View Javadoc
1   /*
2    * The Kuali Financial System, a comprehensive financial management system for higher education.
3    * 
4    * Copyright 2005-2014 The Kuali Foundation
5    * 
6    * This program is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU Affero General Public License as
8    * published by the Free Software Foundation, either version 3 of the
9    * License, or (at your option) any later version.
10   * 
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU Affero General Public License for more details.
15   * 
16   * You should have received a copy of the GNU Affero General Public License
17   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  package org.kuali.kfs.module.ec.service.impl;
20  
21  import java.math.BigDecimal;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  
30  import org.apache.commons.lang.StringUtils;
31  import org.kuali.kfs.coa.businessobject.Account;
32  import org.kuali.kfs.integration.cg.ContractsAndGrantsModuleService;
33  import org.kuali.kfs.integration.ld.LaborLedgerExpenseTransferAccountingLine;
34  import org.kuali.kfs.integration.ld.LaborLedgerExpenseTransferSourceAccountingLine;
35  import org.kuali.kfs.integration.ld.LaborLedgerExpenseTransferTargetAccountingLine;
36  import org.kuali.kfs.integration.ld.LaborModuleService;
37  import org.kuali.kfs.module.ec.EffortConstants;
38  import org.kuali.kfs.module.ec.EffortKeyConstants;
39  import org.kuali.kfs.module.ec.businessobject.EffortCertificationDetail;
40  import org.kuali.kfs.module.ec.businessobject.EffortCertificationDetailBuild;
41  import org.kuali.kfs.module.ec.businessobject.EffortCertificationDocumentBuild;
42  import org.kuali.kfs.module.ec.businessobject.EffortCertificationReportDefinition;
43  import org.kuali.kfs.module.ec.document.EffortCertificationDocument;
44  import org.kuali.kfs.module.ec.document.validation.impl.EffortCertificationDocumentRuleUtil;
45  import org.kuali.kfs.module.ec.service.EffortCertificationDocumentService;
46  import org.kuali.kfs.sys.KFSConstants;
47  import org.kuali.kfs.sys.KFSPropertyConstants;
48  import org.kuali.kfs.sys.MessageBuilder;
49  import org.kuali.kfs.sys.businessobject.AccountingLineOverride;
50  import org.kuali.kfs.sys.businessobject.AccountingLineOverride.COMPONENT;
51  import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader;
52  import org.kuali.rice.core.api.util.type.KualiDecimal;
53  import org.kuali.rice.kew.api.WorkflowDocument;
54  import org.kuali.rice.kew.api.action.ActionRequestType;
55  import org.kuali.rice.kew.api.action.ActionTaken;
56  import org.kuali.rice.kew.api.action.ActionType;
57  import org.kuali.rice.kew.api.exception.WorkflowException;
58  import org.kuali.rice.kim.api.identity.Person;
59  import org.kuali.rice.kim.api.identity.PersonService;
60  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
61  import org.kuali.rice.krad.UserSession;
62  import org.kuali.rice.krad.bo.AdHocRoutePerson;
63  import org.kuali.rice.krad.service.BusinessObjectService;
64  import org.kuali.rice.krad.service.DocumentService;
65  import org.kuali.rice.krad.service.KualiModuleService;
66  import org.kuali.rice.krad.util.GlobalVariables;
67  import org.springframework.transaction.annotation.Transactional;
68  
69  /**
70   * To implement the services related to the effort certification document
71   */
72  @Transactional
73  public class EffortCertificationDocumentServiceImpl implements EffortCertificationDocumentService {
74      public static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(EffortCertificationDocumentServiceImpl.class);
75  
76      private LaborModuleService laborModuleService;
77      private KualiModuleService kualiModuleService;
78      private ContractsAndGrantsModuleService contractsAndGrantsModuleService;
79  
80      private DocumentService documentService;
81      private BusinessObjectService businessObjectService;
82  
83      /**
84       * @see org.kuali.kfs.module.ec.service.EffortCertificationDocumentService#processApprovedEffortCertificationDocument(org.kuali.kfs.module.ec.document.EffortCertificationDocument)
85       */
86      @Override
87      public void processApprovedEffortCertificationDocument(EffortCertificationDocument effortCertificationDocument) {
88          WorkflowDocument workflowDocument = effortCertificationDocument.getDocumentHeader().getWorkflowDocument();
89  
90          if (workflowDocument.isProcessed()) {
91              GlobalVariables.setUserSession(new UserSession(KFSConstants.SYSTEM_USER));
92              generateSalaryExpenseTransferDocument(effortCertificationDocument);
93          }
94      }
95  
96      /**
97       * @see org.kuali.kfs.module.ec.service.EffortCertificationDocumentService#createAndRouteEffortCertificationDocument(org.kuali.kfs.module.ec.businessobject.EffortCertificationDocumentBuild)
98       */
99  
100     @Override
101     public boolean createAndRouteEffortCertificationDocument(EffortCertificationDocumentBuild effortCertificationDocumentBuild) {
102         try {
103             EffortCertificationDocument effortCertificationDocument = (EffortCertificationDocument) documentService.getNewDocument(EffortConstants.EffortDocumentTypes.EFFORT_CERTIFICATION_DOCUMENT);
104             populateEffortCertificationDocument(effortCertificationDocument, effortCertificationDocumentBuild);
105             documentService.routeDocument(effortCertificationDocument, KFSConstants.EMPTY_STRING, null);
106         }
107         catch (WorkflowException we) {
108             LOG.error( "Unable to route ECD document: " + effortCertificationDocumentBuild, we);
109             throw new RuntimeException("Unable to route ECD document: " + effortCertificationDocumentBuild, we);
110         }
111 
112         return true;
113     }
114 
115     /**
116      * @see org.kuali.kfs.module.ec.service.EffortCertificationDocumentService#populateEffortCertificationDocument(org.kuali.kfs.module.ec.document.EffortCertificationDocument,
117      *      org.kuali.kfs.module.ec.businessobject.EffortCertificationDocumentBuild)
118      */
119 
120     @Override
121     public boolean populateEffortCertificationDocument(EffortCertificationDocument effortCertificationDocument, EffortCertificationDocumentBuild effortCertificationDocumentBuild) {
122         // populate the fields of the document
123         effortCertificationDocument.setUniversityFiscalYear(effortCertificationDocumentBuild.getUniversityFiscalYear());
124         effortCertificationDocument.setEmplid(effortCertificationDocumentBuild.getEmplid());
125         effortCertificationDocument.setEffortCertificationReportNumber(effortCertificationDocumentBuild.getEffortCertificationReportNumber());
126         effortCertificationDocument.setEffortCertificationDocumentCode(effortCertificationDocumentBuild.getEffortCertificationDocumentCode());
127 
128         // populate the detail line of the document
129         List<EffortCertificationDetail> detailLines = effortCertificationDocument.getEffortCertificationDetailLines();
130         detailLines.clear();
131 
132         List<EffortCertificationDetailBuild> detailLinesBuild = effortCertificationDocumentBuild.getEffortCertificationDetailLinesBuild();
133         for (EffortCertificationDetailBuild detailLineBuild : detailLinesBuild) {
134             detailLines.add(new EffortCertificationDetail(detailLineBuild));
135         }
136 
137         // populate the document header of the document
138         FinancialSystemDocumentHeader documentHeader = effortCertificationDocument.getFinancialSystemDocumentHeader();
139         documentHeader.setDocumentDescription(effortCertificationDocumentBuild.getEmplid());
140         documentHeader.setFinancialDocumentTotalAmount(EffortCertificationDocument.getDocumentTotalAmount(effortCertificationDocument));
141 
142         return true;
143     }
144 
145     /**
146      * @see org.kuali.kfs.module.ec.service.EffortCertificationDocumentService#resetEffortCertificationDetailLines(org.kuali.kfs.module.ec.document.EffortCertificationDocument)
147      */
148 
149     @Override
150     public void removeEffortCertificationDetailLines(EffortCertificationDocument effortCertificationDocument) {
151         Map<String, String> fieldValues = new HashMap<String, String>();
152         fieldValues.put(KFSPropertyConstants.DOCUMENT_NUMBER, effortCertificationDocument.getDocumentNumber());
153 
154         businessObjectService.deleteMatching(EffortCertificationDetail.class, fieldValues);
155     }
156 
157     /**
158      * @see org.kuali.kfs.module.ec.service.EffortCertificationDocumentService#generateSalaryExpenseTransferDocument(org.kuali.kfs.module.ec.document.EffortCertificationDocument)
159      */
160 
161     @Override
162     public boolean generateSalaryExpenseTransferDocument(EffortCertificationDocument effortCertificationDocument) {
163         List<LaborLedgerExpenseTransferAccountingLine> sourceAccoutingLines = this.buildSourceAccountingLines(effortCertificationDocument);
164         List<LaborLedgerExpenseTransferAccountingLine> targetAccoutingLines = this.buildTargetAccountingLines(effortCertificationDocument);
165 
166         if (sourceAccoutingLines.isEmpty() || targetAccoutingLines.isEmpty()) {
167             return true;
168         }
169 
170         String description = effortCertificationDocument.getEmplid();
171         String explanation = MessageBuilder.buildMessageWithPlaceHolder(EffortKeyConstants.MESSAGE_CREATE_SET_DOCUMENT_DESCRIPTION, effortCertificationDocument.getDocumentNumber()).toString();
172 
173         String annotation = KFSConstants.EMPTY_STRING;
174         List<String> adHocRecipients = new ArrayList<String>();
175         adHocRecipients.addAll(this.getFiscalOfficersIfAmountChanged(effortCertificationDocument));
176 
177         try {
178             laborModuleService.createAndBlankApproveSalaryExpenseTransferDocument(description, explanation, annotation, adHocRecipients, sourceAccoutingLines, targetAccoutingLines);
179         }
180         catch (WorkflowException we) {
181             LOG.error( "Error while routing SET document created from ECD: " + effortCertificationDocument, we);
182             throw new RuntimeException("Error while routing SET document created from ECD: " + effortCertificationDocument, we);
183         }
184         return true;
185     }
186 
187     /**
188      * @see org.kuali.kfs.module.ec.service.EffortCertificationDocumentService#addRouteLooping(org.kuali.kfs.module.ec.document.EffortCertificationDocument)
189      */
190 
191     @Override
192     public void addRouteLooping(EffortCertificationDocument effortCertificationDocument) {
193         WorkflowDocument workflowDocument = effortCertificationDocument.getDocumentHeader().getWorkflowDocument();
194         Set<Person> priorApprovers = getPriorApprovers(workflowDocument);
195 
196         for (EffortCertificationDetail detailLine : effortCertificationDocument.getEffortCertificationDetailLines()) {
197             boolean hasBeenChanged = EffortCertificationDocumentRuleUtil.isPayrollAmountChangedFromPersisted(detailLine);
198             if (!hasBeenChanged) {
199                 continue;
200             }
201             boolean isNewLine = detailLine.isNewLineIndicator();
202             if ( LOG.isInfoEnabled() ) {
203                 LOG.info( "EC Detail Line has been changed: " + detailLine );
204             }
205 
206             Account account = detailLine.getAccount();
207             Person fiscalOfficer = account.getAccountFiscalOfficerUser();
208             if ( fiscalOfficer != null && StringUtils.isNotBlank(fiscalOfficer.getPrincipalName())) {
209                 // KULEFR-206
210                 // String actionRequestOfOfficer = this.getActionRequest(routeLevelName, KFSConstants.RouteLevelNames.ACCOUNT);
211                 AdHocRoutePerson adHocRoutePerson = buildAdHocRouteRecipient(fiscalOfficer.getPrincipalName(), ActionRequestType.APPROVE);
212 
213                 addAdHocRoutePerson(effortCertificationDocument.getAdHocRoutePersons(), priorApprovers, adHocRoutePerson, isNewLine);
214             } else {
215                 LOG.warn( "Unable to obtain a fiscal officer for the detail line's account: " + account.getChartOfAccountsCode() + "-" + account.getAccountNumber() );
216             }
217 
218             Person projectDirector = contractsAndGrantsModuleService.getProjectDirectorForAccount(account);
219             if (projectDirector != null) {
220                 String accountProjectDirectorPersonUserId = projectDirector.getPrincipalName();
221                 // KULEFR-206
222                 // String actionRequestOfDirector = this.getActionRequest(routeLevelName,
223                 // KFSConstants.RouteLevelNames.PROJECT_MANAGEMENT);
224                 AdHocRoutePerson adHocRoutePerson = buildAdHocRouteRecipient(accountProjectDirectorPersonUserId, ActionRequestType.APPROVE);
225 
226                 addAdHocRoutePerson(effortCertificationDocument.getAdHocRoutePersons(), priorApprovers, adHocRoutePerson, isNewLine);
227             }
228         }
229     }
230 
231     /**
232      * add the given ad hoc route person in the list if the person is one of prior approvers and is not in the list
233      *
234      * @param adHocRoutePersonList Collection of adhoc route persons
235      * @param priorApprovers Set of prior approvers
236      * @param adHocRoutePerson person to adhoc route to
237      */
238     protected void addAdHocRoutePerson(Collection<AdHocRoutePerson> adHocRoutePersonList, Set<Person> priorApprovers, AdHocRoutePerson adHocRoutePerson) {
239         addAdHocRoutePerson(adHocRoutePersonList, priorApprovers, adHocRoutePerson, false);
240     }
241 
242     /**
243      * add the given ad hoc route person in the list if the person is one of prior approvers, or the change was a new line, and the person is not in the list
244      *
245      * @param adHocRoutePersonList Collection of adhoc route persons
246      * @param priorApprovers Set of prior approvers
247      * @param adHocRoutePerson person to adhoc route to
248      * @param isNewLine whether the change was a new line
249      */
250     protected void addAdHocRoutePerson(Collection<AdHocRoutePerson> adHocRoutePersonList, Set<Person> priorApprovers, AdHocRoutePerson adHocRoutePerson, boolean isNewLine) {
251         boolean canBeAdded = false;
252 
253         // if it's a new line, person can be added even if they weren't a prior approver
254         if (priorApprovers == null || isNewLine) {
255             canBeAdded = true;
256         } else {
257             // we only want to ad-hoc if the user previously approved this document
258             for (Person approver : priorApprovers) {
259                 if (StringUtils.equals(approver.getPrincipalName(), adHocRoutePerson.getId())) {
260                     canBeAdded = true;
261                     break;
262                 }
263             }
264         }
265 
266         if (canBeAdded) {
267             // check that we have not already added them for the same action
268             for (AdHocRoutePerson person : adHocRoutePersonList) {
269                 if (isSameAdHocRoutePerson(person, adHocRoutePerson)) {
270                     canBeAdded = false;
271                     break;
272                 }
273             }
274         }
275 
276         if (canBeAdded) {
277             adHocRoutePersonList.add(adHocRoutePerson);
278         }
279     }
280 
281     protected boolean isSameAdHocRoutePerson(AdHocRoutePerson person1, AdHocRoutePerson person2) {
282         if (person1 == null || person2 == null) {
283             return false;
284         }
285 
286         boolean isSameAdHocRoutePerson = StringUtils.equals(person1.getId(), person2.getId());
287         isSameAdHocRoutePerson &= person1.getType().equals(person2.getType());
288         isSameAdHocRoutePerson &= StringUtils.equals(person1.getActionRequested(), person2.getActionRequested());
289 
290         return isSameAdHocRoutePerson;
291     }
292 
293     protected Set<Person> getPriorApprovers(WorkflowDocument workflowDocument) {
294         PersonService personService = KimApiServiceLocator.getPersonService();
295         List<ActionTaken> actionsTaken = workflowDocument.getActionsTaken();
296         Set<String> principalIds = new HashSet<String>();
297         Set<Person> persons = new HashSet<Person>();
298 
299         for (ActionTaken actionTaken : actionsTaken) {
300             if (ActionType.APPROVE.equals(actionTaken.getActionTaken())) {
301                 String principalId = actionTaken.getPrincipalId();
302                 if (!principalIds.contains(principalId)) {
303                     principalIds.add(principalId);
304                     persons.add(personService.getPerson(principalId));
305                 }
306             }
307         }
308         return persons;
309     }
310 
311     /**
312      * build an adhoc route recipient from the given person user id and action request
313      *
314      * @param personUserId the given person user id
315      * @param actionRequest the given action request
316      * @return an adhoc route recipient built from the given information
317      */
318     protected AdHocRoutePerson buildAdHocRouteRecipient(String personUserId, ActionRequestType actionRequest) {
319         AdHocRoutePerson adHocRoutePerson = new AdHocRoutePerson();
320         adHocRoutePerson.setActionRequested(actionRequest.getCode());
321         adHocRoutePerson.setId(personUserId);
322 
323         return adHocRoutePerson;
324     }
325 
326     /**
327      * build the source accounting lines for a salary expense transfer document from the given effort certification document. In the
328      * holder, the first item is source accounting line list and the second the target accounting line list.
329      *
330      * @param effortCertificationDocument the given effort certification document
331      * @return the source accounting lines for a salary expense transfer document built from the given effort certification document
332      */
333     protected List<LaborLedgerExpenseTransferAccountingLine> buildSourceAccountingLines(EffortCertificationDocument effortCertificationDocument) {
334         List<LaborLedgerExpenseTransferAccountingLine> sourceAccountingLines = new ArrayList<LaborLedgerExpenseTransferAccountingLine>();
335 
336         List<EffortCertificationDetail> effortCertificationDetailLines = effortCertificationDocument.getEffortCertificationDetailLines();
337         for (EffortCertificationDetail detailLine : effortCertificationDetailLines) {
338             if (this.getDifference(detailLine).isPositive()) {
339                 LaborLedgerExpenseTransferSourceAccountingLine sourceLine = kualiModuleService.getResponsibleModuleService(LaborLedgerExpenseTransferSourceAccountingLine.class).createNewObjectFromExternalizableClass(LaborLedgerExpenseTransferSourceAccountingLine.class);
340                 this.addAccountingLineIntoList(sourceAccountingLines, sourceLine, effortCertificationDocument, detailLine);
341             }
342         }
343         return sourceAccountingLines;
344     }
345 
346     /**
347      * build the target accounting lines for a salary expense transfer document from the given effort certification document. In the
348      * holder, the first item is source accounting line list and the second the target accounting line list.
349      *
350      * @param effortCertificationDocument the given effort certification document
351      * @return the target accounting lines for a salary expense transfer document built from the given effort certification document
352      */
353     protected List<LaborLedgerExpenseTransferAccountingLine> buildTargetAccountingLines(EffortCertificationDocument effortCertificationDocument) {
354         List<LaborLedgerExpenseTransferAccountingLine> targetAccountingLines = new ArrayList<LaborLedgerExpenseTransferAccountingLine>();
355 
356         List<EffortCertificationDetail> effortCertificationDetailLines = effortCertificationDocument.getEffortCertificationDetailLines();
357         for (EffortCertificationDetail detailLine : effortCertificationDetailLines) {
358             if (this.getDifference(detailLine).isNegative()) {
359                 LaborLedgerExpenseTransferTargetAccountingLine targetLine = kualiModuleService.getResponsibleModuleService(LaborLedgerExpenseTransferTargetAccountingLine.class).createNewObjectFromExternalizableClass(LaborLedgerExpenseTransferTargetAccountingLine.class);
360                 this.addAccountingLineIntoList(targetAccountingLines, targetLine, effortCertificationDocument, detailLine);
361             }
362         }
363         return targetAccountingLines;
364     }
365 
366     /**
367      * get all fiscal officers of the detail line accounts where the salary amounts are changed
368      *
369      * @param effortCertificationDocument the given document that contains the detail lines
370      * @return all fiscal officers of the detail line accounts where the salary amounts are changed
371      */
372     protected Set<String> getFiscalOfficersIfAmountChanged(EffortCertificationDocument effortCertificationDocument) {
373         Set<String> fiscalOfficers = new HashSet<String>();
374 
375         List<EffortCertificationDetail> effortCertificationDetailLines = effortCertificationDocument.getEffortCertificationDetailLines();
376         for (EffortCertificationDetail detailLine : effortCertificationDetailLines) {
377             if (this.getDifference(detailLine).isNonZero()) {
378                 Account account = detailLine.getAccount();
379                 String accountFiscalOfficerPersonUserId = account.getAccountFiscalOfficerUser().getPrincipalName();
380 
381                 if (StringUtils.isEmpty(accountFiscalOfficerPersonUserId)) {
382                     fiscalOfficers.add(accountFiscalOfficerPersonUserId);
383                 }
384             }
385         }
386         return fiscalOfficers;
387     }
388 
389     /**
390      * add a new accounting line into the given accounting line list. The accounting line is generated from the given detail line
391      *
392      * @param accountingLines a list of accounting lines
393      * @param clazz the specified class of the accounting line
394      * @param effortCertificationDocument the given effort certification document that contains the given detail line
395      * @param detailLine the given detail line that is used to generate an accounting line
396      */
397     protected void addAccountingLineIntoList(List<LaborLedgerExpenseTransferAccountingLine> accountingLineList, LaborLedgerExpenseTransferAccountingLine accountingLine, EffortCertificationDocument effortCertificationDocument, EffortCertificationDetail detailLine) {
398         accountingLine.setSequenceNumber(accountingLineList.size() + 1);
399 
400         this.populateAccountingLine(effortCertificationDocument, detailLine, accountingLine);
401         accountingLineList.add(accountingLine);
402     }
403 
404     /**
405      * populate an accounting line from the given detail line
406      *
407      * @param effortCertificationDocument the given effort certification document that contains the given detail line
408      * @param detailLine the given detail line
409      * @param accountingLine the accounting line needed to be populated
410      */
411     protected void populateAccountingLine(EffortCertificationDocument effortCertificationDocument, EffortCertificationDetail detailLine, LaborLedgerExpenseTransferAccountingLine accountingLine) {
412         accountingLine.setChartOfAccountsCode(detailLine.getChartOfAccountsCode());
413         accountingLine.setAccountNumber(detailLine.getAccountNumber());
414         accountingLine.setSubAccountNumber(detailLine.getSubAccountNumber());
415 
416         accountingLine.setPostingYear(detailLine.getUniversityFiscalYear());
417         accountingLine.setFinancialObjectCode(detailLine.getFinancialObjectCode());
418         accountingLine.setBalanceTypeCode(KFSConstants.BALANCE_TYPE_ACTUAL);
419 
420         accountingLine.setAmount(this.getDifference(detailLine).abs());
421 
422         accountingLine.setFinancialSubObjectCode(null);
423         accountingLine.setProjectCode(null);
424         accountingLine.setOrganizationReferenceId(null);
425 
426         accountingLine.setEmplid(effortCertificationDocument.getEmplid());
427         accountingLine.setPositionNumber(detailLine.getPositionNumber());
428         accountingLine.setPayrollTotalHours(BigDecimal.ZERO);
429 
430         EffortCertificationReportDefinition reportDefinition = effortCertificationDocument.getEffortCertificationReportDefinition();
431         accountingLine.setPayrollEndDateFiscalYear(reportDefinition.getExpenseTransferFiscalYear());
432         accountingLine.setPayrollEndDateFiscalPeriodCode(reportDefinition.getExpenseTransferFiscalPeriodCode());
433 
434         accountingLine.refreshNonUpdateableReferences();
435 
436         AccountingLineOverride override = laborModuleService.determineNeededOverrides(null, accountingLine);
437 
438         // if an expired account override is needed, set it, otherwise validations on the downstream ST doc could fail
439         accountingLine.setAccountExpiredOverrideNeeded(override.hasComponent(COMPONENT.EXPIRED_ACCOUNT));
440         accountingLine.setAccountExpiredOverride(accountingLine.getAccountExpiredOverrideNeeded());
441 
442         // if a non-budgeted object code override is needed, set it, otherwise validations on the downstream ST doc could fail
443         accountingLine.setObjectBudgetOverrideNeeded(override.hasComponent(COMPONENT.NON_BUDGETED_OBJECT));
444         accountingLine.setObjectBudgetOverride(accountingLine.isObjectBudgetOverrideNeeded());
445 
446         if (accountingLine.getAccountExpiredOverrideNeeded() || accountingLine.isObjectBudgetOverrideNeeded()) {
447             accountingLine.setOverrideCode(override.getCode());
448         }
449 
450     }
451 
452     /**
453      * get the difference between the original amount and updated amount of the given detail line
454      *
455      * @param detailLine the given detail line
456      * @return the difference between the original amount and updated amount of the given detail line
457      */
458     protected KualiDecimal getDifference(EffortCertificationDetail detailLine) {
459         return detailLine.getEffortCertificationOriginalPayrollAmount().subtract(detailLine.getEffortCertificationPayrollAmount());
460     }
461 
462     /**
463      * Sets the laborModuleService attribute value.
464      *
465      * @param laborModuleService The laborModuleService to set.
466      */
467     public void setLaborModuleService(LaborModuleService laborModuleService) {
468         this.laborModuleService = laborModuleService;
469     }
470 
471     /**
472      * Sets the documentService attribute value.
473      *
474      * @param documentService The documentService to set.
475      */
476     public void setDocumentService(DocumentService documentService) {
477         this.documentService = documentService;
478     }
479 
480     /**
481      * Sets the businessObjectService attribute value.
482      *
483      * @param businessObjectService The businessObjectService to set.
484      */
485     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
486         this.businessObjectService = businessObjectService;
487     }
488 
489     /**
490      * Sets the contractsAndGrantsModuleService attribute value.
491      * @param contractsAndGrantsModuleService The contractsAndGrantsModuleService to set.
492      */
493     public void setContractsAndGrantsModuleService(ContractsAndGrantsModuleService contractsAndGrantsModuleService) {
494         this.contractsAndGrantsModuleService = contractsAndGrantsModuleService;
495     }
496 
497     /**
498      * Sets the kualiModuleService attribute value.
499      *
500      * @param kualiModuleService The kualiModuleService to set.
501      */
502     public void setKualiModuleService(KualiModuleService kualiModuleService) {
503         this.kualiModuleService = kualiModuleService;
504     }
505 }