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