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.service.impl;
017:
018: import java.util.ArrayList;
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Map;
023:
024: import org.kuali.core.document.Document;
025: import org.kuali.core.service.BusinessObjectService;
026: import org.kuali.core.service.DateTimeService;
027: import org.kuali.core.service.DocumentService;
028: import org.kuali.core.util.KualiDecimal;
029: import org.kuali.core.util.KualiInteger;
030: import org.kuali.core.util.ObjectUtils;
031: import org.kuali.kfs.KFSPropertyConstants;
032: import org.kuali.kfs.context.SpringContext;
033: import org.kuali.module.kra.KraConstants;
034: import org.kuali.module.kra.budget.bo.Budget;
035: import org.kuali.module.kra.budget.bo.BudgetFringeRate;
036: import org.kuali.module.kra.budget.bo.BudgetGraduateAssistantRate;
037: import org.kuali.module.kra.budget.bo.BudgetModular;
038: import org.kuali.module.kra.budget.bo.BudgetModularPeriod;
039: import org.kuali.module.kra.budget.bo.BudgetNonpersonnel;
040: import org.kuali.module.kra.budget.bo.BudgetPeriod;
041: import org.kuali.module.kra.budget.bo.BudgetTask;
042: import org.kuali.module.kra.budget.bo.BudgetUser;
043: import org.kuali.module.kra.budget.bo.UserAppointmentTask;
044: import org.kuali.module.kra.budget.bo.UserAppointmentTaskPeriod;
045: import org.kuali.module.kra.budget.document.BudgetDocument;
046: import org.kuali.module.kra.budget.service.BudgetCostShareService;
047: import org.kuali.module.kra.budget.service.BudgetFringeRateService;
048: import org.kuali.module.kra.budget.service.BudgetGraduateAssistantRateService;
049: import org.kuali.module.kra.budget.service.BudgetIndirectCostService;
050: import org.kuali.module.kra.budget.service.BudgetModularService;
051: import org.kuali.module.kra.budget.service.BudgetPeriodService;
052: import org.kuali.module.kra.budget.service.BudgetPersonnelService;
053: import org.kuali.module.kra.budget.service.BudgetService;
054: import org.kuali.module.kra.budget.web.struts.form.BudgetNonpersonnelCopyOverBoHelper;
055: import org.springframework.transaction.annotation.Transactional;
056:
057: import edu.iu.uis.eden.exception.WorkflowException;
058:
059: @Transactional
060: public class BudgetServiceImpl implements BudgetService {
061:
062: private BudgetFringeRateService budgetFringeRateService;
063: private BudgetGraduateAssistantRateService budgetGraduateAssistantRateService;
064: private BudgetPersonnelService budgetPersonnelService;
065: private BudgetCostShareService budgetCostShareService;
066: private DocumentService documentService;
067: private BudgetModularService budgetModularService;
068: private BudgetIndirectCostService budgetIndirectCostService;
069: private BusinessObjectService businessObjectService;
070: private DateTimeService dateTimeService;
071:
072: /**
073: * @see org.kuali.module.kra.budget.service.BudgetService#initializeBudget(org.kuali.module.kra.budget.bo.Budget)
074: */
075: public void initializeBudget(BudgetDocument budgetDocument) {
076: Budget budget = budgetDocument.getBudget();
077: budget.setDocumentNumber(budgetDocument.getDocumentNumber());
078: budgetFringeRateService.setupDefaultFringeRates(budget);
079: budgetGraduateAssistantRateService
080: .setupDefaultGradAssistantRates(budget);
081: budgetIndirectCostService.setupIndirectCostRates(budget);
082: }
083:
084: /**
085: * @see org.kuali.module.kra.budget.service.BudgetService#prepareBudgetForSave(org.kuali.module.kra.budget.document.BudgetDocument)
086: */
087: public void prepareBudgetForSave(BudgetDocument budgetDocument)
088: throws WorkflowException {
089: // Materialize tasks/periods if necessary (i.e., they are proxy objects currently)
090: ObjectUtils.materializeObjects(budgetDocument.getBudget()
091: .getTasks());
092: ObjectUtils.materializeObjects(budgetDocument.getBudget()
093: .getPeriods());
094:
095: Document databaseDocument = documentService
096: .getByDocumentHeaderId(budgetDocument
097: .getDocumentNumber());
098:
099: Budget budget = budgetDocument.getBudget();
100: String documentNumber = budget.getDocumentNumber();
101: List personnel = budget.getPersonnel();
102: List institutionCostSharePersonnelItems = budget
103: .getInstitutionCostSharePersonnelItems();
104:
105: if (budgetDocument.isCleanseBudgetOnSave()) {
106: if (databaseDocument != null) {
107: BudgetDocument databaseBudgetDocument = (BudgetDocument) databaseDocument;
108:
109: // First get rid of items that need to be deleted - cleansing should get rid items that are no longer valid because
110: // the
111: // associated task/period are no longer in the list.
112: cleanseNonpersonnel(budgetDocument);
113: budgetPersonnelService.cleansePersonnel(budgetDocument);
114: budgetCostShareService.cleanseCostShare(budget
115: .isInstitutionCostShareIndicator(), budget
116: .getInstitutionCostShareItems(), budget
117: .isBudgetThirdPartyCostShareIndicator(), budget
118: .getThirdPartyCostShareItems(), personnel,
119: budget.getInstitutionCostSharePersonnelItems());
120: cleanseModular(budgetDocument);
121:
122: // Find what's changed that has a down-stream effect on other parts of the Budget, if anything, since the last save
123: List modifiedPeriods = findModifiedPeriods(
124: budgetDocument, databaseBudgetDocument);
125: List<BudgetFringeRate> modifiedFringeRates = findModifiedFringeRates(
126: budgetDocument, databaseBudgetDocument);
127: List<BudgetGraduateAssistantRate> modifiedGraduateAssistantRates = findModifiedGraduateAssistantRates(
128: budgetDocument, databaseBudgetDocument);
129: // List modifiedPersonnel = findModifiedPersonnel(budgetDocument, databaseBudgetDocument);
130:
131: boolean isPersonnelInflationRateModified = isPersonnelInflationRateModified(
132: budgetDocument, databaseBudgetDocument);
133:
134: boolean isNonpersonnelInflationRateModified = isNonpersonnelInflationRateModified(
135: budgetDocument, databaseBudgetDocument);
136:
137: boolean isInstitutionCostShareInclusionModified = isInstitutionCostShareInclusionModified(
138: budgetDocument, databaseBudgetDocument);
139:
140: // Update effected Personnel/Nonpersonnel entries based on what's changed above
141: if (modifiedPeriods.size() > 0
142: || modifiedFringeRates.size() > 0
143: || isPersonnelInflationRateModified) {
144: updatePersonnelDetail(budgetDocument,
145: modifiedPeriods, modifiedFringeRates,
146: isPersonnelInflationRateModified,
147: isInstitutionCostShareInclusionModified);
148: }
149:
150: if (isInstitutionCostShareInclusionModified
151: && !isInstitutionCostShareIncludeBoxChecked(budgetDocument)) {
152: updatePersonnelCostShare(budgetDocument);
153: }
154:
155: if (isNonpersonnelInflationRateModified
156: || modifiedPeriods.size() > 0
157: || !(isInstitutionCostShareIncludeBoxChecked(budgetDocument))
158: || !(isThirdPartyCostShareIncludeBoxChecked(budgetDocument))) {
159: updateNonpersonnelDetail(budgetDocument,
160: isNonpersonnelInflationRateModified,
161: modifiedPeriods);
162: }
163:
164: // Do these after personnel/nonpersonnel update
165: List modifiedUserAppointmentTaskPeriods = findModifiedUserAppointmentTaskPeriods(
166: budgetDocument, databaseBudgetDocument);
167: List modifiedNonpersonnel = findModifiedNonpersonnel(
168: budgetDocument, databaseBudgetDocument);
169:
170: if (budget.isAgencyModularIndicator()
171: && ((modifiedPeriods.size() > 0 || modifiedUserAppointmentTaskPeriods
172: .size() > 0) || modifiedNonpersonnel
173: .size() > 0)) {
174: updateModular(budgetDocument);
175: }
176:
177: budget.setFringeRates(databaseBudgetDocument
178: .getBudget().getFringeRates());
179: // Update timestamp of modified Fringe Rates
180: for (BudgetFringeRate modifiedBudgetFringeRate : modifiedFringeRates) {
181: ObjectUtils
182: .removeObjectWithIdentitcalKey(budget
183: .getFringeRates(),
184: modifiedBudgetFringeRate);
185: modifiedBudgetFringeRate
186: .setBudgetLastUpdateTimestamp(dateTimeService
187: .getCurrentTimestamp());
188: }
189:
190: // Replace all of the fringe rates with what's in the database. remove all of the modified ones (the .equals()
191: // method does not check timestamp) and re-add them.
192: budget.getFringeRates().addAll(modifiedFringeRates);
193:
194: budget.setGraduateAssistantRates(databaseBudgetDocument
195: .getBudget().getGraduateAssistantRates());
196: // Update timestamp of modified Fringe Rates
197: for (BudgetGraduateAssistantRate modifiedBudgetGraduateRate : modifiedGraduateAssistantRates) {
198: ObjectUtils.removeObjectWithIdentitcalKey(budget
199: .getGraduateAssistantRates(),
200: modifiedBudgetGraduateRate);
201: modifiedBudgetGraduateRate
202: .setLastUpdateTimestamp(dateTimeService
203: .getCurrentTimestamp());
204: }
205:
206: // Replace all of the fringe rates with what's in the database. remove all of the modified ones (the .equals()
207: // method does not check timestamp) and re-add them.
208: budget.getGraduateAssistantRates().addAll(
209: modifiedGraduateAssistantRates);
210:
211: } else {
212: for (BudgetFringeRate budgetFringeRate : budgetDocument
213: .getBudget().getFringeRates()) {
214: budgetFringeRate
215: .setBudgetLastUpdateTimestamp(dateTimeService
216: .getCurrentTimestamp());
217: }
218:
219: for (BudgetGraduateAssistantRate budgetGradAsstRate : budgetDocument
220: .getBudget().getGraduateAssistantRates()) {
221: budgetGradAsstRate
222: .setLastUpdateTimestamp(dateTimeService
223: .getCurrentTimestamp());
224: }
225: }
226:
227: // Add new data, based on changes that may have occurred prior to the save (e.g., Project Director from Parameters)
228: budgetPersonnelService
229: .reconcileProjectDirector(budgetDocument);
230:
231: // Add new Cost Share data based on personnel
232: budgetCostShareService.reconcileCostShare(documentNumber,
233: personnel, institutionCostSharePersonnelItems);
234:
235: // Clean up indirect cost and task/period items.
236: budgetIndirectCostService
237: .reconcileIndirectCost(budgetDocument);
238: }
239: }
240:
241: /**
242: * @see org.kuali.module.kra.budget.service.BudgetService#isCostShareInclusionModified(org.kuali.module.kra.budget.document.BudgetDocument)
243: */
244: public String buildCostShareRemovedCode(
245: BudgetDocument budgetDocument) {
246:
247: BudgetDocument databaseBudgetDocument;
248: try {
249: databaseBudgetDocument = (BudgetDocument) documentService
250: .getByDocumentHeaderId(budgetDocument
251: .getDocumentNumber());
252: } catch (WorkflowException e) {
253: throw new RuntimeException(
254: "Exception retrieving document: " + e);
255: }
256: if (databaseBudgetDocument == null) {
257: return "";
258: }
259:
260: StringBuffer codes = new StringBuffer();
261: if (databaseBudgetDocument.getBudget()
262: .isInstitutionCostShareIndicator()
263: && !budgetDocument.getBudget()
264: .isInstitutionCostShareIndicator()) {
265: codes.append(KraConstants.INSTITUTION_COST_SHARE_CODE);
266: }
267: if (databaseBudgetDocument.getBudget()
268: .isBudgetThirdPartyCostShareIndicator()
269: && !budgetDocument.getBudget()
270: .isBudgetThirdPartyCostShareIndicator()) {
271: codes.append(KraConstants.THIRD_PARTY_COST_SHARE_CODE);
272: }
273: return codes.toString();
274: }
275:
276: /**
277: * This method will determine if Third Party Cost Share has changed
278: *
279: * @param budgetDocument
280: * @param databaseBudgetDocument
281: * @return boolean
282: */
283: private boolean isThirdPartyCostShareInclusionModified(
284: BudgetDocument budgetDocument,
285: BudgetDocument databaseBudgetDocument) {
286: return !(budgetDocument.getBudget()
287: .isBudgetThirdPartyCostShareIndicator() == databaseBudgetDocument
288: .getBudget().isBudgetThirdPartyCostShareIndicator());
289: }
290:
291: /**
292: * This method will determine if Institution Cost Share has changed
293: *
294: * @param budgetDocument
295: * @return
296: */
297: private boolean isInstitutionCostShareInclusionModified(
298: BudgetDocument budgetDocument,
299: BudgetDocument databaseBudgetDocument) {
300: return !(budgetDocument.getBudget()
301: .isInstitutionCostShareIndicator() == databaseBudgetDocument
302: .getBudget().isInstitutionCostShareIndicator());
303: }
304:
305: /**
306: * This method will determine if the institution cost share include box is checked.
307: *
308: * @param budgetDocument
309: * @return
310: */
311: private boolean isInstitutionCostShareIncludeBoxChecked(
312: BudgetDocument budgetDocument) {
313: return budgetDocument.getBudget()
314: .isInstitutionCostShareIndicator();
315: }
316:
317: /**
318: * This method will determine if the 3rd party cost share include check box is checked.
319: *
320: * @param budgetDocument
321: * @return
322: */
323: private boolean isThirdPartyCostShareIncludeBoxChecked(
324: BudgetDocument budgetDocument) {
325: return budgetDocument.getBudget()
326: .isBudgetThirdPartyCostShareIndicator();
327: }
328:
329: /**
330: * This method will recalculate Nonpersonnel entries based on whether the nonpersonnel inflation rate has been modified, whether
331: * institution cost share inclusion has changed, or whether third party cost share inclusion has been changed. In practice, this
332: * will only apply to nonpersonnel entries that have been "copied forward" from previous periods.
333: *
334: * @param budgetDocument
335: * @param isNonpersonnelInflationRateModified identifies if the inflation rate changed
336: * @param modifiedPeriods list of modified periods
337: */
338: private void updateNonpersonnelDetail(
339: BudgetDocument budgetDocument,
340: boolean isNonpersonnelInflationRateModified,
341: List modifiedPeriods) {
342: boolean isInstitutionCostShareCheckBoxChecked = isInstitutionCostShareIncludeBoxChecked(budgetDocument);
343: boolean isThirdPartyCostShareCheckBoxChecked = isThirdPartyCostShareIncludeBoxChecked(budgetDocument);
344:
345: List nonpersonnelItemsList = new ArrayList(budgetDocument
346: .getBudget().getNonpersonnelItems()); // necessary to make copy
347: // because period fill up
348: // below adds to the list,
349: // want to avoid concurrent
350: // modification exception
351: List periods = budgetDocument.getBudget().getPeriods();
352: KualiDecimal budgetNonpersonnelInflationRate = budgetDocument
353: .getBudget().getBudgetNonpersonnelInflationRate();
354:
355: for (Iterator nonpersonnelItem = nonpersonnelItemsList
356: .iterator(); nonpersonnelItem.hasNext();) {
357: BudgetNonpersonnel budgetNonpersonnel = (BudgetNonpersonnel) nonpersonnelItem
358: .next();
359:
360: // if Institution Cost Share check box or Third Party Cost share check boxes are un-checked,
361: // set the corresponding amounts to zero.
362: if (!(isInstitutionCostShareCheckBoxChecked)) {
363: budgetNonpersonnel
364: .setBudgetInstitutionCostShareAmount(new KualiInteger(
365: 0));
366: }
367: if (!(isThirdPartyCostShareCheckBoxChecked)) {
368: budgetNonpersonnel
369: .setBudgetThirdPartyCostShareAmount(new KualiInteger(
370: 0));
371: }
372:
373: // if periods were added and this is an origin item that has been copied over, we need to fill in a new item for each
374: // new period
375: if (modifiedPeriods.size() > 0
376: && budgetNonpersonnel.isOriginItem()
377: && budgetNonpersonnel.isCopiedOverItem()) {
378: // Iterate over each added period since each one needs new NPRS copy over items
379: for (Iterator periodsIter = modifiedPeriods.iterator(); periodsIter
380: .hasNext();) {
381: BudgetPeriod period = (BudgetPeriod) periodsIter
382: .next();
383: // check if this is a new (added) period or truly modified
384: if (period.getVersionNumber() == null) {
385: int inflationLength = SpringContext
386: .getBean(BudgetPeriodService.class)
387: .getPeriodIndex(
388: period
389: .getBudgetPeriodSequenceNumber(),
390: periods);
391:
392: // Create new item
393: BudgetNonpersonnelCopyOverBoHelper budgetNonpersonnelCopyOverBoHelper = new BudgetNonpersonnelCopyOverBoHelper(
394: budgetNonpersonnel,
395: period.getBudgetPeriodSequenceNumber(),
396: inflationLength,
397: budgetNonpersonnelInflationRate);
398:
399: // indicators should always be false for these "new period" items
400: budgetNonpersonnelCopyOverBoHelper
401: .setAgencyCopyIndicator(false);
402: budgetNonpersonnelCopyOverBoHelper
403: .setBudgetInstitutionCostShareCopyIndicator(false);
404: budgetNonpersonnelCopyOverBoHelper
405: .setBudgetThirdPartyCostShareCopyIndicator(false);
406:
407: // add it to the Budget Document per the standard methods provided.
408: BudgetNonpersonnel newNonpersonnel = budgetNonpersonnelCopyOverBoHelper
409: .getBudgetNonpersonnel();
410: newNonpersonnel
411: .setBudgetNonpersonnelSequenceNumber(budgetDocument
412: .getNonpersonnelNextSequenceNumber());
413: budgetDocument.addNonpersonnel(newNonpersonnel);
414: }
415: }
416: }
417:
418: // if inflation rate changed, if it did we have to update copy over items only
419: if (isNonpersonnelInflationRateModified
420: && !budgetNonpersonnel.isOriginItem()
421: && budgetNonpersonnel.isCopiedOverItem()) {
422: // Figure the inflationLength (current item period seq#) and call the constructor which will calculate inflation
423: // values for us
424: int inflationLength = SpringContext.getBean(
425: BudgetPeriodService.class).getPeriodIndex(
426: budgetNonpersonnel
427: .getBudgetPeriodSequenceNumber(),
428: periods);
429: BudgetNonpersonnelCopyOverBoHelper budgetNonpersonnelCopyOverBoHelper = new BudgetNonpersonnelCopyOverBoHelper(
430: budgetNonpersonnel, inflationLength,
431: budgetNonpersonnelInflationRate);
432:
433: // update appropriate amounts per indicators set
434: if (budgetNonpersonnel.getAgencyCopyIndicator()) {
435: budgetNonpersonnel
436: .setAgencyRequestAmount(budgetNonpersonnelCopyOverBoHelper
437: .getBudgetInflatedAgencyAmount());
438: }
439: if (budgetNonpersonnel
440: .getBudgetInstitutionCostShareCopyIndicator()) {
441: budgetNonpersonnel
442: .setBudgetInstitutionCostShareAmount(budgetNonpersonnelCopyOverBoHelper
443: .getBudgetInflatedInstitutionCostShareAmount());
444: }
445: if (budgetNonpersonnel
446: .getBudgetThirdPartyCostShareCopyIndicator()) {
447: budgetNonpersonnel
448: .setBudgetThirdPartyCostShareAmount(budgetNonpersonnelCopyOverBoHelper
449: .getBudgetInflatedThirdPartyCostShareAmount());
450: }
451: }
452: }
453: }
454:
455: /**
456: * This method will recalculate Personnel entries based on changes to the length of periods, changes to fringe rates, or a
457: * change to the personnel inflation rate, or a change to cost share inclusion
458: *
459: * @param budgetDocument
460: * @param modifiedPeriods
461: * @param modifiedFringeRates
462: * @param isPersonnelInflationRateModified
463: */
464: private void updatePersonnelDetail(BudgetDocument budgetDocument,
465: List modifiedPeriods, List modifiedFringeRates,
466: boolean isPersonnelInflationRateModified,
467: boolean isInstitutionCostShareInclusionModified) {
468: budgetPersonnelService
469: .reconcileAndCalculatePersonnel(budgetDocument);
470: }
471:
472: private void updatePersonnelCostShare(BudgetDocument budgetDocument) {
473: // if Institution Cost Share check box check box is un-checked, set the corresponding amounts to zero.
474: for (BudgetUser budgetUser : budgetDocument.getBudget()
475: .getPersonnel()) {
476: for (UserAppointmentTask userAppointmentTask : budgetUser
477: .getUserAppointmentTasks()) {
478: for (UserAppointmentTaskPeriod userAppointmentTaskPeriod : userAppointmentTask
479: .getUserAppointmentTaskPeriods()) {
480: userAppointmentTaskPeriod
481: .setInstitutionCostSharePercentEffortAmount(new KualiInteger(
482: 0));
483: userAppointmentTaskPeriod
484: .setUserInstitutionHours(new KualiInteger(0));
485: userAppointmentTaskPeriod
486: .setInstitutionFullTimeEquivalentPercent(new KualiInteger(
487: 0));
488: userAppointmentTaskPeriod
489: .setInstitutionHealthInsuranceAmount(new KualiInteger(
490: 0));
491: userAppointmentTaskPeriod
492: .setInstitutionRequestedFeesAmount(new KualiInteger(
493: 0));
494: userAppointmentTaskPeriod
495: .setInstitutionSalaryAmount(new KualiInteger(
496: 0));
497: userAppointmentTaskPeriod
498: .setInstitutionCostShareFringeBenefitTotalAmount(new KualiInteger(
499: 0));
500: userAppointmentTaskPeriod
501: .setInstitutionCostShareRequestTotalAmount(new KualiInteger(
502: 0));
503: }
504: }
505: }
506: }
507:
508: /**
509: * This method will recalculate Modular entries based on changes to the length of periods, changes to personnel or nonpersonnel
510: * items
511: *
512: * @param budgetDocument
513: * @param modifiedPeriods
514: * @param modifiedFringeRates
515: * @param isPersonnelInflationRateModified
516: */
517: private void updateModular(BudgetDocument budgetDocument) {
518: budgetModularService.resetModularBudget(budgetDocument
519: .getBudget());
520: }
521:
522: /**
523: * This method will determine if the Nonpersonnel Inflation rate has changed.
524: *
525: * @param budgetDocument
526: * @return whether or not nonpersonnel inflation rate changed
527: */
528: private boolean isNonpersonnelInflationRateModified(
529: BudgetDocument budgetDocument,
530: BudgetDocument databaseBudgetDocument) {
531: return !budgetDocument.getBudget()
532: .getBudgetNonpersonnelInflationRate().equals(
533: databaseBudgetDocument.getBudget()
534: .getBudgetNonpersonnelInflationRate());
535: }
536:
537: /**
538: * This method...
539: *
540: * @param budgetDocument
541: * @return
542: */
543: private boolean isPersonnelInflationRateModified(
544: BudgetDocument budgetDocument,
545: BudgetDocument databaseBudgetDocument) {
546: return !budgetDocument.getBudget()
547: .getBudgetPersonnelInflationRate().equals(
548: databaseBudgetDocument.getBudget()
549: .getBudgetPersonnelInflationRate());
550: }
551:
552: /**
553: * This method will remove Nonpersonnel entries that are no longer valid as a result of the task or period that they reference
554: * are no longer present.
555: *
556: * @param budgetDocument
557: */
558: private void cleanseNonpersonnel(BudgetDocument budgetDocument) {
559: List budgetNonpersonnelItems = budgetDocument.getBudget()
560: .getNonpersonnelItems();
561: List budgetTasks = budgetDocument.getBudget().getTasks();
562: List budgetPeriods = budgetDocument.getBudget().getPeriods();
563:
564: for (Iterator i = budgetNonpersonnelItems.iterator(); i
565: .hasNext();) {
566: BudgetNonpersonnel budgetNonpersonnel = (BudgetNonpersonnel) i
567: .next();
568:
569: BudgetTask budgetTask = (BudgetTask) businessObjectService
570: .retrieve(new BudgetTask(budgetNonpersonnel
571: .getDocumentNumber(), budgetNonpersonnel
572: .getBudgetTaskSequenceNumber()));
573:
574: BudgetPeriod budgetPeriod = (BudgetPeriod) businessObjectService
575: .retrieve(new BudgetPeriod(budgetNonpersonnel
576: .getDocumentNumber(), budgetNonpersonnel
577: .getBudgetPeriodSequenceNumber()));
578:
579: if (!ObjectUtils.collectionContainsObjectWithIdentitcalKey(
580: budgetTasks, budgetTask)
581: || !ObjectUtils
582: .collectionContainsObjectWithIdentitcalKey(
583: budgetPeriods, budgetPeriod)) {
584: i.remove();
585: }
586: }
587: }
588:
589: /**
590: * This method will remove Modular period entries that are no longer valid as a result of the task or period that they reference
591: * are no longer present.
592: *
593: * @param budgetDocument
594: */
595: private void cleanseModular(BudgetDocument budgetDocument) {
596: Budget budget = budgetDocument.getBudget();
597: if (!budget.isAgencyModularIndicator()) {
598: // Not a modular budget - wipe out existing modular budget, if any
599: Long versionNumber = null;
600: if (ObjectUtils.isNotNull(budget.getModularBudget())) {
601: versionNumber = budget.getModularBudget()
602: .getVersionNumber();
603: }
604: budget.setModularBudget(new BudgetModular(budget
605: .getDocumentNumber()));
606: if (versionNumber != null) {
607: budget.getModularBudget().setVersionNumber(
608: versionNumber);
609: }
610: } else if (budgetDocument.getBudget().getModularBudget() != null) {
611: List modularPeriods = budget.getModularBudget()
612: .getBudgetModularPeriods();
613: List budgetPeriods = budget.getPeriods();
614:
615: for (Iterator i = modularPeriods.iterator(); i.hasNext();) {
616: BudgetModularPeriod currentModularPeriod = (BudgetModularPeriod) i
617: .next();
618:
619: BudgetPeriod budgetPeriod = (BudgetPeriod) businessObjectService
620: .retrieve(new BudgetPeriod(
621: currentModularPeriod
622: .getDocumentNumber(),
623: currentModularPeriod
624: .getBudgetPeriodSequenceNumber()));
625:
626: if (!ObjectUtils
627: .collectionContainsObjectWithIdentitcalKey(
628: budgetPeriods, budgetPeriod)) {
629: i.remove();
630: }
631: }
632: }
633: }
634:
635: /**
636: * This method finds and reports periods that have been modified from the last save.
637: *
638: * @param BudgetDocument The BudgetDocument whose periods are being checked.
639: * @return List A List of modified BudgetPeriods
640: */
641: private List findModifiedPeriods(BudgetDocument budgetDocument,
642: BudgetDocument databaseBudgetDocument) {
643: List modifiedPeriods = new ArrayList();
644:
645: List budgetPeriods = budgetDocument.getBudget().getPeriods();
646:
647: for (Iterator i = budgetPeriods.iterator(); i.hasNext();) {
648: BudgetPeriod budgetPeriod = (BudgetPeriod) i.next();
649: if (!databaseBudgetDocument.getBudget().getPeriods()
650: .contains(budgetPeriod)) {
651: modifiedPeriods.add(budgetPeriod);
652: }
653: }
654: return modifiedPeriods;
655: }
656:
657: /**
658: * This method will find and report any Appointment Types that have had changes to the associated Fringe Rates since the last
659: * save.
660: *
661: * @param budgetDocument
662: * @return List a list of appointments whose fringe rates have been modified
663: */
664: private List findModifiedFringeRates(BudgetDocument budgetDocument,
665: BudgetDocument databaseBudgetDocument) {
666: List modifiedFringeRates = new ArrayList();
667:
668: List budgetFringeRates = budgetDocument.getBudget()
669: .getFringeRates();
670:
671: for (Iterator i = budgetFringeRates.iterator(); i.hasNext();) {
672: BudgetFringeRate budgetFringeRate = (BudgetFringeRate) i
673: .next();
674: if (!databaseBudgetDocument.getBudget().getFringeRates()
675: .contains(budgetFringeRate)) {
676: modifiedFringeRates.add(budgetFringeRate);
677: }
678: }
679: return modifiedFringeRates;
680: }
681:
682: /**
683: * This method will find and report any Appointment Types that have had changes to the associated Fringe Rates since the last
684: * save.
685: *
686: * @param budgetDocument
687: * @return List a list of appointments whose fringe rates have been modified
688: */
689: private List findModifiedGraduateAssistantRates(
690: BudgetDocument budgetDocument,
691: BudgetDocument databaseBudgetDocument) {
692: List modifiedGradAsstRates = new ArrayList();
693:
694: List<BudgetGraduateAssistantRate> budgetGradAsstRates = budgetDocument
695: .getBudget().getGraduateAssistantRates();
696:
697: for (BudgetGraduateAssistantRate budgetGradAsstRate : budgetGradAsstRates) {
698: if (!databaseBudgetDocument.getBudget()
699: .getGraduateAssistantRates().contains(
700: budgetGradAsstRate)) {
701: modifiedGradAsstRates.add(budgetGradAsstRate);
702: }
703: }
704: return modifiedGradAsstRates;
705: }
706:
707: private List findModifiedUserAppointmentTaskPeriods(
708: BudgetDocument budgetDocument,
709: BudgetDocument databaseBudgetDocument) {
710: List modifiedList = new ArrayList();
711: List budgetList = budgetDocument.getBudget()
712: .getAllUserAppointmentTaskPeriods(false);
713: List databaseList = databaseBudgetDocument.getBudget()
714: .getAllUserAppointmentTaskPeriods(false);
715:
716: for (Iterator iter = budgetList.iterator(); iter.hasNext();) {
717: UserAppointmentTaskPeriod userAppointmentTaskPeriod = (UserAppointmentTaskPeriod) iter
718: .next();
719: if (!databaseList.contains(userAppointmentTaskPeriod)) {
720: modifiedList.add(userAppointmentTaskPeriod);
721: }
722: }
723:
724: return modifiedList;
725: }
726:
727: /**
728: * This method will find and report any Appointment Types that have had changes to the associated Fringe Rates since the last
729: * save.
730: *
731: * @param budgetDocument
732: * @return List a list of appointments whose fringe rates have been modified
733: */
734: private List findModifiedNonpersonnel(
735: BudgetDocument budgetDocument,
736: BudgetDocument databaseBudgetDocument) {
737: List modifiedNonpersonnel = new ArrayList();
738: List budgetList = budgetDocument.getBudget()
739: .getNonpersonnelItems();
740: List databaseList = databaseBudgetDocument.getBudget()
741: .getNonpersonnelItems();
742:
743: for (Iterator i = budgetList.iterator(); i.hasNext();) {
744: BudgetNonpersonnel budgetNonpersonnel = (BudgetNonpersonnel) i
745: .next();
746: if (!databaseList.contains(budgetNonpersonnel)) {
747: modifiedNonpersonnel.add(budgetNonpersonnel);
748: }
749: }
750: return modifiedNonpersonnel;
751: }
752:
753: /**
754: * The following methods are here for Spring's Dependency Injection to work.
755: */
756:
757: /**
758: * Sets the budgetFringeRateService attribute value.
759: *
760: * @param budgetFringeRateService The budgetFringeRateService to set.
761: */
762: public void setBudgetFringeRateService(
763: BudgetFringeRateService budgetFringeRateService) {
764: this .budgetFringeRateService = budgetFringeRateService;
765: }
766:
767: /**
768: * Sets the budgetGraduateAssistantRateService attribute value.
769: *
770: * @param budgetGraduateAssistantRateService The budgetGraduateAssistantRateService to set.
771: */
772: public void setBudgetGraduateAssistantRateService(
773: BudgetGraduateAssistantRateService budgetGraduateAssistantRateService) {
774: this .budgetGraduateAssistantRateService = budgetGraduateAssistantRateService;
775: }
776:
777: /**
778: * Sets the budgetPersonnelService attribute value.
779: *
780: * @param budgetPersonnelService The budgetPersonnelService to set.
781: */
782: public void setBudgetPersonnelService(
783: BudgetPersonnelService budgetPersonnelService) {
784: this .budgetPersonnelService = budgetPersonnelService;
785: }
786:
787: /**
788: * Sets the budgetCostShareService attribute value.
789: *
790: * @param budgetCostShareService The budgetCostShareService to set.
791: */
792: public void setBudgetCostShareService(
793: BudgetCostShareService budgetCostShareService) {
794: this .budgetCostShareService = budgetCostShareService;
795: }
796:
797: /**
798: * Sets the documentService attribute value.
799: *
800: * @param documentService The documentService to set.
801: */
802: public void setDocumentService(DocumentService documentService) {
803: this .documentService = documentService;
804: }
805:
806: /**
807: * Sets the budgetModularService attribute value.
808: *
809: * @param budgetModularService The budgetModularService to set.
810: */
811: public void setBudgetModularService(
812: BudgetModularService budgetModularService) {
813: this .budgetModularService = budgetModularService;
814: }
815:
816: /**
817: * @param budgetIndirectCostService The budgetIndirectCostService to set.
818: */
819: public void setBudgetIndirectCostService(
820: BudgetIndirectCostService budgetIndirectCostService) {
821: this .budgetIndirectCostService = budgetIndirectCostService;
822: }
823:
824: public void setBusinessObjectService(
825: BusinessObjectService businessObjectService) {
826: this .businessObjectService = businessObjectService;
827: }
828:
829: public void setDateTimeService(DateTimeService dateTimeService) {
830: this .dateTimeService = dateTimeService;
831: }
832:
833: public String getDisplayName(String documentNumber) {
834: Budget budget = (Budget) businessObjectService
835: .findByPrimaryKey(Budget.class,
836: mapPrimaryKeys(documentNumber));
837: if (budget == null) {
838: return "budget document not found";
839: }
840: return "PD: "
841: + budget.getProjectDirector().getUniversalUser()
842: .getPersonName() + " Agency: "
843: + budget.getBudgetAgency().getFullName();
844: }
845:
846: private Map<String, Object> mapPrimaryKeys(String documentNumber) {
847: Map<String, Object> primaryKeys = new HashMap();
848: primaryKeys.put(KFSPropertyConstants.DOCUMENT_NUMBER,
849: documentNumber.trim());
850: return primaryKeys;
851: }
852:
853: }
|