/*
* 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.gl.batch.service.impl;
import java.util.Date;
import org.kuali.kfs.gl.GeneralLedgerConstants;
import org.kuali.kfs.gl.batch.service.AccountingCycleCachingService;
import org.kuali.kfs.gl.batch.service.PostTransaction;
import org.kuali.kfs.gl.businessobject.SufficientFundBalances;
import org.kuali.kfs.gl.businessobject.Transaction;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.service.ReportWriterService;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.krad.service.PersistenceStructureService;
import org.kuali.rice.krad.util.ObjectUtils;
import org.springframework.transaction.annotation.Transactional;
/**
* An implementation of PostTransaction which posts a transaction to the appropriate sufficient funds record
*/
@Transactional
public class PostSufficientFundBalances implements PostTransaction {
private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PostSufficientFundBalances.class);
private AccountingCycleCachingService accountingCycleCachingService;
private PersistenceStructureService persistenceStructureService;
/**
* Constructs a PostSufficientFundBalances instance
*/
public PostSufficientFundBalances() {
super();
}
/**
* Posts the transaction to the appropriate sufficient funds records
*
* @param t the transaction which is being posted
* @param mode the mode the poster is currently running in
* @param postDate the date this transaction should post to
* @param posterReportWriterService the writer service where the poster is writing its report
* @return the accomplished post type
* @see org.kuali.kfs.gl.batch.service.PostTransaction#post(org.kuali.kfs.gl.businessobject.Transaction, int, java.util.Date)
*/
public String post(Transaction t, int mode, Date postDate, ReportWriterService posterReportWriterService) {
LOG.debug("post() started");
String returnCode = GeneralLedgerConstants.UPDATE_CODE;
if (KFSConstants.SF_TYPE_NO_CHECKING.equals(t.getAccount().getAccountSufficientFundsCode())) {
// Don't need to post
return GeneralLedgerConstants.EMPTY_CODE;
}
// Get the Sufficient funds code
// Sufficient Funds Code
String sufficientFundsObjectCode = null;
if (KFSConstants.SF_TYPE_OBJECT.equals(t.getAccount().getAccountSufficientFundsCode())) {
sufficientFundsObjectCode = t.getFinancialObjectCode();
}
else if (KFSConstants.SF_TYPE_LEVEL.equals(t.getAccount().getAccountSufficientFundsCode())) {
if (ObjectUtils.isNull(t.getFinancialObject())) {
return "E:Could not find sufficient funds object code for " + t.toString();
}
sufficientFundsObjectCode = t.getFinancialObject().getFinancialObjectLevelCode();
}
else if (KFSConstants.SF_TYPE_CONSOLIDATION.equals(t.getAccount().getAccountSufficientFundsCode())) {
//sufficientFundsObjectCode = t.getFinancialObject().getFinancialObjectLevel().getFinancialConsolidationObjectCode();
if (ObjectUtils.isNull(t.getFinancialObject())) {
return "E:Could not find sufficient funds object code for " + t.toString();
}
sufficientFundsObjectCode = accountingCycleCachingService.getObjectLevel(t.getFinancialObject().getChartOfAccountsCode(), t.getFinancialObject().getFinancialObjectLevelCode()).getFinancialConsolidationObjectCode();
}
else if (KFSConstants.SF_TYPE_CASH_AT_ACCOUNT.equals(t.getAccount().getAccountSufficientFundsCode()) || KFSConstants.SF_TYPE_ACCOUNT.equals(t.getAccount().getAccountSufficientFundsCode())) {
sufficientFundsObjectCode = GeneralLedgerConstants.getSpaceFinancialObjectCode();
}
else {
return "E:Invalid sufficient funds code (" + t.getAccount().getAccountSufficientFundsCode() + ")";
}
// Look to see if there is a sufficient funds record for this
SufficientFundBalances sfBalance = accountingCycleCachingService.getSufficientFundBalances(t.getUniversityFiscalYear(), t.getChartOfAccountsCode(), t.getAccountNumber(), sufficientFundsObjectCode);
if (sfBalance == null) {
returnCode = GeneralLedgerConstants.INSERT_CODE;
sfBalance = new SufficientFundBalances();
sfBalance.setUniversityFiscalYear(t.getUniversityFiscalYear());
sfBalance.setChartOfAccountsCode(t.getChartOfAccountsCode());
sfBalance.setAccountNumber(t.getAccountNumber());
sfBalance.setFinancialObjectCode(sufficientFundsObjectCode);
sfBalance.setAccountActualExpenditureAmt(KualiDecimal.ZERO);
sfBalance.setAccountEncumbranceAmount(KualiDecimal.ZERO);
sfBalance.setCurrentBudgetBalanceAmount(KualiDecimal.ZERO);
sfBalance.setAccountSufficientFundsCode(t.getAccount().getAccountSufficientFundsCode());
}
if (KFSConstants.SF_TYPE_CASH_AT_ACCOUNT.equals(t.getAccount().getAccountSufficientFundsCode())) {
// 2640-PROCESS-CASH
if (t.getFinancialBalanceTypeCode().equals(t.getOption().getActualFinancialBalanceTypeCd())) {
if (t.getFinancialObjectCode().equals(t.getChart().getFinancialCashObjectCode()) || t.getFinancialObjectCode().equals(t.getChart().getFinAccountsPayableObjectCode())) {
// 2641-PROCESS-CASH-ACTUAL
updateBudgetAmount(t.getTransactionDebitCreditCode(), sfBalance, t.getTransactionLedgerEntryAmount());
}
else {
// No need to post this
return GeneralLedgerConstants.EMPTY_CODE;
}
}
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())) {
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())) {
// 2462-PROCESS-CASH-ENCUMBRANCE
updateEncumbranceAmount(t.getTransactionDebitCreditCode(), sfBalance, t.getTransactionLedgerEntryAmount());
}
else {
// No need to post this
return GeneralLedgerConstants.EMPTY_CODE;
}
}
else {
// No need to post this
return GeneralLedgerConstants.EMPTY_CODE;
}
}
else {
// 2630-PROCESS-OBJECT-OR-ACCOUNT
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())) {
if (t.getFinancialBalanceTypeCode().equals(t.getOption().getActualFinancialBalanceTypeCd())) {
// 2631-PROCESS-OBJTACCT-ACTUAL
updateExpendedAmount(t.getTransactionDebitCreditCode(), sfBalance, t.getTransactionLedgerEntryAmount());
}
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())) {
// 2632-PROCESS-OBJTACCT-ENCMBRNC
updateEncumbranceAmount(t.getTransactionDebitCreditCode(), sfBalance, t.getTransactionLedgerEntryAmount());
}
else if (t.getFinancialBalanceTypeCode().equals(t.getOption().getBudgetCheckingBalanceTypeCd())) {
sfBalance.setCurrentBudgetBalanceAmount(sfBalance.getCurrentBudgetBalanceAmount().add(t.getTransactionLedgerEntryAmount()));
}
else {
// No need to post this
return GeneralLedgerConstants.EMPTY_CODE;
}
}
else {
// No need to post this
return GeneralLedgerConstants.EMPTY_CODE;
}
}
// If we get here, we need to save the balance entry
if (returnCode.equals(GeneralLedgerConstants.INSERT_CODE)) {
accountingCycleCachingService.insertSufficientFundBalances(sfBalance);
} else {
accountingCycleCachingService.updateSufficientFundBalances(sfBalance);
}
return returnCode;
}
/**
* Updates the expenditure amount of a given sufficient funds balance record
*
* @param debitCreditCode whether the the amount should be debited or credited to the SF balance
* @param bal a sufficient funds balance to update
* @param amount the amount to debit or credit
*/
protected void updateExpendedAmount(String debitCreditCode, SufficientFundBalances bal, KualiDecimal amount) {
if (KFSConstants.GL_CREDIT_CODE.equals(debitCreditCode)) {
bal.setAccountActualExpenditureAmt(bal.getAccountActualExpenditureAmt().subtract(amount));
}
else if (KFSConstants.GL_DEBIT_CODE.equals(debitCreditCode) || KFSConstants.GL_BUDGET_CODE.equals(debitCreditCode)) {
bal.setAccountActualExpenditureAmt(bal.getAccountActualExpenditureAmt().add(amount));
}
}
/**
* Updates the encumbrance amount of a given sufficient funds balance record
*
* @param debitCreditCode whether the the amount should be debited or credited to the SF balance
* @param bal a sufficient funds balance to update
* @param amount the amount to debit or credit
*/
protected void updateEncumbranceAmount(String debitCreditCode, SufficientFundBalances bal, KualiDecimal amount) {
if (KFSConstants.GL_CREDIT_CODE.equals(debitCreditCode)) {
bal.setAccountEncumbranceAmount(bal.getAccountEncumbranceAmount().subtract(amount));
}
else if (KFSConstants.GL_DEBIT_CODE.equals(debitCreditCode) || KFSConstants.GL_BUDGET_CODE.equals(debitCreditCode)) {
bal.setAccountEncumbranceAmount(bal.getAccountEncumbranceAmount().add(amount));
}
}
/**
* Updates the budget amount of a given sufficient funds balance record
*
* @param debitCreditCode whether the the amount should be debited or credited to the SF balance
* @param bal a sufficient funds balance to update
* @param amount the amount to debit or credit
*/
protected void updateBudgetAmount(String debitCreditCode, SufficientFundBalances bal, KualiDecimal amount) {
if (KFSConstants.GL_CREDIT_CODE.equals(debitCreditCode)) {
bal.setCurrentBudgetBalanceAmount(bal.getCurrentBudgetBalanceAmount().subtract(amount));
}
else if (KFSConstants.GL_DEBIT_CODE.equals(debitCreditCode) || KFSConstants.GL_BUDGET_CODE.equals(debitCreditCode)) {
bal.setCurrentBudgetBalanceAmount(bal.getCurrentBudgetBalanceAmount().add(amount));
}
}
/**
* @see org.kuali.kfs.gl.batch.service.PostTransaction#getDestinationName()
*/
public String getDestinationName() {
return persistenceStructureService.getTableName(SufficientFundBalances.class);
}
public void setAccountingCycleCachingService(AccountingCycleCachingService accountingCycleCachingService) {
this.accountingCycleCachingService = accountingCycleCachingService;
}
public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
this.persistenceStructureService = persistenceStructureService;
}
}