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