001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.module.kra.budget.document;
017:
018: import java.sql.Date;
019: import java.util.ArrayList;
020: import java.util.Iterator;
021: import java.util.LinkedHashMap;
022: import java.util.List;
023:
024: import org.apache.commons.lang.StringUtils;
025: import org.apache.log4j.Logger;
026: import org.kuali.core.bo.user.AuthenticationUserId;
027: import org.kuali.core.bo.user.UniversalUser;
028: import org.kuali.core.exceptions.IllegalObjectStateException;
029: import org.kuali.core.exceptions.UserNotFoundException;
030: import org.kuali.core.service.PersistenceService;
031: import org.kuali.core.service.UniversalUserService;
032: import org.kuali.core.util.ObjectUtils;
033: import org.kuali.core.workflow.DocumentInitiator;
034: import org.kuali.core.workflow.KualiDocumentXmlMaterializer;
035: import org.kuali.core.workflow.KualiTransactionalDocumentInformation;
036: import org.kuali.kfs.KFSPropertyConstants;
037: import org.kuali.kfs.bo.AccountingLineBase;
038: import org.kuali.kfs.context.SpringContext;
039: import org.kuali.kfs.service.ParameterService;
040: import org.kuali.module.chart.service.ChartUserService;
041: import org.kuali.module.kra.KraConstants;
042: import org.kuali.module.kra.bo.AdhocOrg;
043: import org.kuali.module.kra.budget.bo.Budget;
044: import org.kuali.module.kra.budget.bo.BudgetInstitutionCostShare;
045: import org.kuali.module.kra.budget.bo.BudgetNonpersonnel;
046: import org.kuali.module.kra.budget.bo.BudgetPeriod;
047: import org.kuali.module.kra.budget.bo.BudgetTask;
048: import org.kuali.module.kra.budget.bo.BudgetThirdPartyCostShare;
049: import org.kuali.module.kra.budget.bo.BudgetUser;
050: import org.kuali.module.kra.budget.service.BudgetService;
051: import org.kuali.module.kra.document.ResearchDocumentBase;
052:
053: /**
054: * Budget
055: */
056: public class BudgetDocument extends ResearchDocumentBase {
057: private static final Logger LOG = Logger
058: .getLogger(BudgetDocument.class);
059:
060: private static final long serialVersionUID = -3561859858801995441L;
061: private Integer budgetTaskNextSequenceNumber;
062: private Integer budgetPeriodNextSequenceNumber;
063: private Integer personnelNextSequenceNumber;
064: private Integer nonpersonnelNextSequenceNumber;
065: private Integer institutionCostShareNextSequenceNumber;
066: private Integer thirdPartyCostShareNextSequenceNumber;
067: boolean forceRefreshOfBOSubListsForSave = true;
068: boolean cleanseBudgetOnSave = true;
069: private String periodToDelete;
070: private String taskToDelete;
071:
072: private Budget budget;
073:
074: /**
075: * Default no-arg constructor.
076: */
077: public BudgetDocument() {
078: super ();
079: budget = new Budget();
080: budget.setDocumentNumber(this .documentNumber);
081: budgetTaskNextSequenceNumber = new Integer(1);
082: budgetPeriodNextSequenceNumber = new Integer(1);
083: personnelNextSequenceNumber = new Integer(1);
084: nonpersonnelNextSequenceNumber = new Integer(1);
085:
086: institutionCostShareNextSequenceNumber = new Integer(1);
087: thirdPartyCostShareNextSequenceNumber = new Integer(1);
088: }
089:
090: public void initialize() {
091: SpringContext.getBean(BudgetService.class).initializeBudget(
092: this );
093: }
094:
095: // TODO Can't use this just yet - need to ensure that rules are run prior to this being called
096: // /**
097: // * Budget Document specific logic to perform prior to saving.
098: // *
099: // * @see org.kuali.core.document.DocumentBase#prepareForSave()
100: // */
101: // @Override
102: // public void prepareForSave() {
103: // super.prepareForSave();
104: // try {
105: // SpringContext.getBean(BudgetService.class).prepareBudgetForSave(this);
106: // } catch (WorkflowException e) {
107: // throw new RuntimeException("no document found for documentNumber '" + this.documentHeader + "'", e);
108: // }
109: // }
110:
111: /**
112: * @param o
113: */
114: public void setBudgetTaskNextSequenceNumber(Integer o) {
115: budgetTaskNextSequenceNumber = o;
116: }
117:
118: /**
119: * @return budgetTaskNextSequenceNumber
120: */
121: public Integer getBudgetTaskNextSequenceNumber() {
122:
123: return budgetTaskNextSequenceNumber;
124: }
125:
126: /**
127: * @param o
128: */
129: public void setBudgetPeriodNextSequenceNumber(Integer o) {
130: budgetPeriodNextSequenceNumber = o;
131: }
132:
133: /**
134: * @return budgetPeriodNextSequenceNumber
135: */
136: public Integer getBudgetPeriodNextSequenceNumber() {
137: return budgetPeriodNextSequenceNumber;
138: }
139:
140: /**
141: * @param o
142: */
143: public void setPersonnelNextSequenceNumber(Integer o) {
144: personnelNextSequenceNumber = o;
145: }
146:
147: /**
148: * @return budgetPersonnelNextSequenceNumber
149: */
150: public Integer getPersonnelNextSequenceNumber() {
151: return personnelNextSequenceNumber;
152: }
153:
154: /**
155: * @see org.kuali.module.chart.bo.ResearchAdministrationDocumentBase#generatePEsfromAL(org.kuali.bo.AccountingLineBase, boolean,
156: * int)
157: */
158: public void generatePEsfromAL(AccountingLineBase line,
159: boolean isSource, int counter)
160: throws IllegalObjectStateException {
161: // TODO Auto-generated method stub
162:
163: }
164:
165: /**
166: * @see org.kuali.core.bo.BusinessObjectBase#toStringMapper()
167: */
168: protected LinkedHashMap toStringMapper() {
169: LinkedHashMap m = new LinkedHashMap();
170:
171: m
172: .put(KFSPropertyConstants.DOCUMENT_NUMBER,
173: this .documentNumber);
174:
175: return m;
176: }
177:
178: /**
179: * @return Returns the budget.
180: */
181: public Budget getBudget() {
182: return budget;
183: }
184:
185: /**
186: * @param budget The budget to set.
187: */
188: public void setBudget(Budget budget) {
189: this .budget = budget;
190: }
191:
192: public int getPeriodListSize() {
193: return this .budget.getPeriods().size();
194: }
195:
196: public int getTaskListSize() {
197: return this .budget.getTasks().size();
198: }
199:
200: public void addPeriod(BudgetPeriod budgetPeriod) {
201: if (budgetPeriod.getBudgetPeriodBeginDate() == null) {
202: Date defaultNextBeginDate = this .getBudget()
203: .getDefaultNextPeriodBeginDate();
204: if (defaultNextBeginDate != null) {
205: budgetPeriod
206: .setBudgetPeriodBeginDate(defaultNextBeginDate);
207: }
208: }
209:
210: budgetPeriod
211: .setBudgetPeriodSequenceNumber(getBudgetPeriodNextSequenceNumber());
212: budgetPeriod.setDocumentNumber(this .getDocumentNumber());
213: this .budget.getPeriods().add(budgetPeriod);
214:
215: setBudgetPeriodNextSequenceNumber(new Integer(
216: getBudgetPeriodNextSequenceNumber().intValue() + 1));
217: }
218:
219: public void addTask(BudgetTask budgetTask) {
220: budgetTask
221: .setBudgetTaskSequenceNumber(getBudgetTaskNextSequenceNumber());
222: budgetTask.setDocumentNumber(this .getDocumentNumber());
223: if (this .budget.isAgencyModularIndicator()
224: && this .budget.getTasks().size() == 0) {
225: this .budget.getModularBudget().setBudgetModularTaskNumber(
226: budgetTask.getBudgetTaskSequenceNumber());
227: }
228: this .budget.getTasks().add(budgetTask);
229:
230: setBudgetTaskNextSequenceNumber(new Integer(
231: getBudgetTaskNextSequenceNumber().intValue() + 1));
232: }
233:
234: public void addPersonnel(BudgetUser budgetUser) {
235: budgetUser.initializeBudgetUser(this );
236: budgetUser.setCurrentTaskNumber(((BudgetTask) this .getBudget()
237: .getTasks().get(0)).getBudgetTaskSequenceNumber());
238: budget.getPersonnel().add(budgetUser);
239: setPersonnelNextSequenceNumber(new Integer(
240: getPersonnelNextSequenceNumber().intValue() + 1));
241: }
242:
243: public void addNonpersonnel(BudgetNonpersonnel budgetNonpersonnel) {
244: budgetNonpersonnel
245: .setBudgetNonpersonnelSequenceNumber(getNonpersonnelNextSequenceNumber());
246: this .budget.getNonpersonnelItems().add(budgetNonpersonnel);
247: setNonpersonnelNextSequenceNumber(new Integer(
248: getNonpersonnelNextSequenceNumber().intValue() + 1));
249: }
250:
251: public void addInstitutionCostShare(List<BudgetPeriod> periods,
252: BudgetInstitutionCostShare budgetInstitutionCostShare) {
253: budgetInstitutionCostShare
254: .setBudgetCostShareSequenceNumber(this
255: .getInstitutionCostShareNextSequenceNumber());
256: budgetInstitutionCostShare.populateKeyFields(this
257: .getDocumentNumber(), periods);
258:
259: this .budget.getInstitutionCostShareItems().add(
260: budgetInstitutionCostShare);
261:
262: setInstitutionCostShareNextSequenceNumber(new Integer(
263: getInstitutionCostShareNextSequenceNumber().intValue() + 1));
264: }
265:
266: public void addThirdPartyCostShare(List<BudgetPeriod> periods,
267: BudgetThirdPartyCostShare budgetThirdPartyCostShare) {
268: budgetThirdPartyCostShare.setBudgetCostShareSequenceNumber(this
269: .getThirdPartyCostShareNextSequenceNumber());
270: budgetThirdPartyCostShare.populateKeyFields(this
271: .getDocumentNumber(), periods);
272:
273: this .budget.getThirdPartyCostShareItems().add(
274: budgetThirdPartyCostShare);
275:
276: setThirdPartyCostShareNextSequenceNumber(new Integer(
277: getThirdPartyCostShareNextSequenceNumber().intValue() + 1));
278: }
279:
280: /**
281: * Gets the nonpersonnelNextSequenceNumber attribute.
282: *
283: * @return Returns the nonpersonnelNextSequenceNumber.
284: */
285: public Integer getNonpersonnelNextSequenceNumber() {
286: return nonpersonnelNextSequenceNumber;
287: }
288:
289: /**
290: * Sets the nonpersonnelNextSequenceNumber attribute value.
291: *
292: * @param nonpersonnelNextSequenceNumber The nonpersonnelNextSequenceNumber to set.
293: */
294: public void setNonpersonnelNextSequenceNumber(
295: Integer nonpersonnelNextSequenceNumber) {
296: this .nonpersonnelNextSequenceNumber = nonpersonnelNextSequenceNumber;
297: }
298:
299: /**
300: * Gets the forceRefreshOfBOSubListsForSave attribute.
301: *
302: * @return Returns the forceRefreshOfBOSubListsForSave.
303: */
304: public boolean isForceRefreshOfBOSubListsForSave() {
305: return forceRefreshOfBOSubListsForSave;
306: }
307:
308: /**
309: * Sets the forceRefreshOfBOSubListsForSave attribute value.
310: *
311: * @param forceRefreshOfBOSubListsForSave The forceRefreshOfBOSubListsForSave to set.
312: */
313: public void setForceRefreshOfBOSubListsForSave(
314: boolean forceRefreshOfBOSubListsForSave) {
315: this .forceRefreshOfBOSubListsForSave = forceRefreshOfBOSubListsForSave;
316: }
317:
318: /**
319: * @return Returns the budgetInstitutionCostShareNextSequenceNumber.
320: */
321: public Integer getInstitutionCostShareNextSequenceNumber() {
322: return institutionCostShareNextSequenceNumber;
323: }
324:
325: /**
326: * @param budgetInstitutionCostShareNextSequenceNumber The budgetInstitutionCostShareNextSequenceNumber to set.
327: */
328: public void setInstitutionCostShareNextSequenceNumber(
329: Integer budgetInstitutionCostShareNextSequenceNumber) {
330: this .institutionCostShareNextSequenceNumber = budgetInstitutionCostShareNextSequenceNumber;
331: }
332:
333: public boolean isCleanseBudgetOnSave() {
334: return cleanseBudgetOnSave;
335: }
336:
337: public void setCleanseBudgetOnSave(boolean cleanseBudgetOnSave) {
338: this .cleanseBudgetOnSave = cleanseBudgetOnSave;
339: }
340:
341: /**
342: * @return Returns the budgetThirdPartyCostShareNextSequenceNumber.
343: */
344: public Integer getThirdPartyCostShareNextSequenceNumber() {
345: return thirdPartyCostShareNextSequenceNumber;
346: }
347:
348: /**
349: * @param budgetThirdPartyCostShareNextSequenceNumber The budgetThirdPartyCostShareNextSequenceNumber to set.
350: */
351: public void setThirdPartyCostShareNextSequenceNumber(
352: Integer budgetThirdPartyCostShareNextSequenceNumber) {
353: this .thirdPartyCostShareNextSequenceNumber = budgetThirdPartyCostShareNextSequenceNumber;
354: }
355:
356: public String getPeriodToDelete() {
357: return periodToDelete;
358: }
359:
360: public void setPeriodToDelete(String periodToDelete) {
361: this .periodToDelete = periodToDelete;
362: }
363:
364: public String getTaskToDelete() {
365: return taskToDelete;
366: }
367:
368: public void setTaskToDelete(String taskToDelete) {
369: this .taskToDelete = taskToDelete;
370: }
371:
372: @Override
373: public List buildListOfDeletionAwareLists() {
374: List list = new ArrayList();
375:
376: list.add(this .getAdhocPersons());
377: list.add(this .getAdhocOrgs());
378: list.add(this .getAdhocWorkgroups());
379:
380: Budget budget = this .getBudget();
381: list.add(budget.getNonpersonnelItems());
382: list.add(budget.getAllUserAppointmentTaskPeriods(this
383: .isForceRefreshOfBOSubListsForSave()));
384: list.add(budget.getAllUserAppointmentTasks(this
385: .isForceRefreshOfBOSubListsForSave()));
386: list.add(budget.getPersonnel());
387:
388: list.add(budget.getAllThirdPartyCostSharePeriods(this
389: .isForceRefreshOfBOSubListsForSave()));
390: list.add(budget.getThirdPartyCostShareItems());
391:
392: list.add(budget.getAllInstitutionCostSharePeriods(this
393: .isForceRefreshOfBOSubListsForSave()));
394: list.add(budget.getInstitutionCostShareItems());
395:
396: list.add(budget.getInstitutionCostSharePersonnelItems());
397:
398: if (budget.getIndirectCost() != null
399: && budget.getIndirectCost()
400: .getBudgetTaskPeriodIndirectCostItems() != null) {
401: list.add(budget.getIndirectCost()
402: .getBudgetTaskPeriodIndirectCostItems());
403: } else {
404: list.add(new ArrayList());
405: }
406:
407: if (budget.getModularBudget() != null) {
408: list.add(budget.getModularBudget()
409: .getBudgetModularPeriods());
410: } else {
411: list.add(new ArrayList());
412: }
413:
414: // Lots of FKs from previous collections point to these two, so they need to handled last
415: list.add(budget.getTasks());
416: list.add(budget.getPeriods());
417:
418: return list;
419: }
420:
421: @Override
422: public void populateDocumentForRouting() {
423: KualiTransactionalDocumentInformation transInfo = new KualiTransactionalDocumentInformation();
424: DocumentInitiator initiator = new DocumentInitiator();
425: String initiatorNetworkId = documentHeader
426: .getWorkflowDocument().getInitiatorNetworkId();
427: try {
428: UniversalUser initiatorUser = SpringContext.getBean(
429: UniversalUserService.class).getUniversalUser(
430: new AuthenticationUserId(initiatorNetworkId));
431: initiator.setUniversalUser(initiatorUser);
432: } catch (UserNotFoundException e) {
433: throw new RuntimeException(e);
434: }
435: transInfo.setDocumentInitiator(initiator);
436: KualiDocumentXmlMaterializer xmlWrapper = new KualiDocumentXmlMaterializer();
437: xmlWrapper.setDocument(this );
438: xmlWrapper.setKualiTransactionalDocumentInformation(transInfo);
439: documentHeader.getWorkflowDocument().setApplicationContent(
440: generateDocumentContent());
441: }
442:
443: public String generateDocumentContent() {
444: List referenceObjects = new ArrayList();
445: referenceObjects.add("personnel");
446: referenceObjects.add("institutionCostShareItems");
447: SpringContext.getBean(PersistenceService.class)
448: .retrieveReferenceObjects(budget, referenceObjects);
449: this .refreshReferenceObject("adhocOrgs");
450:
451: StringBuffer xml = new StringBuffer("<documentContent>");
452: xml.append(buildProjectDirectorReportXml(false));
453: xml.append(buildCostShareOrgReportXml(false));
454: xml.append(buildAdhocOrgReportXml(false));
455: xml.append("</documentContent>");
456:
457: return xml.toString();
458: }
459:
460: /**
461: * Build the xml to use when generating the workflow routing report.
462: *
463: * @param BudgetUser projectDirector
464: * @param boolean encloseContent - whether the generated xml should be enclosed within a <documentContent> tag
465: * @return String
466: */
467: public String buildProjectDirectorReportXml(boolean encloseContent) {
468: StringBuffer xml = new StringBuffer();
469: if (encloseContent) {
470: xml.append("<documentContent>");
471: }
472: BudgetUser projectDirector = null;
473:
474: for (Iterator iter = this .getBudget().getPersonnel().iterator(); iter
475: .hasNext();) {
476: BudgetUser person = (BudgetUser) iter.next();
477: if (person.isPersonProjectDirectorIndicator()) {
478: projectDirector = person;
479: break;
480: }
481: }
482:
483: if (ObjectUtils.isNotNull(projectDirector)
484: && ObjectUtils.isNotNull(projectDirector.getUser())) {
485: if (!this .getBudget().isProjectDirectorToBeNamedIndicator()) {
486: xml.append("<projectDirector>");
487: xml.append(projectDirector.getUser()
488: .getPersonUniversalIdentifier());
489: xml.append("</projectDirector>");
490: }
491: if (!StringUtils.isBlank(projectDirector
492: .getFiscalCampusCode())) {
493: xml.append("<chartOrg><chartOfAccountsCode>");
494: xml.append(projectDirector.getFiscalCampusCode());
495: xml.append("</chartOfAccountsCode><organizationCode>");
496: if (StringUtils.isBlank(projectDirector
497: .getPrimaryDepartmentCode())) {
498: xml.append(SpringContext.getBean(
499: ChartUserService.class)
500: .getDefaultOrganizationCode(
501: projectDirector.getUser()));
502: } else {
503: xml.append(projectDirector
504: .getPrimaryDepartmentCode());
505: }
506: xml.append("</organizationCode></chartOrg>");
507: }
508: }
509: if (encloseContent) {
510: xml.append("</documentContent>");
511: }
512: return xml.toString();
513: }
514:
515: /**
516: * Build the xml to use when generating the workflow org routing report.
517: *
518: * @param List<BudgetAdhocOrg> orgs
519: * @param boolean encloseContent - whether the generated xml should be enclosed within a <documentContent> tag
520: * @return String
521: */
522: public String buildCostShareOrgReportXml(boolean encloseContent) {
523:
524: String costSharePermissionCode = SpringContext.getBean(
525: ParameterService.class).getParameterValue(
526: BudgetDocument.class,
527: KraConstants.BUDGET_COST_SHARE_PERMISSION_CODE);
528:
529: StringBuffer xml = new StringBuffer();
530: if (encloseContent) {
531: xml.append("<documentContent>");
532: }
533:
534: List costShareItems = this .getBudget()
535: .getInstitutionCostShareItems();
536: for (Iterator iter = costShareItems.iterator(); iter.hasNext();) {
537: BudgetInstitutionCostShare costShare = (BudgetInstitutionCostShare) iter
538: .next();
539: if (costShare.isPermissionIndicator()
540: || costSharePermissionCode
541: .equals(KraConstants.COST_SHARE_PERMISSION_CODE_TRUE)) {
542: xml.append("<chartOrg><chartOfAccountsCode>");
543: if (costShare.getChartOfAccountsCode() != null) {
544: xml.append(costShare.getChartOfAccountsCode());
545: }
546: xml.append("</chartOfAccountsCode><organizationCode>");
547: if (costShare.getOrganizationCode() != null) {
548: xml.append(costShare.getOrganizationCode());
549: }
550: xml.append("</organizationCode></chartOrg>");
551: }
552: }
553: if (encloseContent) {
554: xml.append("</documentContent>");
555: }
556:
557: return xml.toString();
558: }
559:
560: /**
561: * Build the xml to use when generating the workflow org routing report.
562: *
563: * @param List<BudgetAdhocOrg> orgs
564: * @param boolean encloseContent - whether the generated xml should be enclosed within a <documentContent> tag
565: * @return String
566: */
567: public String buildAdhocOrgReportXml(boolean encloseContent) {
568: StringBuffer xml = new StringBuffer();
569: if (encloseContent) {
570: xml.append("<documentContent>");
571: }
572: List<AdhocOrg> orgs = this .getAdhocOrgs();
573: for (AdhocOrg org : orgs) {
574: xml.append("<chartOrg><chartOfAccountsCode>");
575: xml.append(org.getFiscalCampusCode());
576: xml.append("</chartOfAccountsCode><organizationCode>");
577: xml.append(org.getPrimaryDepartmentCode());
578: xml.append("</organizationCode></chartOrg>");
579: }
580: if (encloseContent) {
581: xml.append("</documentContent>");
582: }
583: return xml.toString();
584: }
585: }
|