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 }