View Javadoc
1   /*
2    * Copyright 2009 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.gl.batch.service.impl;
17  
18  import java.sql.Date;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.apache.commons.lang.ArrayUtils;
26  import org.kuali.ole.coa.businessobject.A21SubAccount;
27  import org.kuali.ole.coa.businessobject.BalanceType;
28  import org.kuali.ole.coa.businessobject.ObjectCode;
29  import org.kuali.ole.coa.businessobject.OffsetDefinition;
30  import org.kuali.ole.coa.businessobject.PriorYearAccount;
31  import org.kuali.ole.coa.businessobject.SubFundGroup;
32  import org.kuali.ole.coa.businessobject.SubObjectCode;
33  import org.kuali.ole.coa.service.A21SubAccountService;
34  import org.kuali.ole.coa.service.ObjectCodeService;
35  import org.kuali.ole.coa.service.ObjectTypeService;
36  import org.kuali.ole.coa.service.OffsetDefinitionService;
37  import org.kuali.ole.coa.service.SubFundGroupService;
38  import org.kuali.ole.coa.service.SubObjectCodeService;
39  import org.kuali.ole.gl.GeneralLedgerConstants;
40  import org.kuali.ole.gl.batch.EncumbranceForwardStep;
41  import org.kuali.ole.gl.batch.ScrubberStep;
42  import org.kuali.ole.gl.batch.service.AccountingCycleCachingService;
43  import org.kuali.ole.gl.batch.service.EncumbranceClosingOriginEntryGenerationService;
44  import org.kuali.ole.gl.batch.service.impl.exception.FatalErrorException;
45  import org.kuali.ole.gl.businessobject.Encumbrance;
46  import org.kuali.ole.gl.businessobject.OriginEntryFull;
47  import org.kuali.ole.select.document.OlePurchaseOrderDocument;
48  import org.kuali.ole.sys.OLEConstants;
49  import org.kuali.ole.sys.OLEPropertyConstants;
50  import org.kuali.ole.sys.context.SpringContext;
51  import org.kuali.ole.sys.service.FlexibleOffsetAccountService;
52  import org.kuali.ole.sys.service.OptionsService;
53  import org.kuali.ole.sys.service.impl.OleParameterConstants;
54  import org.kuali.rice.core.api.parameter.ParameterEvaluator;
55  import org.kuali.rice.core.api.parameter.ParameterEvaluatorService;
56  import org.kuali.rice.core.api.util.type.KualiDecimal;
57  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
58  import org.kuali.rice.kns.service.DataDictionaryService;
59  import org.kuali.rice.krad.service.BusinessObjectService;
60  import org.kuali.rice.krad.service.KRADServiceLocator;
61  
62  /**
63   * The default implementation of the EncumbranceClosingOriginEntryGenerationService
64   */
65  public class EncumbranceClosingOriginEntryGenerationServiceImpl implements EncumbranceClosingOriginEntryGenerationService {
66      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(EncumbranceClosingOriginEntryGenerationServiceImpl.class);
67      protected ParameterService parameterService;
68      protected OffsetDefinitionService offsetDefinitionService;
69      protected ObjectCodeService objectCodeService;
70      protected DataDictionaryService dataDictionaryService;
71      protected FlexibleOffsetAccountService flexibleOffsetAccountService;
72      protected A21SubAccountService a21SubAccountService;
73      protected SubObjectCodeService subObjectCodeService;
74      protected OptionsService optionsService;
75      protected SubFundGroupService subFundGroupService;
76      protected BusinessObjectService businessObjectService;
77      protected AccountingCycleCachingService accountingCycleCachingService;
78  
79      /**
80       * @see org.kuali.ole.gl.batch.service.EncumbranceClosingOriginEntryGenerationService#createBeginningBalanceEntryOffsetPair(org.kuali.ole.gl.businessobject.Encumbrance, java.lang.Integer, java.sql.Date)
81       */
82      @Override
83      public OriginEntryOffsetPair createCostShareBeginningBalanceEntryOffsetPair(Encumbrance encumbrance, Date transactionDate) {
84          final String GL_ACLO = getParameterService().getParameterValueAsString(OleParameterConstants.GENERAL_LEDGER_BATCH.class, OLEConstants.SystemGroupParameterNames.GL_ANNUAL_CLOSING_DOC_TYPE);
85          final String GL_ORIGINATION_CODE = getParameterService().getParameterValueAsString(OleParameterConstants.GENERAL_LEDGER_BATCH.class, OLEConstants.SystemGroupParameterNames.GL_ORIGINATION_CODE);
86  
87          OriginEntryOffsetPair pair = new OriginEntryOffsetPair();
88  
89          // Generate the entry ...
90  
91          OriginEntryFull entry = new OriginEntryFull(encumbrance.getDocumentTypeCode(), encumbrance.getOriginCode());
92  
93          String description = encumbrance.getTransactionEncumbranceDescription();
94          String fromDesc = "FR-" + encumbrance.getChartOfAccountsCode() + encumbrance.getAccountNumber();
95          int descLength = getDataDictionaryService().getAttributeMaxLength(OriginEntryFull.class, OLEPropertyConstants.TRANSACTION_LEDGER_ENTRY_DESC);
96          if ((description.length() + fromDesc.length()) < descLength) {
97              int padLength = descLength - (description.length() + fromDesc.length());
98              StringBuilder sb = new StringBuilder();
99              for (int i = 0; i < padLength; i++) {
100                 sb.append(' ');
101             }
102             sb.append(fromDesc);
103             fromDesc = sb.toString();
104             description += fromDesc;
105         }
106         else if ((description.length() + fromDesc.length()) > descLength) {
107             description = description.substring(0, (descLength - fromDesc.length())) + fromDesc;
108         }
109         else {
110             description += fromDesc;
111         }
112         entry.setTransactionLedgerEntryDescription(description);
113 
114         // SpringContext is used because this method is static.
115         A21SubAccount a21SubAccount = getA21SubAccountService().getByPrimaryKey(encumbrance.getChartOfAccountsCode(), encumbrance.getAccountNumber(), encumbrance.getSubAccountNumber());
116 
117         entry.setUniversityFiscalYear(new Integer(encumbrance.getUniversityFiscalYear().intValue() + 1));
118         entry.setChartOfAccountsCode(a21SubAccount.getCostShareChartOfAccountCode());
119         entry.setAccountNumber(a21SubAccount.getCostShareSourceAccountNumber());
120         entry.setSubAccountNumber(a21SubAccount.getCostShareSourceSubAccountNumber());
121 
122         // The subAccountNumber is set to dashes in the OriginEntryFull constructor.
123         if (entry.getSubAccountNumber() == null || OLEConstants.EMPTY_STRING.equals(entry.getSubAccountNumber().trim())) {
124             entry.setSubAccountNumber(OLEConstants.getDashSubAccountNumber());
125         }
126 
127 //        ObjectCode finObjCode = accountingCycleCachingService.getObjectCode(encumbrance.getUniversityFiscalYear(), entry.getChartOfAccountsCode(), entry.getFinancialObjectCode());
128 //        if (finObjCode != null)
129 //            entry.setFinancialObjectTypeCode(finObjCode.getFinancialObjectTypeCode());
130 //        
131         
132         ObjectCode encumbranceObjectCode = accountingCycleCachingService.getObjectCode(entry.getUniversityFiscalYear(), entry.getChartOfAccountsCode(), encumbrance.getObjectCode());
133         
134         if (null != encumbranceObjectCode) {
135 
136             String financialObjectLevelCode = encumbranceObjectCode.getFinancialObjectLevelCode();
137             String financialObjectCode = encumbrance.getObjectCode();
138             
139             String overriddenObjectCode = overrideCostShareObjectCode(financialObjectLevelCode, financialObjectCode);
140             final ObjectCode overriddenObject = this.getAccountingCycleCachingService().getObjectCode(entry.getUniversityFiscalYear(), entry.getChartOfAccountsCode(), overriddenObjectCode);
141             
142             String param = parameterService.getSubParameterValueAsString(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.COST_SHARE_OBJECT_CODE_BY_LEVEL_PARM_NM, overriddenObject.getFinancialObjectLevelCode());
143             if (param == null) {
144                 param = parameterService.getSubParameterValueAsString(ScrubberStep.class, GeneralLedgerConstants.GlScrubberGroupParameters.COST_SHARE_OBJECT_CODE_BY_LEVEL_PARM_NM, "DEFAULT");
145                 if (param == null) {
146                     throw new RuntimeException("Unable to determine cost sharing object code from object level (" + overriddenObject.getFinancialObjectLevelCode() + ").  Default entry missing.");
147                 }
148             }
149             financialObjectCode = param;
150 
151          // Lookup the new object code
152             ObjectCode newObjectCode = accountingCycleCachingService.getObjectCode(entry.getUniversityFiscalYear(), entry.getChartOfAccountsCode(), financialObjectCode);
153             if (newObjectCode != null) {
154                 entry.setFinancialObjectTypeCode(newObjectCode.getFinancialObjectTypeCode());
155                 entry.setFinancialObjectCode(financialObjectCode);
156             }
157             else {
158                 LOG.error("Error retrieving ObjectCode("+entry.getUniversityFiscalYear()+"/"+entry.getChartOfAccountsCode()+"/"+financialObjectCode+")");
159                 pair.setFatalErrorFlag(true);
160                 return pair;
161             }
162         } else {
163 
164             LOG.error("Error retrieving ObjectCode("+entry.getUniversityFiscalYear()+"/"+entry.getChartOfAccountsCode()+"/"+entry.getFinancialObjectCode()+")");
165             pair.setFatalErrorFlag(true);
166             return pair;
167 
168         }
169         
170         
171         entry.setFinancialSubObjectCode(OLEConstants.getDashFinancialSubObjectCode());
172         entry.setFinancialBalanceTypeCode(OLEConstants.BALANCE_TYPE_COST_SHARE_ENCUMBRANCE);
173 
174         entry.setUniversityFiscalPeriodCode(OLEConstants.PERIOD_CODE_BEGINNING_BALANCE);
175         entry.setTransactionLedgerEntrySequenceNumber(new Integer(0));
176         entry.setDocumentNumber(encumbrance.getDocumentNumber());
177         entry.setFinancialBalanceTypeCode(OLEConstants.BALANCE_TYPE_COST_SHARE_ENCUMBRANCE);
178 
179         KualiDecimal delta = encumbrance.getAccountLineEncumbranceAmount().subtract(encumbrance.getAccountLineEncumbranceClosedAmount());
180         if (delta.isPositive()) {
181             entry.setTransactionDebitCreditCode(OLEConstants.GL_DEBIT_CODE);
182             entry.setTransactionLedgerEntryAmount(delta);
183         }
184         else {
185             entry.setTransactionDebitCreditCode(OLEConstants.GL_CREDIT_CODE);
186             entry.setTransactionLedgerEntryAmount(delta.negated());
187         }
188         entry.setTransactionEncumbranceUpdateCode(OLEConstants.ENCUMB_UPDT_DOCUMENT_CD);
189         entry.setProjectCode(OLEConstants.getDashProjectCode());
190         entry.setTransactionDate(transactionDate);
191 
192         pair.setEntry(entry);
193 
194         // And now the offset ...
195 
196         OriginEntryFull offset = new OriginEntryFull(encumbrance.getDocumentTypeCode(), encumbrance.getOriginCode());
197         final String GENERATED_TRANSACTION_LEDGER_ENTRY_DESCRIPTION = getParameterService().getParameterValueAsString(EncumbranceForwardStep.class, GeneralLedgerConstants.EncumbranceClosingOriginEntry.GENERATED_TRANSACTION_LEDGER_ENTRY_DESCRIPTION);
198         offset.setTransactionLedgerEntryDescription(GENERATED_TRANSACTION_LEDGER_ENTRY_DESCRIPTION);
199 
200         offset.setUniversityFiscalYear(new Integer(encumbrance.getUniversityFiscalYear().intValue() + 1));
201         offset.setChartOfAccountsCode(a21SubAccount.getCostShareChartOfAccountCode());
202         offset.setAccountNumber(a21SubAccount.getCostShareSourceAccountNumber());
203         offset.setSubAccountNumber(a21SubAccount.getCostShareSourceSubAccountNumber());
204         if (offset.getSubAccountNumber() == null || OLEConstants.EMPTY_STRING.equals(offset.getSubAccountNumber().trim())) {
205             offset.setSubAccountNumber(OLEConstants.getDashSubAccountNumber());
206         }
207         // Lookup the offset definition for the explicit entry we just created.
208         OffsetDefinition offsetDefinition = getOffsetDefinitionService().getByPrimaryId(entry.getUniversityFiscalYear(), entry.getChartOfAccountsCode(), entry.getFinancialDocumentTypeCode(), entry.getFinancialBalanceTypeCode());
209         // Set values from the offset definition if it was found.
210         if (null != offsetDefinition) {
211 
212             offset.setFinancialObjectCode(offsetDefinition.getFinancialObjectCode());
213             offset.setFinancialSubObjectCode(OLEConstants.getDashFinancialSubObjectCode());
214         }
215         else { // Log an exception if the offset definition was not found.
216 
217             LOG.info("FATAL ERROR: One of the following errors occurred (no way to know exactly which):\n\t" + "- OFFSET DEFINITION NOT FOUND\n\t" + "- ERROR ACCESSING OFSD TABLE");
218             pair.setFatalErrorFlag(true);
219             return pair;
220 
221         }
222         offset.setFinancialBalanceTypeCode(OLEConstants.BALANCE_TYPE_COST_SHARE_ENCUMBRANCE);
223         // Validate the object code for the explicit entry.
224         ObjectCode objectCode = getObjectCodeService().getByPrimaryId(offset.getUniversityFiscalYear(), offset.getChartOfAccountsCode(), offset.getFinancialObjectCode());
225         if (null != objectCode) {
226             offset.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode());
227         }
228         else {
229             LOG.info("FATAL ERROR: One of the following errors occurred (no way to know exactly which):\n\t" + "- NO OBJECT FOR OBJECT ON OFSD\n\t" + "- ERROR ACCESSING OBJECT TABLE");
230             pair.setFatalErrorFlag(true);
231             return pair;
232         }
233         offset.setUniversityFiscalPeriodCode(OLEConstants.PERIOD_CODE_BEGINNING_BALANCE);
234         offset.setDocumentNumber(encumbrance.getDocumentNumber());
235         offset.setTransactionLedgerEntrySequenceNumber(new Integer(0));
236         if (delta.isPositive()) {
237             offset.setTransactionDebitCreditCode(OLEConstants.GL_CREDIT_CODE);
238             offset.setTransactionLedgerEntryAmount(delta);
239         }
240         else {
241             offset.setTransactionDebitCreditCode(OLEConstants.GL_DEBIT_CODE);
242             offset.setTransactionLedgerEntryAmount(delta.negated());
243         }
244 
245         offset.setTransactionEncumbranceUpdateCode(null);
246         offset.setOrganizationDocumentNumber(null);
247         offset.setProjectCode(OLEConstants.getDashProjectCode());
248         offset.setTransactionDate(transactionDate);
249         offset.setOrganizationReferenceId(null);
250         offset.setReferenceFinancialDocumentTypeCode(null);
251         offset.setReferenceFinancialSystemOriginationCode(null);
252         offset.setReferenceFinancialDocumentNumber(null);
253         offset.setReversalDate(null);
254         
255         getFlexibleOffsetAccountService().updateOffset(offset);
256 
257         pair.setOffset(offset);
258 
259         return pair;
260     }
261 
262     /**
263      * @see org.kuali.ole.gl.batch.service.EncumbranceClosingOriginEntryGenerationService#createCostShareBeginningBalanceEntryOffsetPair(org.kuali.ole.gl.businessobject.Encumbrance, java.sql.Date)
264      */
265     @Override
266     public OriginEntryOffsetPair createBeginningBalanceEntryOffsetPair(Encumbrance encumbrance, Integer closingFiscalYear, Date transactionDate) {
267         OriginEntryOffsetPair pair = new OriginEntryOffsetPair();
268 
269         // Build the entry ...
270         OriginEntryFull entry = new OriginEntryFull(encumbrance.getDocumentTypeCode(), encumbrance.getOriginCode());
271 
272         Integer thisFiscalYear = new Integer(closingFiscalYear.intValue() + 1);
273         entry.setUniversityFiscalYear(thisFiscalYear);
274         entry.setChartOfAccountsCode(encumbrance.getChartOfAccountsCode());
275         entry.setAccountNumber(encumbrance.getAccountNumber());
276         entry.setSubAccountNumber(encumbrance.getSubAccountNumber());
277 
278         ObjectCode objectCode = accountingCycleCachingService.getObjectCode(entry.getUniversityFiscalYear(), entry.getChartOfAccountsCode(), encumbrance.getObjectCode());
279         
280         if (null != objectCode) {
281 
282             entry.setFinancialObjectTypeCode(objectCode.getFinancialObjectTypeCode());
283 
284             if (null != objectCode.getNextYearFinancialObjectCode() && !OLEConstants.EMPTY_STRING.equals(objectCode.getNextYearFinancialObjectCode().trim())) {
285 
286                 entry.setFinancialObjectCode(objectCode.getNextYearFinancialObjectCode());
287 
288             }
289             else {
290 
291                 entry.setFinancialObjectCode(encumbrance.getObjectCode());
292 
293             }
294 
295         }
296         
297         
298         else {
299 
300             LOG.error("Error retrieving ObjectCode("+entry.getUniversityFiscalYear()+"/"+entry.getChartOfAccountsCode()+"/"+entry.getFinancialObjectCode()+")");
301             pair.setFatalErrorFlag(true);
302             return pair;
303 
304         }
305 
306         SubObjectCode subObjectCode = getSubObjectCodeService().getByPrimaryId(encumbrance.getUniversityFiscalYear(), encumbrance.getChartOfAccountsCode(), encumbrance.getAccountNumber(), encumbrance.getObjectCode(), encumbrance.getSubObjectCode());
307 
308         if (null != subObjectCode) {
309 
310             entry.setFinancialSubObjectCode(subObjectCode.getFinancialSubObjectCode());
311 
312         }
313         else {
314 
315             entry.setFinancialSubObjectCode(OLEConstants.getDashFinancialSubObjectCode());
316 
317         }
318 
319         entry.setFinancialBalanceTypeCode(encumbrance.getBalanceTypeCode());
320         entry.setUniversityFiscalPeriodCode(OLEConstants.PERIOD_CODE_BEGINNING_BALANCE);
321         Map map = new HashMap();
322         map.put(OLEConstants.PUR_AP_IDEN,encumbrance.getDocumentNumber());
323         List<OlePurchaseOrderDocument> olePurchaseOrderDocument = ( List<OlePurchaseOrderDocument>)KRADServiceLocator.getBusinessObjectService().findMatching(OlePurchaseOrderDocument.class, map);
324         if(olePurchaseOrderDocument.size() > 0){
325             entry.setDocumentNumber(olePurchaseOrderDocument.get(0).getDocumentNumber());
326         }
327         entry.setTransactionLedgerEntrySequenceNumber(new Integer(1));
328         entry.setTransactionLedgerEntryDescription(encumbrance.getTransactionEncumbranceDescription());
329         entry.setTransactionLedgerEntryAmount(encumbrance.getAccountLineEncumbranceAmount().subtract(encumbrance.getAccountLineEncumbranceClosedAmount()));
330 
331         if (entry.getTransactionLedgerEntryAmount().isNegative()) {
332 
333             entry.setTransactionLedgerEntryAmount(entry.getTransactionLedgerEntryAmount().negated());
334             entry.setTransactionDebitCreditCode(OLEConstants.GL_CREDIT_CODE);
335 
336         }
337         else {
338 
339             entry.setTransactionDebitCreditCode(OLEConstants.GL_DEBIT_CODE);
340 
341         }
342 
343         entry.setTransactionDate(transactionDate);
344         entry.setOrganizationDocumentNumber(null);
345         entry.setProjectCode(OLEConstants.getDashProjectCode());
346         entry.setOrganizationReferenceId(null);
347         entry.setReferenceFinancialDocumentTypeCode(null);
348         entry.setReferenceFinancialSystemOriginationCode(null);
349         entry.setReferenceFinancialDocumentNumber(null);
350         entry.setReversalDate(null);
351         entry.setTransactionEncumbranceUpdateCode(OLEConstants.ENCUMB_UPDT_DOCUMENT_CD);
352 
353         pair.setEntry(entry);
354 
355         final String OBJECT_CODE_FOR_BALANCE_TYPE_INTERNAL_ENCUMBRANCE = getParameterService().getParameterValueAsString(EncumbranceForwardStep.class, GeneralLedgerConstants.EncumbranceClosingOriginEntry.OFFSET_OBJECT_CODE_FOR_INTERNAL_ENCUMBRANCE);
356         final String OBJECT_CODE_FOR_BALANCE_TYPE_PRE_ENCUMBRANCE = getParameterService().getParameterValueAsString(EncumbranceForwardStep.class, GeneralLedgerConstants.EncumbranceClosingOriginEntry.OFFSET_OBJECT_CODE_FOR_PRE_ENCUMBRANCE);
357         final String OBJECT_CODE_FOR_BALANCE_TYPE_EXTERNAL_ENCUMBRANCE = getParameterService().getParameterValueAsString(EncumbranceForwardStep.class, GeneralLedgerConstants.EncumbranceClosingOriginEntry.OFFSET_OBJECT_CODE_FOR_EXTERNAL_ENCUMBRANCE);
358         final String BEGINNING_FUND_TRANSACTION_LEDGER_ENTRY_DESCRIPTION = getParameterService().getParameterValueAsString(EncumbranceForwardStep.class, GeneralLedgerConstants.EncumbranceClosingOriginEntry.BEGINNING_FUND_BALANCE_TRANSACTION_LEDGER_ENTRY_DESCRIPTION);
359 
360         // And now build the offset.
361         OriginEntryFull offset = new OriginEntryFull(entry);
362         offset.setTransactionLedgerEntryAmount(entry.getTransactionLedgerEntryAmount());
363         // OLEConstants.BALANCE_TYPE_INTERNAL_ENCUMBRANCE case...
364         offset.setFinancialObjectCode(OBJECT_CODE_FOR_BALANCE_TYPE_INTERNAL_ENCUMBRANCE);
365 
366         if (OLEConstants.BALANCE_TYPE_PRE_ENCUMBRANCE.equals(entry.getFinancialBalanceTypeCode())) {
367 
368             offset.setFinancialObjectCode(OBJECT_CODE_FOR_BALANCE_TYPE_PRE_ENCUMBRANCE);
369 
370         }
371         else if (OLEConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE.equals(entry.getFinancialBalanceTypeCode())) {
372 
373             offset.setFinancialObjectCode(OBJECT_CODE_FOR_BALANCE_TYPE_EXTERNAL_ENCUMBRANCE);
374 
375         }
376 
377         offset.setFinancialObjectTypeCode(getOptionsService().getCurrentYearOptions().getFinObjectTypeFundBalanceCd());
378         offset.setTransactionLedgerEntryDescription(BEGINNING_FUND_TRANSACTION_LEDGER_ENTRY_DESCRIPTION);
379 
380         if (OLEConstants.GL_DEBIT_CODE.equals(entry.getTransactionDebitCreditCode())) {
381 
382             offset.setTransactionDebitCreditCode(OLEConstants.GL_CREDIT_CODE);
383 
384         }
385         else {
386 
387             offset.setTransactionDebitCreditCode(OLEConstants.GL_DEBIT_CODE);
388 
389         }
390         getFlexibleOffsetAccountService().updateOffset(offset);
391         
392         pair.setOffset(offset);
393 
394         return pair;
395     }
396     
397     /**
398      * Determine whether or not an encumbrance should be carried forward from one fiscal year to the next.
399      * 
400      * @param encumbrance the encumbrance to qualify
401      * @return true if the encumbrance should be rolled forward from the closing fiscal year to the opening fiscal year.
402      */
403     @Override
404     public boolean shouldForwardEncumbrance(Encumbrance encumbrance) {
405         // null guard
406         if (null == encumbrance) {
407             return false;
408         }
409 
410         if (encumbrance.getAccountLineEncumbranceAmount().equals(encumbrance.getAccountLineEncumbranceClosedAmount())) {
411             return false;
412         }
413 
414         if (getEncumbranceBalanceTypeCodes().contains(encumbrance.getBalanceTypeCode())) {
415 
416             ParameterEvaluator evaluator = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(EncumbranceForwardStep.class, GeneralLedgerConstants.EncumbranceClosingOriginEntry.FORWARD_ENCUMBRANCE_BALANCE_TYPE_AND_ORIGIN_CODE,encumbrance.getBalanceTypeCode(),  encumbrance.getOriginCode());
417             if (!evaluator.evaluationSucceeds()) {
418                 return false;
419             }
420             else if (OLEConstants.BALANCE_TYPE_PRE_ENCUMBRANCE.equals(encumbrance.getBalanceTypeCode())) {
421                 // pre-encumbrances are forwarded, but only if they're related to contracts and grants accounts
422                 PriorYearAccount priorYearAccount = retrievePriorYearAccount(encumbrance.getChartOfAccountsCode(), encumbrance.getAccountNumber());
423                 // the account on the encumbrance must be valid
424                 if (null == priorYearAccount) {
425                     LOG.info("No prior year account for chart \"" + encumbrance.getChartOfAccountsCode() + "\" and account \"" + encumbrance.getAccountNumber() + "\"");
426                     return false;
427                 }
428                 // the sub fund group must exist for the prior year account and the
429                 // encumbrance must not be closed.
430                 return priorYearAccount.isForContractsAndGrants();
431             }
432             else {
433                 // we're still here? because we're an external encumbrance, and we always get forwarded
434                 return true;
435             }
436         }
437         // we're still here? because we're not of a valid encumbrance balance type; we don't get forwarded
438         return false;
439 
440     }
441     
442     /**
443      * @return a list of BalanceType codes which correspond to encumbrance balance types
444      */
445     protected List<String> getEncumbranceBalanceTypeCodes() {
446         List<String> balanceTypeCodes = new ArrayList<String>();
447         
448         
449         Map<String, Object> keys = new HashMap<String, Object>();
450         keys.put("active", Boolean.TRUE);
451         keys.put("finBalanceTypeEncumIndicator", Boolean.TRUE);
452         Collection balanceTypes = businessObjectService.findMatching(BalanceType.class, keys);
453         for (Object balanceTypeAsObject : balanceTypes) {
454             ParameterEvaluator evaluator = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(EncumbranceForwardStep.class, GeneralLedgerConstants.EncumbranceClosingOriginEntry.FORWARDING_ENCUMBRANCE_BALANCE_TYPES, ((BalanceType)balanceTypeAsObject).getCode());
455             if (evaluator.evaluationSucceeds())
456                 balanceTypeCodes.add(((BalanceType)balanceTypeAsObject).getCode()); 
457         }
458        
459         return balanceTypeCodes;
460     }
461     
462     /**
463      * Determine whether or not the encumbrance has been fully relieved.
464      * 
465      * @param encumbrance the encumbrance to qualify
466      * @return true if the amount closed on the encumbrance is NOT equal to the amount of the encumbrance itself, e.g. if the
467      *         encumbrance has not yet been paid off.
468      */
469     @Override
470     public boolean isEncumbranceClosed(Encumbrance encumbrance) {
471         if (encumbrance.getAccountLineEncumbranceAmount().doubleValue() == encumbrance.getAccountLineEncumbranceClosedAmount().doubleValue()) {
472             return false;
473         }
474         return true;
475     }
476     
477     /**
478      * Do some validation and make sure that the encumbrance A21SubAccount is a cost share sub-account.
479      * 
480      * @param entry not used in this implementation
481      * @param offset not used in this implementation
482      * @param encumbrance the encumbrance whose A21SubAccount must be qualified
483      * @param objectTypeCode the object type code of the generated entries
484      * @return true if the encumbrance is eligible for cost share.
485      * @throws FatalErrorException thrown if a given A21SubAccount, SubFundGroup, or PriorYearAccount record is not found in the database
486      */
487     @Override
488     public boolean shouldForwardCostShareForEncumbrance(OriginEntryFull entry, OriginEntryFull offset, Encumbrance encumbrance, String objectTypeCode) throws FatalErrorException {
489         PriorYearAccount priorYearAccount = retrievePriorYearAccount(encumbrance.getChartOfAccountsCode(), encumbrance.getAccountNumber());
490 
491         // the sub fund group for the prior year account must exist.
492         String subFundGroupCode = null;
493         if (null != priorYearAccount) {
494             subFundGroupCode = priorYearAccount.getSubFundGroupCode();
495         }
496         else {
497             // this message was carried over from the cobol.
498             throw new FatalErrorException("ERROR ACCESSING PRIOR YR ACCT TABLE FOR " + encumbrance.getAccountNumber());
499         }
500 
501         SubFundGroup subFundGroup = getSubFundGroupService().getByPrimaryId(subFundGroupCode);
502         if (null != subFundGroup) {
503             if (!priorYearAccount.isForContractsAndGrants()) {
504                 return false;
505             }
506         }
507         else {
508             throw new FatalErrorException("ERROR ACCESSING SUB FUND GROUP TABLE FOR " + subFundGroupCode);
509         }
510 
511         // I think this is redundant to the statement a few lines above here.
512         // In any case, the sub fund group must not be contracts and grants.
513         if (!priorYearAccount.isForContractsAndGrants()) {
514             return false;
515         }
516 
517         ObjectTypeService objectTypeService = (ObjectTypeService) SpringContext.getBean(ObjectTypeService.class);
518         List<String> expenseObjectCodeTypes = objectTypeService.getCurrentYearExpenseObjectTypes();
519 
520         String[] encumbranceBalanceTypeCodes = new String[] { OLEConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE, OLEConstants.BALANCE_TYPE_INTERNAL_ENCUMBRANCE, OLEConstants.BALANCE_TYPE_PRE_ENCUMBRANCE };
521 
522         // the object type code must be an expense and the encumbrance balance type code must correspond to an internal, external or
523         // pre-encumbrance
524         if (!expenseObjectCodeTypes.contains(objectTypeCode) || !ArrayUtils.contains(encumbranceBalanceTypeCodes, encumbrance.getBalanceTypeCode())) {
525             return false;
526         }
527         else if (!encumbrance.getSubAccountNumber().equals(OLEConstants.getDashSubAccountNumber())) {
528             A21SubAccount a21SubAccount = getA21SubAccountService().getByPrimaryKey(encumbrance.getChartOfAccountsCode(), encumbrance.getAccountNumber(), encumbrance.getSubAccountNumber());
529             if (null == a21SubAccount) {
530                 // Error message carried over from cobol. not very well descriptive.
531                 // Just indicates that the a21 sub account doesn't exist.
532                 throw new FatalErrorException("ERROR ACCESSING A21 SUB ACCOUNT TABLE FOR ENCUMBRANCE " + encumbrance.getChartOfAccountsCode() + "-" + encumbrance.getAccountNumber() + " " + encumbrance.getSubAccountNumber());
533             }
534             // everything is valid, return true if the a21 sub account is a cost share sub-account
535             return OLEConstants.SubAccountType.COST_SHARE.equals(a21SubAccount.getSubAccountTypeCode());
536         }
537         else {
538             return false;
539         }
540 
541     }
542     
543     /**
544      * Retrieves a prior year account from the persistence store
545      * @param chartOfAccountsCode the chart of accounts for the prior year account
546      * @param accountNumber the account number for the prior year account
547      * @return the PriorYearAccount
548      */
549     protected PriorYearAccount retrievePriorYearAccount(String chartOfAccountsCode, String accountNumber) {
550         Map pks = new HashMap();
551         pks.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode);
552         pks.put(OLEPropertyConstants.ACCOUNT_NUMBER, accountNumber);
553         
554         return (PriorYearAccount)this.getBusinessObjectService().findByPrimaryKey(PriorYearAccount.class, pks);
555     }
556     
557     /**
558      * 
559      * This method eases the institutional customization for Cost Sharing Object Codes for OriginEntries
560      * @param levelCode of the originEntry
561      * @param objectCode of the originEntry
562      * @return the new objectCode 
563      */
564     
565     protected String overrideCostShareObjectCode(String levelCode, String objectCode){
566         return objectCode;
567     }
568 
569     /**
570      * Gets the parameterService attribute. 
571      * @return Returns the parameterService.
572      */
573     public ParameterService getParameterService() {
574         return parameterService;
575     }
576 
577     /**
578      * Sets the parameterService attribute value.
579      * @param parameterService The parameterService to set.
580      */
581     public void setParameterService(ParameterService parameterService) {
582         this.parameterService = parameterService;
583     }
584 
585     /**
586      * Gets the offsetDefinitionService attribute. 
587      * @return Returns the offsetDefinitionService.
588      */
589     public OffsetDefinitionService getOffsetDefinitionService() {
590         return offsetDefinitionService;
591     }
592 
593     /**
594      * Sets the offsetDefinitionService attribute value.
595      * @param offsetDefinitionService The offsetDefinitionService to set.
596      */
597     public void setOffsetDefinitionService(OffsetDefinitionService offsetDefinitionService) {
598         this.offsetDefinitionService = offsetDefinitionService;
599     }
600 
601     /**
602      * Gets the objectCodeService attribute. 
603      * @return Returns the objectCodeService.
604      */
605     public ObjectCodeService getObjectCodeService() {
606         return objectCodeService;
607     }
608 
609     /**
610      * Sets the objectCodeService attribute value.
611      * @param objectCodeService The objectCodeService to set.
612      */
613     public void setObjectCodeService(ObjectCodeService objectCodeService) {
614         this.objectCodeService = objectCodeService;
615     }
616 
617     /**
618      * Gets the dataDictionaryService attribute. 
619      * @return Returns the dataDictionaryService.
620      */
621     public DataDictionaryService getDataDictionaryService() {
622         return dataDictionaryService;
623     }
624 
625     /**
626      * Sets the dataDictionaryService attribute value.
627      * @param dataDictionaryService The dataDictionaryService to set.
628      */
629     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
630         this.dataDictionaryService = dataDictionaryService;
631     }
632 
633     /**
634      * Gets the flexibleOffsetAccountService attribute. 
635      * @return Returns the flexibleOffsetAccountService.
636      */
637     public FlexibleOffsetAccountService getFlexibleOffsetAccountService() {
638         return flexibleOffsetAccountService;
639     }
640 
641     /**
642      * Sets the flexibleOffsetAccountService attribute value.
643      * @param flexibleOffsetAccountService The flexibleOffsetAccountService to set.
644      */
645     public void setFlexibleOffsetAccountService(FlexibleOffsetAccountService flexibleOffsetAccountService) {
646         this.flexibleOffsetAccountService = flexibleOffsetAccountService;
647     }
648 
649     /**
650      * Gets the a21SubAccountService attribute. 
651      * @return Returns the a21SubAccountService.
652      */
653     public A21SubAccountService getA21SubAccountService() {
654         return a21SubAccountService;
655     }
656 
657     /**
658      * Sets the a21SubAccountService attribute value.
659      * @param subAccountService The a21SubAccountService to set.
660      */
661     public void setA21SubAccountService(A21SubAccountService subAccountService) {
662         a21SubAccountService = subAccountService;
663     }
664 
665     /**
666      * Gets the subObjectCodeService attribute. 
667      * @return Returns the subObjectCodeService.
668      */
669     public SubObjectCodeService getSubObjectCodeService() {
670         return subObjectCodeService;
671     }
672 
673     /**
674      * Sets the subObjectCodeService attribute value.
675      * @param subObjectCodeService The subObjectCodeService to set.
676      */
677     public void setSubObjectCodeService(SubObjectCodeService subObjectCodeService) {
678         this.subObjectCodeService = subObjectCodeService;
679     }
680 
681     /**
682      * Gets the optionsService attribute. 
683      * @return Returns the optionsService.
684      */
685     public OptionsService getOptionsService() {
686         return optionsService;
687     }
688 
689     /**
690      * Sets the optionsService attribute value.
691      * @param optionsService The optionsService to set.
692      */
693     public void setOptionsService(OptionsService optionsService) {
694         this.optionsService = optionsService;
695     }
696 
697     /**
698      * Gets the subFundGroupService attribute. 
699      * @return Returns the subFundGroupService.
700      */
701     public SubFundGroupService getSubFundGroupService() {
702         return subFundGroupService;
703     }
704 
705     /**
706      * Sets the subFundGroupService attribute value.
707      * @param subFundGroupService The subFundGroupService to set.
708      */
709     public void setSubFundGroupService(SubFundGroupService subFundGroupService) {
710         this.subFundGroupService = subFundGroupService;
711     }
712 
713     /**
714      * Gets the businessObjectService attribute. 
715      * @return Returns the businessObjectService.
716      */
717     public BusinessObjectService getBusinessObjectService() {
718         return businessObjectService;
719     }
720 
721     /**
722      * Sets the businessObjectService attribute value.
723      * @param businessObjectService The businessObjectService to set.
724      */
725     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
726         this.businessObjectService = businessObjectService;
727     }
728 
729     /**
730      * Gets the accountingCycleCachingService attribute. 
731      * @return Returns the accountingCycleCachingService.
732      */
733     public AccountingCycleCachingService getAccountingCycleCachingService() {
734         return accountingCycleCachingService;
735     }
736 
737     /**
738      * Sets the accountingCycleCachingService attribute value.
739      * @param accountingCycleCachingService The accountingCycleCachingService to set.
740      */
741     public void setAccountingCycleCachingService(AccountingCycleCachingService accountingCycleCachingService) {
742         this.accountingCycleCachingService = accountingCycleCachingService;
743     }
744     
745 }