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.util.Date; 019 020 import org.apache.ojb.broker.metadata.MetadataManager; 021 import org.kuali.kfs.gl.GeneralLedgerConstants; 022 import org.kuali.kfs.gl.batch.service.AccountingCycleCachingService; 023 import org.kuali.kfs.gl.batch.service.PostTransaction; 024 import org.kuali.kfs.gl.businessobject.Reversal; 025 import org.kuali.kfs.gl.businessobject.SufficientFundBalances; 026 import org.kuali.kfs.gl.businessobject.Transaction; 027 import org.kuali.kfs.gl.dataaccess.SufficientFundBalancesDao; 028 import org.kuali.kfs.sys.KFSConstants; 029 import org.kuali.kfs.sys.service.ReportWriterService; 030 import org.kuali.rice.kns.service.PersistenceStructureService; 031 import org.kuali.rice.kns.util.KualiDecimal; 032 import org.kuali.rice.kns.util.ObjectUtils; 033 import org.springframework.transaction.annotation.Transactional; 034 035 /** 036 * An implementation of PostTransaction which posts a transaction to the appropriate sufficient funds record 037 */ 038 @Transactional 039 public class PostSufficientFundBalances implements PostTransaction { 040 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PostSufficientFundBalances.class); 041 042 private AccountingCycleCachingService accountingCycleCachingService; 043 private PersistenceStructureService persistenceStructureService; 044 045 /** 046 * Constructs a PostSufficientFundBalances instance 047 */ 048 public PostSufficientFundBalances() { 049 super(); 050 } 051 052 /** 053 * Posts the transaction to the appropriate sufficient funds records 054 * 055 * @param t the transaction which is being posted 056 * @param mode the mode the poster is currently running in 057 * @param postDate the date this transaction should post to 058 * @param posterReportWriterService the writer service where the poster is writing its report 059 * @return the accomplished post type 060 * @see org.kuali.kfs.gl.batch.service.PostTransaction#post(org.kuali.kfs.gl.businessobject.Transaction, int, java.util.Date) 061 */ 062 public String post(Transaction t, int mode, Date postDate, ReportWriterService posterReportWriterService) { 063 LOG.debug("post() started"); 064 065 String returnCode = GeneralLedgerConstants.UPDATE_CODE; 066 067 if (KFSConstants.SF_TYPE_NO_CHECKING.equals(t.getAccount().getAccountSufficientFundsCode())) { 068 // Don't need to post 069 return GeneralLedgerConstants.EMPTY_CODE; 070 } 071 072 // Get the Sufficient funds code 073 // Sufficient Funds Code 074 String sufficientFundsObjectCode = null; 075 if (KFSConstants.SF_TYPE_OBJECT.equals(t.getAccount().getAccountSufficientFundsCode())) { 076 sufficientFundsObjectCode = t.getFinancialObjectCode(); 077 } 078 else if (KFSConstants.SF_TYPE_LEVEL.equals(t.getAccount().getAccountSufficientFundsCode())) { 079 if (ObjectUtils.isNull(t.getFinancialObject())) { 080 return "E:Could not find sufficient funds object code for " + t.toString(); 081 } 082 sufficientFundsObjectCode = t.getFinancialObject().getFinancialObjectLevelCode(); 083 } 084 else if (KFSConstants.SF_TYPE_CONSOLIDATION.equals(t.getAccount().getAccountSufficientFundsCode())) { 085 //sufficientFundsObjectCode = t.getFinancialObject().getFinancialObjectLevel().getFinancialConsolidationObjectCode(); 086 if (ObjectUtils.isNull(t.getFinancialObject())) { 087 return "E:Could not find sufficient funds object code for " + t.toString(); 088 } 089 sufficientFundsObjectCode = accountingCycleCachingService.getObjectLevel(t.getFinancialObject().getChartOfAccountsCode(), t.getFinancialObject().getFinancialObjectLevelCode()).getFinancialConsolidationObjectCode(); 090 } 091 else if (KFSConstants.SF_TYPE_CASH_AT_ACCOUNT.equals(t.getAccount().getAccountSufficientFundsCode()) || KFSConstants.SF_TYPE_ACCOUNT.equals(t.getAccount().getAccountSufficientFundsCode())) { 092 sufficientFundsObjectCode = GeneralLedgerConstants.getSpaceFinancialObjectCode(); 093 } 094 else { 095 return "E:Invalid sufficient funds code (" + t.getAccount().getAccountSufficientFundsCode() + ")"; 096 } 097 098 // Look to see if there is a sufficient funds record for this 099 SufficientFundBalances sfBalance = accountingCycleCachingService.getSufficientFundBalances(t.getUniversityFiscalYear(), t.getChartOfAccountsCode(), t.getAccountNumber(), sufficientFundsObjectCode); 100 if (sfBalance == null) { 101 returnCode = GeneralLedgerConstants.INSERT_CODE; 102 sfBalance = new SufficientFundBalances(); 103 sfBalance.setUniversityFiscalYear(t.getUniversityFiscalYear()); 104 sfBalance.setChartOfAccountsCode(t.getChartOfAccountsCode()); 105 sfBalance.setAccountNumber(t.getAccountNumber()); 106 sfBalance.setFinancialObjectCode(sufficientFundsObjectCode); 107 sfBalance.setAccountActualExpenditureAmt(KualiDecimal.ZERO); 108 sfBalance.setAccountEncumbranceAmount(KualiDecimal.ZERO); 109 sfBalance.setCurrentBudgetBalanceAmount(KualiDecimal.ZERO); 110 sfBalance.setAccountSufficientFundsCode(t.getAccount().getAccountSufficientFundsCode()); 111 } 112 113 if (KFSConstants.SF_TYPE_CASH_AT_ACCOUNT.equals(t.getAccount().getAccountSufficientFundsCode())) { 114 // 2640-PROCESS-CASH 115 if (t.getFinancialBalanceTypeCode().equals(t.getOption().getActualFinancialBalanceTypeCd())) { 116 if (t.getFinancialObjectCode().equals(t.getChart().getFinancialCashObjectCode()) || t.getFinancialObjectCode().equals(t.getChart().getFinAccountsPayableObjectCode())) { 117 // 2641-PROCESS-CASH-ACTUAL 118 updateBudgetAmount(t.getTransactionDebitCreditCode(), sfBalance, t.getTransactionLedgerEntryAmount()); 119 } 120 else { 121 // No need to post this 122 return GeneralLedgerConstants.EMPTY_CODE; 123 } 124 } 125 else if (t.getFinancialBalanceTypeCode().equals(t.getOption().getExtrnlEncumFinBalanceTypCd()) || t.getFinancialBalanceTypeCode().equals(t.getOption().getIntrnlEncumFinBalanceTypCd()) || t.getFinancialBalanceTypeCode().equals(t.getOption().getPreencumbranceFinBalTypeCd()) || t.getOption().getCostShareEncumbranceBalanceTypeCd().equals(t.getFinancialBalanceTypeCode())) { 126 if (t.getFinancialObjectTypeCode().equals(t.getOption().getFinObjTypeExpenditureexpCd()) || t.getFinancialObjectTypeCode().equals(t.getOption().getFinObjTypeExpendNotExpCode()) || t.getOption().getFinancialObjectTypeTransferExpenseCd().equals(t.getFinancialObjectTypeCode()) || t.getOption().getFinObjTypeExpNotExpendCode().equals(t.getFinancialObjectTypeCode())) { 127 // 2462-PROCESS-CASH-ENCUMBRANCE 128 updateEncumbranceAmount(t.getTransactionDebitCreditCode(), sfBalance, t.getTransactionLedgerEntryAmount()); 129 } 130 else { 131 // No need to post this 132 return GeneralLedgerConstants.EMPTY_CODE; 133 } 134 } 135 else { 136 // No need to post this 137 return GeneralLedgerConstants.EMPTY_CODE; 138 } 139 } 140 else { 141 // 2630-PROCESS-OBJECT-OR-ACCOUNT 142 if (t.getFinancialObjectTypeCode().equals(t.getOption().getFinObjTypeExpenditureexpCd()) || t.getFinancialObjectTypeCode().equals(t.getOption().getFinObjTypeExpendNotExpCode()) || t.getOption().getFinancialObjectTypeTransferExpenseCd().equals(t.getFinancialObjectTypeCode()) || t.getOption().getFinObjTypeExpNotExpendCode().equals(t.getFinancialObjectTypeCode())) { 143 if (t.getFinancialBalanceTypeCode().equals(t.getOption().getActualFinancialBalanceTypeCd())) { 144 // 2631-PROCESS-OBJTACCT-ACTUAL 145 updateExpendedAmount(t.getTransactionDebitCreditCode(), sfBalance, t.getTransactionLedgerEntryAmount()); 146 } 147 else if (t.getFinancialBalanceTypeCode().equals(t.getOption().getExtrnlEncumFinBalanceTypCd()) || t.getFinancialBalanceTypeCode().equals(t.getOption().getIntrnlEncumFinBalanceTypCd()) || t.getFinancialBalanceTypeCode().equals(t.getOption().getPreencumbranceFinBalTypeCd()) || t.getFinancialBalanceTypeCode().equals(t.getOption().getCostShareEncumbranceBalanceTypeCd())) { 148 // 2632-PROCESS-OBJTACCT-ENCMBRNC 149 updateEncumbranceAmount(t.getTransactionDebitCreditCode(), sfBalance, t.getTransactionLedgerEntryAmount()); 150 } 151 else if (t.getFinancialBalanceTypeCode().equals(t.getOption().getBudgetCheckingBalanceTypeCd())) { 152 sfBalance.setCurrentBudgetBalanceAmount(sfBalance.getCurrentBudgetBalanceAmount().add(t.getTransactionLedgerEntryAmount())); 153 } 154 else { 155 // No need to post this 156 return GeneralLedgerConstants.EMPTY_CODE; 157 } 158 } 159 else { 160 // No need to post this 161 return GeneralLedgerConstants.EMPTY_CODE; 162 } 163 } 164 165 // If we get here, we need to save the balance entry 166 if (returnCode.equals(GeneralLedgerConstants.INSERT_CODE)) { 167 accountingCycleCachingService.insertSufficientFundBalances(sfBalance); 168 } else { 169 accountingCycleCachingService.updateSufficientFundBalances(sfBalance); 170 } 171 172 173 return returnCode; 174 } 175 176 /** 177 * Updates the expenditure amount of a given sufficient funds balance record 178 * 179 * @param debitCreditCode whether the the amount should be debited or credited to the SF balance 180 * @param bal a sufficient funds balance to update 181 * @param amount the amount to debit or credit 182 */ 183 protected void updateExpendedAmount(String debitCreditCode, SufficientFundBalances bal, KualiDecimal amount) { 184 if (KFSConstants.GL_CREDIT_CODE.equals(debitCreditCode)) { 185 bal.setAccountActualExpenditureAmt(bal.getAccountActualExpenditureAmt().subtract(amount)); 186 } 187 else if (KFSConstants.GL_DEBIT_CODE.equals(debitCreditCode) || KFSConstants.GL_BUDGET_CODE.equals(debitCreditCode)) { 188 bal.setAccountActualExpenditureAmt(bal.getAccountActualExpenditureAmt().add(amount)); 189 } 190 } 191 192 /** 193 * Updates the encumbrance amount of a given sufficient funds balance record 194 * 195 * @param debitCreditCode whether the the amount should be debited or credited to the SF balance 196 * @param bal a sufficient funds balance to update 197 * @param amount the amount to debit or credit 198 */ 199 protected void updateEncumbranceAmount(String debitCreditCode, SufficientFundBalances bal, KualiDecimal amount) { 200 if (KFSConstants.GL_CREDIT_CODE.equals(debitCreditCode)) { 201 bal.setAccountEncumbranceAmount(bal.getAccountEncumbranceAmount().subtract(amount)); 202 } 203 else if (KFSConstants.GL_DEBIT_CODE.equals(debitCreditCode) || KFSConstants.GL_BUDGET_CODE.equals(debitCreditCode)) { 204 bal.setAccountEncumbranceAmount(bal.getAccountEncumbranceAmount().add(amount)); 205 } 206 } 207 208 /** 209 * Updates the budget amount of a given sufficient funds balance record 210 * 211 * @param debitCreditCode whether the the amount should be debited or credited to the SF balance 212 * @param bal a sufficient funds balance to update 213 * @param amount the amount to debit or credit 214 */ 215 protected void updateBudgetAmount(String debitCreditCode, SufficientFundBalances bal, KualiDecimal amount) { 216 if (KFSConstants.GL_CREDIT_CODE.equals(debitCreditCode)) { 217 bal.setCurrentBudgetBalanceAmount(bal.getCurrentBudgetBalanceAmount().subtract(amount)); 218 } 219 else if (KFSConstants.GL_DEBIT_CODE.equals(debitCreditCode) || KFSConstants.GL_BUDGET_CODE.equals(debitCreditCode)) { 220 bal.setCurrentBudgetBalanceAmount(bal.getCurrentBudgetBalanceAmount().add(amount)); 221 } 222 } 223 224 /** 225 * @see org.kuali.kfs.gl.batch.service.PostTransaction#getDestinationName() 226 */ 227 public String getDestinationName() { 228 return persistenceStructureService.getTableName(SufficientFundBalances.class); 229 } 230 231 public void setAccountingCycleCachingService(AccountingCycleCachingService accountingCycleCachingService) { 232 this.accountingCycleCachingService = accountingCycleCachingService; 233 } 234 235 public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) { 236 this.persistenceStructureService = persistenceStructureService; 237 } 238 }