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