001/*
002 * The Kuali Financial System, a comprehensive financial management system for higher education.
003 * 
004 * Copyright 2005-2014 The Kuali Foundation
005 * 
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU Affero General Public License as
008 * published by the Free Software Foundation, either version 3 of the
009 * License, or (at your option) any later version.
010 * 
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU Affero General Public License for more details.
015 * 
016 * You should have received a copy of the GNU Affero General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.kuali.kfs.gl.batch.service.impl;
020
021import java.util.Collection;
022import java.util.Date;
023import java.util.Iterator;
024
025import org.kuali.kfs.gl.batch.service.AccountingCycleCachingService;
026import org.kuali.kfs.gl.batch.service.BalanceCalculator;
027import org.kuali.kfs.gl.batch.service.PostTransaction;
028import org.kuali.kfs.gl.businessobject.Balance;
029import org.kuali.kfs.gl.businessobject.Transaction;
030import org.kuali.kfs.sys.businessobject.UniversityDate;
031import org.kuali.kfs.sys.context.SpringContext;
032import org.kuali.kfs.sys.service.ReportWriterService;
033import org.kuali.kfs.sys.service.UniversityDateService;
034import org.kuali.rice.core.api.util.type.KualiDecimal;
035import org.springframework.transaction.annotation.Transactional;
036
037/**
038 * This implementation of PostTransaction updates the appropriate Balance
039 */
040@Transactional
041public class PostBalance implements PostTransaction, BalanceCalculator {
042    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PostBalance.class);
043    
044    private AccountingCycleCachingService accountingCycleCachingService;
045    private static final KualiDecimal NEGATIVE_ONE = new KualiDecimal(-1);
046    /**
047     * Constructs a PostBalance instance
048     */
049    public PostBalance() {
050        super();
051    }
052
053    /**
054     * This posts the effect of the transaction upon the appropriate balance record.
055     * 
056     * @param t the transaction which is being posted
057     * @param mode the mode the poster is currently running in
058     * @param postDate the date this transaction should post to
059     * @param posterReportWriterService the writer service where the poster is writing its report
060     * @return the accomplished post type
061     * @see org.kuali.kfs.gl.batch.service.PostTransaction#post(org.kuali.kfs.gl.businessobject.Transaction, int, java.util.Date)
062     */
063    public String post(Transaction t, int mode, Date postDate, ReportWriterService posterReportWriterService) {
064        LOG.debug("post() started");
065
066        String postType = "U";
067
068        KualiDecimal amount = t.getTransactionLedgerEntryAmount();
069
070        // Subtract the amount if offset generation indicator & the debit/credit code isn't the same
071        // as the one in the object type code table
072        if (t.getBalanceType().isFinancialOffsetGenerationIndicator()) {
073            if (!t.getTransactionDebitCreditCode().equals(t.getObjectType().getFinObjectTypeDebitcreditCd())) {
074                amount = amount.multiply(NEGATIVE_ONE);
075            }
076        }
077
078        Balance b = accountingCycleCachingService.getBalance(t);
079        if (b == null) {
080            postType = "I";
081            b = new Balance(t);
082        }
083        String period = t.getUniversityFiscalPeriodCode();
084        b.addAmount(period, amount);
085
086        if (postType.equals("I")) {
087            accountingCycleCachingService.insertBalance(b);
088        } else {
089            accountingCycleCachingService.updateBalance(b);
090        }
091        
092        return postType;
093    }
094
095    /**
096     * Given a list of balances, determines which one the given trsnaction should post to
097     * 
098     * @param balanceList a Collection of balances
099     * @param t the transaction that is being posted
100     * @return the balance, either found from the list, or, if not present in the list, newly created
101     * @see org.kuali.kfs.gl.batch.service.BalanceCalculator#findBalance(java.util.Collection, org.kuali.kfs.gl.businessobject.Transaction)
102     */
103    public Balance findBalance(Collection balanceList, Transaction t) {
104        // Try to find one that already exists
105        for (Iterator iter = balanceList.iterator(); iter.hasNext();) {
106            Balance b = (Balance) iter.next();
107
108            if (b.getUniversityFiscalYear().equals(t.getUniversityFiscalYear()) && b.getChartOfAccountsCode().equals(t.getChartOfAccountsCode()) && b.getAccountNumber().equals(t.getAccountNumber()) && b.getSubAccountNumber().equals(t.getSubAccountNumber()) && b.getObjectCode().equals(t.getFinancialObjectCode()) && b.getSubObjectCode().equals(t.getFinancialSubObjectCode()) && b.getBalanceTypeCode().equals(t.getFinancialBalanceTypeCode()) && b.getObjectTypeCode().equals(t.getFinancialObjectTypeCode())) {
109                return b;
110            }
111        }
112
113        // If we couldn't find one that exists, create a new one
114        Balance b = new Balance(t);
115        balanceList.add(b);
116
117        return b;
118    }
119
120    /**
121     * @param t
122     * @param enc
123     */
124    public void updateBalance(Transaction t, Balance b) {
125
126        // The pending entries haven't been scrubbed so there could be
127        // bad data. This won't update a balance if the data it needs
128        // is invalid
129        KualiDecimal amount = t.getTransactionLedgerEntryAmount();
130        if (amount == null) {
131            amount = KualiDecimal.ZERO;
132        }
133
134        if (t.getObjectType() == null) {
135            LOG.error("updateBalance() Invalid object type (" + t.getFinancialObjectTypeCode() + ") in pending table");
136            return;
137        }
138
139        if (t.getBalanceType() == null) {
140            LOG.error("updateBalance() Invalid balance type (" + t.getFinancialBalanceTypeCode() + ") in pending table");
141            return;
142        }
143
144        // Subtract the amount if offset generation indicator & the debit/credit code isn't the same
145        // as the one in the object type code table
146        if (t.getBalanceType().isFinancialOffsetGenerationIndicator()) {
147            if (!t.getTransactionDebitCreditCode().equals(t.getObjectType().getFinObjectTypeDebitcreditCd())) {
148                amount = amount.multiply(new KualiDecimal(-1));
149            }
150        }
151
152        // update the balance amount of the cooresponding period
153        String period = t.getUniversityFiscalPeriodCode();
154        if (period == null) {
155            UniversityDate currentUniversityDate = SpringContext.getBean(UniversityDateService.class).getCurrentUniversityDate();
156            period = currentUniversityDate.getUniversityFiscalAccountingPeriod();
157        }
158
159        b.addAmount(period, amount);
160    }
161
162    /**
163     * @see org.kuali.kfs.gl.batch.service.PostTransaction#getDestinationName()
164     */
165    public String getDestinationName() {
166        return "GL_BALANCE_T";
167    }
168
169    public void setAccountingCycleCachingService(AccountingCycleCachingService accountingCycleCachingService) {
170        this.accountingCycleCachingService = accountingCycleCachingService;
171    }
172}