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 }