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