/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.ld.batch.service.impl; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.coa.businessobject.Account; import org.kuali.kfs.coa.businessobject.AccountingPeriod; import org.kuali.kfs.coa.businessobject.SubAccount; import org.kuali.kfs.coa.service.AccountService; import org.kuali.kfs.coa.service.BalanceTypeService; import org.kuali.kfs.gl.batch.ScrubberStep; import org.kuali.kfs.gl.batch.service.AccountingCycleCachingService; import org.kuali.kfs.gl.businessobject.OriginEntryFull; import org.kuali.kfs.gl.businessobject.OriginEntryInformation; import org.kuali.kfs.gl.service.ScrubberValidator; import org.kuali.kfs.module.ld.LaborConstants; import org.kuali.kfs.module.ld.LaborKeyConstants; import org.kuali.kfs.module.ld.batch.LaborScrubberStep; import org.kuali.kfs.module.ld.batch.service.LaborAccountingCycleCachingService; import org.kuali.kfs.module.ld.businessobject.LaborObject; import org.kuali.kfs.module.ld.businessobject.LaborOriginEntry; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.Message; import org.kuali.kfs.sys.MessageBuilder; import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry; import org.kuali.kfs.sys.businessobject.SystemOptions; import org.kuali.kfs.sys.businessobject.UniversityDate; import org.kuali.kfs.sys.service.OptionsService; import org.kuali.kfs.sys.service.impl.KfsParameterConstants; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.service.PersistenceService; import org.kuali.rice.krad.service.PersistenceStructureService; import org.kuali.rice.krad.util.ObjectUtils; /** * Service implementation of ScrubberValidator. */ public class ScrubberValidatorImpl implements ScrubberValidator { private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ScrubberValidatorImpl.class); private ConfigurationService kualiConfigurationService; private BusinessObjectService businessObjectService; private ParameterService parameterService; private AccountService accountService; private BalanceTypeService balanceTypService; private OptionsService optionsService; private PersistenceService persistenceService; private ScrubberValidator scrubberValidator; private PersistenceStructureService persistenceStructureService; private boolean continuationAccountIndicator; /** * @see org.kuali.module.labor.service.LaborScrubberValidator#validateTransaction(owrg.kuali.module.labor.bo.LaborOriginEntry, * org.kuali.kfs.module.ld.businessobject.LaborOriginEntry, org.kuali.kfs.gl.businessobject.UniversityDate) */ public List<Message> validateTransaction(OriginEntryInformation originEntry, OriginEntryInformation scrubbedEntry, UniversityDate universityRunDate, boolean laborIndicator, AccountingCycleCachingService laborAccountingCycleCachingService) { LOG.debug("validateTransaction() started"); List<Message> errors = new ArrayList<Message>(); continuationAccountIndicator = false; LaborOriginEntry laborOriginEntry = (LaborOriginEntry) originEntry; LaborOriginEntry laborScrubbedEntry = (LaborOriginEntry) scrubbedEntry; // gl scrubber validation errors = scrubberValidator.validateTransaction(laborOriginEntry, laborScrubbedEntry, universityRunDate, laborIndicator, laborAccountingCycleCachingService); refreshOriginEntryReferences(laborOriginEntry); refreshOriginEntryReferences(laborScrubbedEntry); if (StringUtils.isBlank(laborOriginEntry.getEmplid())) { laborScrubbedEntry.setEmplid(LaborConstants.getDashEmplId()); } if (StringUtils.isBlank(laborOriginEntry.getPositionNumber())) { laborScrubbedEntry.setPositionNumber(LaborConstants.getDashPositionNumber()); } Message err = null; //this validation is duplicated. This is in ScrubberValidatorImpl under GL // err = this.validateClosedPeriodCode(laborOriginEntry, laborScrubbedEntry); // if (err != null) { // errors.add(err); // } err = validatePayrollEndFiscalYear(laborOriginEntry, laborScrubbedEntry, universityRunDate, (LaborAccountingCycleCachingService) laborAccountingCycleCachingService); if (err != null) { errors.add(err); } err = validatePayrollEndFiscalPeriodCode(laborOriginEntry, laborScrubbedEntry, universityRunDate, (LaborAccountingCycleCachingService) laborAccountingCycleCachingService); if (err != null) { errors.add(err); } err = validateAccount(laborOriginEntry, laborScrubbedEntry, universityRunDate, (LaborAccountingCycleCachingService) laborAccountingCycleCachingService); if (err != null) { errors.add(err); } err = validateSubAccount(laborOriginEntry, laborScrubbedEntry, (LaborAccountingCycleCachingService) laborAccountingCycleCachingService); if (err != null) { errors.add(err); } return errors; } /** * This method is for refreshing References of Origin Entry */ protected void refreshOriginEntryReferences(OriginEntryFull originEntry) { Map<String, Class> referenceClasses = persistenceStructureService.listReferenceObjectFields(originEntry.getClass()); for (String reference : referenceClasses.keySet()) { if (KFSPropertyConstants.PROJECT.equals(reference)) { if (KFSConstants.getDashProjectCode().equals(originEntry.getProjectCode())) { originEntry.setProject(null); } else { persistenceService.retrieveReferenceObject(originEntry, reference); } } else if (KFSPropertyConstants.FINANCIAL_SUB_OBJECT.equals(reference)) { if (KFSConstants.getDashFinancialSubObjectCode().equals(originEntry.getFinancialSubObjectCode())) { originEntry.setFinancialSubObject(null); } else { persistenceService.retrieveReferenceObject(originEntry, reference); } } else if (KFSPropertyConstants.SUB_ACCOUNT.equals(reference)) { if (KFSConstants.getDashSubAccountNumber().equals(originEntry.getSubAccountNumber())) { originEntry.setSubAccount(null); } else { persistenceService.retrieveReferenceObject(originEntry, reference); } } else { persistenceService.retrieveReferenceObject(originEntry, reference); } } } /** * Validates the closed period code of the origin entry. Scrubber accepts closed fiscal periods for the specified balance type. * * @param originEntry the origin entry being scrubbed * @param workingEntry the scrubbed version of the origin entry * @return a Message if an error was encountered, otherwise null */ //this validation is duplicated. This is in ScrubberValidatorImpl under GL // protected Message validateClosedPeriodCode(LaborOriginEntry laborOriginEntry, LaborOriginEntry laborWorkingEntry) { // LOG.debug("validateClosedPeriodCode() started"); // // String periodCode = laborOriginEntry.getUniversityFiscalPeriodCode(); // if (StringUtils.isBlank(periodCode)) { // return null; // } // // // Scrubber accepts closed fiscal periods for A21 Balance // AccountingPeriod accountingPeriod = referenceLookup.get().getAccountingPeriod(laborOriginEntry); // if (ObjectUtils.isNotNull(accountingPeriod) && !accountingPeriod.isActive()) { // String bypassBalanceType = parameterService.getParameterValueAsString(LaborScrubberStep.class, LaborConstants.Scrubber.CLOSED_FISCAL_PERIOD_BYPASS_BALANCE_TYPES); // // if (!laborWorkingEntry.getFinancialBalanceTypeCode().equals(bypassBalanceType)) { // return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_FISCAL_PERIOD_CLOSED, periodCode, Message.TYPE_FATAL); // } // // laborWorkingEntry.setUniversityFiscalPeriodCode(periodCode); // } // // return null; // } /** * This method is for validation of payrollEndFiscalYear */ protected Message validatePayrollEndFiscalYear(LaborOriginEntry laborOriginEntry, LaborOriginEntry laborWorkingEntry, UniversityDate universityRunDate, LaborAccountingCycleCachingService laborAccountingCycleCachingService) { LOG.debug("validatePayrollEndFiscalYear() started"); SystemOptions scrubbedEntryOption = null; if (laborOriginEntry.getPayrollEndDateFiscalYear() != null){ scrubbedEntryOption = laborAccountingCycleCachingService.getSystemOptions(laborOriginEntry.getPayrollEndDateFiscalYear()); if (scrubbedEntryOption == null) { return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_PAYROLL_END_DATE_FISCAL_YEAR, "" + laborOriginEntry.getPayrollEndDateFiscalYear(), Message.TYPE_FATAL); } } return null; } /** * This method is for validation of PayrollEndFiscalPeriodCode */ protected Message validatePayrollEndFiscalPeriodCode(LaborOriginEntry laborOriginEntry, LaborOriginEntry laborWorkingEntry, UniversityDate universityRunDate, LaborAccountingCycleCachingService laborAccountingCycleCachingService) { LOG.debug("validateUniversityFiscalPeriodCode() started"); AccountingPeriod accountingPeriod = null; Integer tempPayrollFiscalYear = 0; if (laborOriginEntry.getPayrollEndDateFiscalYear()== null ){ tempPayrollFiscalYear = universityRunDate.getUniversityFiscalYear(); } else { tempPayrollFiscalYear = laborOriginEntry.getPayrollEndDateFiscalYear(); } if (!laborOriginEntry.getPayrollEndDateFiscalPeriodCode().equals("") ){ accountingPeriod = laborAccountingCycleCachingService.getAccountingPeriod(tempPayrollFiscalYear, laborOriginEntry.getPayrollEndDateFiscalPeriodCode()); if (accountingPeriod == null) { return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_PAYROLL_END_DATE_FISCAL_PERIOD, laborOriginEntry.getPayrollEndDateFiscalPeriodCode(), Message.TYPE_FATAL); } } return null; } /** * Performs Account Validation. */ protected Message validateAccount(LaborOriginEntry laborOriginEntry, LaborOriginEntry laborWorkingEntry, UniversityDate universityRunDate, LaborAccountingCycleCachingService laborAccountingCycleCachingService) { LOG.debug("validateAccount() started"); Account account = laborOriginEntry.getAccount(); boolean suspenseAccountLogicInd = parameterService.getParameterValueAsBoolean(LaborScrubberStep.class, LaborConstants.Scrubber.SUSPENSE_ACCOUNT_LOGIC_PARAMETER); if (ObjectUtils.isNull(account)) { if (suspenseAccountLogicInd) { return useSuspenseAccount(laborWorkingEntry); } return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_ACCOUNT_NOT_FOUND, laborOriginEntry.getChartOfAccountsCode() + "-" + laborOriginEntry.getAccountNumber(), Message.TYPE_FATAL); } // default laborWorkingEntry.setAccount(account); laborWorkingEntry.setChartOfAccountsCode(account.getChartOfAccountsCode()); laborWorkingEntry.setAccountNumber(account.getAccountNumber()); // no further validation for gl annual doc type String glAnnualClosingType = parameterService.getParameterValueAsString(KfsParameterConstants.GENERAL_LEDGER_BATCH.class, KFSConstants.SystemGroupParameterNames.GL_ANNUAL_CLOSING_DOC_TYPE); if (glAnnualClosingType.equals(laborOriginEntry.getFinancialDocumentTypeCode())) { return null; } // Sub-Fund Wage Exclusion String orginationCode = laborOriginEntry.getFinancialSystemOriginationCode(); List<String> nonWageSubfundBypassOriginationCodes = new ArrayList<String>( parameterService.getParameterValuesAsString(LaborScrubberStep.class, LaborConstants.Scrubber.NON_WAGE_SUB_FUND_BYPASS_ORIGINATIONS) ); boolean subfundWageExclusionInd = parameterService.getParameterValueAsBoolean(LaborScrubberStep.class, LaborConstants.Scrubber.SUBFUND_WAGE_EXCLUSION_PARAMETER); if (subfundWageExclusionInd && !account.getSubFundGroup().isSubFundGroupWagesIndicator() && !nonWageSubfundBypassOriginationCodes.contains(orginationCode)) { if (suspenseAccountLogicInd) { return useSuspenseAccount(laborWorkingEntry); } return MessageBuilder.buildMessage(LaborKeyConstants.ERROR_SUN_FUND_NOT_ACCEPT_WAGES, Message.TYPE_FATAL); } // Account Fringe Validation List<String> nonFringeAccountBypassOriginationCodes = new ArrayList<String>( parameterService.getParameterValuesAsString(LaborScrubberStep.class, LaborConstants.Scrubber.NON_FRINGE_ACCOUNT_BYPASS_ORIGINATIONS) ); boolean accountFringeExclusionInd = parameterService.getParameterValueAsBoolean(LaborScrubberStep.class, LaborConstants.Scrubber.ACCOUNT_FRINGE_EXCLUSION_PARAMETER); if (accountFringeExclusionInd && !nonFringeAccountBypassOriginationCodes.contains(orginationCode)) { return checkAccountFringeIndicator(laborOriginEntry, laborWorkingEntry, account, universityRunDate, laborAccountingCycleCachingService); } // Expired/Closed Validation return handleExpiredClosedAccount(laborOriginEntry.getAccount(), laborOriginEntry, laborWorkingEntry, universityRunDate); } /** * Checks the continuation account system indicator. If on checks whether the account is expired or closed, and if so calls the * contination logic. */ protected Message handleExpiredClosedAccount(Account account, LaborOriginEntry laborOriginEntry, LaborOriginEntry laborWorkingEntry, UniversityDate universityRunDate) { List<String> continuationAccountBypassBalanceTypeCodes = balanceTypService.getContinuationAccountBypassBalanceTypeCodes(universityRunDate.getUniversityFiscalYear()); List<String> continuationAccountBypassOriginationCodes = new ArrayList<String>( parameterService.getParameterValuesAsString(LaborScrubberStep.class, LaborConstants.Scrubber.CONTINUATION_ACCOUNT_BYPASS_ORIGINATION_CODES) ); List<String> continuationAccountBypassDocumentTypeCodes = new ArrayList<String>( parameterService.getParameterValuesAsString(LaborScrubberStep.class, LaborConstants.Scrubber.CONTINUATION_ACCOUNT_BYPASS_DOCUMENT_TYPE_CODES) ); Calendar today = Calendar.getInstance(); today.setTime(universityRunDate.getUniversityDate()); long offsetAccountExpirationTime = getAdjustedAccountExpirationDate(account); boolean isAccountExpiredOrClosed = (account.getAccountExpirationDate() != null && isAccountExpired(account, universityRunDate)) || !account.isActive(); boolean continuationAccountLogicInd = parameterService.getParameterValueAsBoolean(LaborScrubberStep.class, LaborConstants.Scrubber.CONTINUATION_ACCOUNT_LOGIC_PARAMETER); if (continuationAccountLogicInd && isAccountExpiredOrClosed) { // special checks for origination codes that have override ability boolean isOverrideOriginCode = continuationAccountBypassOriginationCodes.contains(laborOriginEntry.getFinancialSystemOriginationCode()); if (isOverrideOriginCode && !account.isActive()) { return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_ORIGIN_CODE_CANNOT_HAVE_CLOSED_ACCOUNT, laborOriginEntry.getChartOfAccountsCode() + "-" + laborOriginEntry.getAccountNumber(), Message.TYPE_FATAL); } boolean canBypass = isOverrideOriginCode || continuationAccountBypassBalanceTypeCodes.contains(laborOriginEntry.getFinancialBalanceTypeCode()) || continuationAccountBypassDocumentTypeCodes.contains(laborOriginEntry.getFinancialDocumentTypeCode().trim()); if (account.isActive() && canBypass) { return null; } return continuationAccountLogic(account, laborOriginEntry, laborWorkingEntry, universityRunDate); } return null; } /** * Loops through continuation accounts for 10 tries or until it finds an account that is not expired. */ protected Message continuationAccountLogic(Account expiredClosedAccount, LaborOriginEntry laborOriginEntry, LaborOriginEntry laborWorkingEntry, UniversityDate universityRunDate) { String chartCode = expiredClosedAccount.getContinuationFinChrtOfAcctCd(); String accountNumber = expiredClosedAccount.getContinuationAccountNumber(); List<String> checkedAccountNumbers = new ArrayList<String>(); for (int i = 0; i < 10; ++i) { if (checkedAccountNumbers.contains(chartCode + accountNumber)) { // Something is really wrong with the data because this account has already been evaluated. return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_CIRCULAR_DEPENDENCY_IN_CONTINUATION_ACCOUNT_LOGIC, Message.TYPE_FATAL); } checkedAccountNumbers.add(chartCode + accountNumber); if (chartCode == null || accountNumber == null) { return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_CONTINUATION_ACCOUNT_NOT_FOUND, Message.TYPE_FATAL); } // Lookup the account Account account = accountService.getByPrimaryId(chartCode, accountNumber); if (ObjectUtils.isNull(account)) { return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_CONTINUATION_ACCOUNT_NOT_FOUND, Message.TYPE_FATAL); } // check account expiration long offsetAccountExpirationTime = getAdjustedAccountExpirationDate(account); if (ObjectUtils.isNotNull(account.getAccountExpirationDate()) && isAccountExpired(account, universityRunDate)) { chartCode = account.getContinuationFinChrtOfAcctCd(); accountNumber = account.getContinuationAccountNumber(); } else { // set continuationAccountLogicIndi continuationAccountIndicator = true; laborWorkingEntry.setAccount(account); laborWorkingEntry.setAccountNumber(accountNumber); laborWorkingEntry.setChartOfAccountsCode(chartCode); laborWorkingEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); laborWorkingEntry.setTransactionLedgerEntryDescription(kualiConfigurationService.getPropertyValueAsString(KFSKeyConstants.MSG_AUTO_FORWARD) + " " + expiredClosedAccount.getChartOfAccountsCode() + expiredClosedAccount.getAccountNumber() + laborOriginEntry.getTransactionLedgerEntryDescription()); return MessageBuilder.buildMessage(KFSKeyConstants.MSG_ACCOUNT_CLOSED_TO, laborWorkingEntry.getChartOfAccountsCode() + "-" + laborWorkingEntry.getAccountNumber(), Message.TYPE_WARNING); } } // We failed to find a valid continuation account. boolean suspenseAccountLogicInd = parameterService.getParameterValueAsBoolean(LaborScrubberStep.class, LaborConstants.Scrubber.SUSPENSE_ACCOUNT_LOGIC_PARAMETER); if (suspenseAccountLogicInd) { return useSuspenseAccount(laborWorkingEntry); } else { return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_CONTINUATION_ACCOUNT_LIMIT_REACHED, Message.TYPE_FATAL); } } /** * For fringe transaction types checks if the account accepts fringe benefits. If not, retrieves the alternative account, then * calls expiration checking on either the alternative account or the account passed in. */ protected Message checkAccountFringeIndicator(LaborOriginEntry laborOriginEntry, LaborOriginEntry laborWorkingEntry, Account account, UniversityDate universityRunDate, LaborAccountingCycleCachingService laborAccountingCycleCachingService) { // check for fringe tranaction type //LaborObject laborObject = (LaborObject) businessObjectService.findByPrimaryKey(LaborObject.class, fieldValues); LaborObject laborObject = laborAccountingCycleCachingService.getLaborObject(laborOriginEntry.getUniversityFiscalYear(), laborOriginEntry.getChartOfAccountsCode(), laborOriginEntry.getFinancialObjectCode()); boolean isFringeTransaction = laborObject != null && org.apache.commons.lang.StringUtils.equals(LaborConstants.BenefitExpenseTransfer.LABOR_LEDGER_BENEFIT_CODE, laborObject.getFinancialObjectFringeOrSalaryCode()); // alternative account handling for non fringe accounts if (isFringeTransaction && !account.isAccountsFringesBnftIndicator()) { Account altAccount = accountService.getByPrimaryId(laborOriginEntry.getAccount().getReportsToChartOfAccountsCode(), laborOriginEntry.getAccount().getReportsToAccountNumber()); if (ObjectUtils.isNotNull(altAccount)) { laborWorkingEntry.setAccount(altAccount); laborWorkingEntry.setAccountNumber(altAccount.getAccountNumber()); laborWorkingEntry.setChartOfAccountsCode(altAccount.getChartOfAccountsCode()); Message err = handleExpiredClosedAccount(altAccount, laborOriginEntry, laborWorkingEntry, universityRunDate); if (err == null) { err = MessageBuilder.buildMessageWithPlaceHolder(LaborKeyConstants.MESSAGE_FRINGES_MOVED_TO, Message.TYPE_WARNING, new Object[] { altAccount.getAccountNumber() } ); } return err; } // no alt acct, use suspense acct if active boolean suspenseAccountLogicInd = parameterService.getParameterValueAsBoolean(LaborScrubberStep.class, LaborConstants.Scrubber.SUSPENSE_ACCOUNT_LOGIC_PARAMETER); if (suspenseAccountLogicInd) { return useSuspenseAccount(laborWorkingEntry); } return MessageBuilder.buildMessage(LaborKeyConstants.ERROR_NON_FRINGE_ACCOUNT_ALTERNATIVE_NOT_FOUND, Message.TYPE_FATAL); } return handleExpiredClosedAccount(account, laborOriginEntry, laborWorkingEntry, universityRunDate); } /** * Adjustment of Account if it is contracts and grants */ protected long getAdjustedAccountExpirationDate(Account account) { long offsetAccountExpirationTime = 0; if (account.getAccountExpirationDate() != null) { offsetAccountExpirationTime = account.getAccountExpirationDate().getTime(); if (account.isForContractsAndGrants() && account.isActive()) { String daysOffset = parameterService.getParameterValueAsString(ScrubberStep.class, KFSConstants.SystemGroupParameterNames.GL_SCRUBBER_VALIDATION_DAYS_OFFSET); int daysOffsetInt = 0; // default to 0 if (!org.apache.commons.lang.StringUtils.isBlank(daysOffset)) { daysOffsetInt = new Integer(daysOffset).intValue(); } Calendar tempCal = Calendar.getInstance(); tempCal.setTimeInMillis(offsetAccountExpirationTime); tempCal.add(Calendar.DAY_OF_MONTH, daysOffsetInt); offsetAccountExpirationTime = tempCal.getTimeInMillis(); } } return offsetAccountExpirationTime; } /** * This method changes account to suspenseAccount */ protected Message useSuspenseAccount(LaborOriginEntry workingEntry) { String suspenseAccountNumber = parameterService.getParameterValueAsString(LaborScrubberStep.class, LaborConstants.Scrubber.SUSPENSE_ACCOUNT); String suspenseCOAcode = parameterService.getParameterValueAsString(LaborScrubberStep.class, LaborConstants.Scrubber.SUSPENSE_CHART); String suspenseSubAccountNumber = parameterService.getParameterValueAsString(LaborScrubberStep.class, LaborConstants.Scrubber.SUSPENSE_SUB_ACCOUNT); Account account = accountService.getByPrimaryId(suspenseCOAcode, suspenseAccountNumber); if (ObjectUtils.isNull(account)) { return MessageBuilder.buildMessage(LaborKeyConstants.ERROR_INVALID_SUSPENSE_ACCOUNT, Message.TYPE_FATAL); } workingEntry.setAccount(account); workingEntry.setAccountNumber(suspenseAccountNumber); workingEntry.setChartOfAccountsCode(suspenseCOAcode); workingEntry.setSubAccountNumber(suspenseSubAccountNumber); return MessageBuilder.buildMessageWithPlaceHolder(LaborKeyConstants.MESSAGE_SUSPENSE_ACCOUNT_APPLIED, Message.TYPE_WARNING, new Object[] { suspenseCOAcode, suspenseAccountNumber, suspenseSubAccountNumber } ); } /** * Validates the sub account of the origin entry * * @param originEntry the origin entry being scrubbed * @param workingEntry the scrubbed version of the origin entry * @return a Message if an error was encountered, otherwise null */ protected Message validateSubAccount(LaborOriginEntry originEntry, LaborOriginEntry workingEntry, LaborAccountingCycleCachingService laborAccountingCycleCachingService) { LOG.debug("validateSubAccount() started"); // when continuationAccount used, the subAccountNumber should be changed to dashes and skip validation subAccount process if (continuationAccountIndicator) { workingEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); return null; } // If the sub account number is empty, set it to dashes. // Otherwise set the workingEntry sub account number to the // sub account number of the input origin entry. if (org.springframework.util.StringUtils.hasText(originEntry.getSubAccountNumber())) { // sub account IS specified if (!KFSConstants.getDashSubAccountNumber().equals(originEntry.getSubAccountNumber())) { SubAccount originEntrySubAccount = laborAccountingCycleCachingService.getSubAccount(originEntry.getChartOfAccountsCode(), originEntry.getAccountNumber(), originEntry.getSubAccountNumber()); //SubAccount originEntrySubAccount = getSubAccount(originEntry); if (originEntrySubAccount == null) { // sub account is not valid return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_SUB_ACCOUNT_NOT_FOUND, originEntry.getChartOfAccountsCode() + "-" + originEntry.getAccountNumber() + "-" + originEntry.getSubAccountNumber(), Message.TYPE_FATAL); } else { // sub account IS valid if (originEntrySubAccount.isActive()) { // sub account IS active workingEntry.setSubAccountNumber(originEntry.getSubAccountNumber()); } else { // sub account IS NOT active if (parameterService.getParameterValueAsString(KfsParameterConstants.GENERAL_LEDGER_BATCH.class, KFSConstants.SystemGroupParameterNames.GL_ANNUAL_CLOSING_DOC_TYPE).equals(originEntry.getFinancialDocumentTypeCode())) { // document IS annual closing workingEntry.setSubAccountNumber(originEntry.getSubAccountNumber()); } else { // document is NOT annual closing return MessageBuilder.buildMessage(KFSKeyConstants.ERROR_SUB_ACCOUNT_NOT_ACTIVE, originEntry.getChartOfAccountsCode() + "-" + originEntry.getAccountNumber() + "-" + originEntry.getSubAccountNumber(), Message.TYPE_FATAL); } } } } else { // the sub account is dashes workingEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); } } else { // No sub account is specified. workingEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); } return null; } /** * @see org.kuali.kfs.gl.service.ScrubberValidator#isAccountExpired(org.kuali.kfs.coa.businessobject.Account, org.kuali.kfs.sys.businessobject.UniversityDate) */ public boolean isAccountExpired(Account account, UniversityDate universityRunDate) { return scrubberValidator.isAccountExpired(account, universityRunDate); } public void validateForInquiry(GeneralLedgerPendingEntry entry) { } /** * Sets the parameterService attribute value. * * @param parameterService The parameterService to set. */ public void setParameterService(ParameterService parameterService) { this.parameterService = parameterService; } /** * Sets the kualiConfigurationService attribute value. * * @param service The kualiConfigurationService to set. */ public void setConfigurationService(ConfigurationService service) { kualiConfigurationService = service; } /** * Sets the accountService attribute value. * * @param as The accountService to set. */ public void setAccountService(AccountService as) { accountService = as; } /** * Sets the persistenceService attribute value. * * @param ps The persistenceService to set. */ public void setPersistenceService(PersistenceService ps) { persistenceService = ps; } /** * Sets the businessObjectService attribute value. * * @param businessObjectService The businessObjectService to set. */ public void setBusinessObjectService(BusinessObjectService businessObjectService) { this.businessObjectService = businessObjectService; } /** * Sets the balanceTypService attribute value. * * @param balanceTypService The balanceTypService to set. */ public void setBalanceTypService(BalanceTypeService balanceTypService) { this.balanceTypService = balanceTypService; } /** * Sets the scrubberValidator attribute value. * * @param sv The scrubberValidator to set. */ public void setScrubberValidator(ScrubberValidator sv) { scrubberValidator = sv; } /** * Sets the persistenceStructureService attribute value. * * @param persistenceStructureService The persistenceStructureService to set. */ public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) { this.persistenceStructureService = persistenceStructureService; } /** * Sets the optionsService attribute value. * * @param optionsService The optionsService to set. */ public void setOptionsService(OptionsService optionsService) { this.optionsService = optionsService; } }