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.dataaccess.impl;
017    
018    import java.math.BigDecimal;
019    import java.util.Date;
020    import java.util.Iterator;
021    
022    import org.apache.ojb.broker.query.Criteria;
023    import org.apache.ojb.broker.query.QueryByCriteria;
024    import org.apache.ojb.broker.query.QueryFactory;
025    import org.apache.ojb.broker.query.ReportQueryByCriteria;
026    import org.kuali.kfs.gl.businessobject.Entry;
027    import org.kuali.kfs.gl.businessobject.Transaction;
028    import org.kuali.kfs.gl.dataaccess.EntryDao;
029    import org.kuali.kfs.gl.dataaccess.LedgerEntryBalancingDao;
030    import org.kuali.kfs.sys.KFSConstants;
031    import org.kuali.kfs.sys.KFSPropertyConstants;
032    import org.kuali.rice.kns.dao.impl.PlatformAwareDaoBaseOjb;
033    import org.kuali.rice.kns.util.ObjectUtils;
034    import org.kuali.rice.kns.util.TransactionalServiceUtils;
035    
036    /**
037     * An OJB implementation of EntryDao
038     */
039    public class EntryDaoOjb extends PlatformAwareDaoBaseOjb implements EntryDao, LedgerEntryBalancingDao {
040        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(EntryDaoOjb.class);
041    
042        private final static String UNIVERISITY_FISCAL_YEAR = "universityFiscalYear";
043        private final static String CHART_OF_ACCOUNTS_CODE = "chartOfAccountsCode";
044        private final static String ACCOUNT_NUMBER = "accountNumber";
045        private final static String SUB_ACCOUNT_NUMBER = "subAccountNumber";
046        private final static String FINANCIAL_OBJECT_CODE = "financialObjectCode";
047        private final static String FINANCIAL_SUB_OBJECT_CODE = "financialSubObjectCode";
048        private final static String FINANCIAL_BALANCE_TYPE_CODE = "financialBalanceTypeCode";
049        private final static String FINANCIAL_OBJECT_TYPE_CODE = "financialObjectTypeCode";
050        private final static String UNIVERISTY_FISCAL_PERIOD_CODE = "universityFiscalPeriodCode";
051        private final static String FINANCIAL_DOCUMENT_TYPE_CODE = "financialDocumentTypeCode";
052        private final static String FINANCIAL_SYSTEM_ORIGINATION_CODE = "financialSystemOriginationCode";
053        private final static String MAX_CONSTANT = "max(documentNumber)";
054    
055    
056        /**
057         * Constructs a EntryDaoOjb instance
058         */
059        public EntryDaoOjb() {
060            super();
061        }
062    
063        /**
064         * Turns the given transaction into an entry and then saves that entry in the database
065         * 
066         * @param t the transaction to save
067         * @param postDate the officially reported posting date
068         * @see org.kuali.kfs.gl.dataaccess.EntryDao#addEntry(org.kuali.kfs.gl.businessobject.Transaction, java.util.Date)
069         */
070        public void addEntry(Transaction t, Date postDate) {
071            LOG.debug("addEntry() started");
072    
073            Entry e = new Entry(t, postDate);
074    
075            getPersistenceBrokerTemplate().store(e);
076        }
077    
078        /**
079         * Find the maximum transactionLedgerEntrySequenceNumber in the entry table for a specific transaction. This is used to make
080         * sure that rows added have a unique primary key.
081         * 
082         * @param t the transaction to check
083         * @return the max sequence number
084         */
085        public int getMaxSequenceNumber(Transaction t) {
086            LOG.debug("getSequenceNumber() ");
087    
088            Criteria crit = new Criteria();
089            crit.addEqualTo(UNIVERISITY_FISCAL_YEAR, t.getUniversityFiscalYear());
090            crit.addEqualTo(CHART_OF_ACCOUNTS_CODE, t.getChartOfAccountsCode());
091            crit.addEqualTo(ACCOUNT_NUMBER, t.getAccountNumber());
092            crit.addEqualTo(SUB_ACCOUNT_NUMBER, t.getSubAccountNumber());
093            crit.addEqualTo(FINANCIAL_OBJECT_CODE, t.getFinancialObjectCode());
094            crit.addEqualTo(FINANCIAL_SUB_OBJECT_CODE, t.getFinancialSubObjectCode());
095            crit.addEqualTo(FINANCIAL_BALANCE_TYPE_CODE, t.getFinancialBalanceTypeCode());
096            crit.addEqualTo(FINANCIAL_OBJECT_TYPE_CODE, t.getFinancialObjectTypeCode());
097            crit.addEqualTo(UNIVERISTY_FISCAL_PERIOD_CODE, t.getUniversityFiscalPeriodCode());
098            crit.addEqualTo(FINANCIAL_DOCUMENT_TYPE_CODE, t.getFinancialDocumentTypeCode());
099            crit.addEqualTo(FINANCIAL_SYSTEM_ORIGINATION_CODE, t.getFinancialSystemOriginationCode());
100            crit.addEqualTo(KFSPropertyConstants.DOCUMENT_NUMBER, t.getDocumentNumber());
101    
102            ReportQueryByCriteria q = QueryFactory.newReportQuery(Entry.class, crit);
103            q.setAttributes(new String[] { "max(transactionLedgerEntrySequenceNumber)" });
104    
105            Iterator iter = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(q);
106            // would this work better? max = (BigDecimal) getPersistenceBrokerTemplate().getObjectByQuery(q);
107            BigDecimal max = null;
108            while (iter.hasNext()) {
109                Object[] data = (Object[]) iter.next();
110                max = (BigDecimal) data[0]; // Don't know why OJB returns a BigDecimal, but it does
111            }
112            if (max == null) {
113                return 0;
114            }
115            else {
116                return max.intValue();
117            }
118        }
119    
120        /**
121         * Purge the entry table by chart/year
122         * 
123         * @param chart the chart of accounts code of entries to purge
124         * @param year the university fiscal year of entries to purge
125         */
126        public void purgeYearByChart(String chartOfAccountsCode, int year) {
127            LOG.debug("purgeYearByChart() started");
128    
129            Criteria criteria = new Criteria();
130            criteria.addEqualTo(CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode);
131            criteria.addLessThan(UNIVERISITY_FISCAL_YEAR, new Integer(year));
132    
133            getPersistenceBrokerTemplate().deleteByQuery(new QueryByCriteria(Entry.class, criteria));
134    
135            // This is required because if any deleted rows are in the cache, deleteByQuery doesn't
136            // remove them from the cache so a future select will retrieve these deleted account balances from
137            // the cache and return them. Clearing the cache forces OJB to go to the database again.
138            getPersistenceBrokerTemplate().clearCache();
139        }
140        
141        /**
142         * @see org.kuali.kfs.gl.dataaccess.LedgerEntryBalancingDao#findEntryByGroup(java.lang.Integer, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
143         */
144        public Object[] findEntryByGroup(Integer universityFiscalYear, String chartOfAccountsCode, String financialObjectCode, String financialBalanceTypeCode, String universityFiscalPeriodCode, String transactionDebitCreditCode) {
145            Criteria criteria = new Criteria();
146            criteria.addEqualTo(KFSConstants.UNIVERSITY_FISCAL_YEAR_PROPERTY_NAME, universityFiscalYear);
147            criteria.addEqualTo(KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME, chartOfAccountsCode);
148            criteria.addEqualTo(KFSConstants.FINANCIAL_OBJECT_CODE_PROPERTY_NAME, financialObjectCode);
149            criteria.addEqualTo(KFSConstants.FINANCIAL_BALANCE_TYPE_CODE_PROPERTY_NAME, financialBalanceTypeCode);
150            criteria.addEqualTo(KFSConstants.UNIVERSITY_FISCAL_PERIOD_CODE_PROPERTY_NAME, universityFiscalPeriodCode);
151            criteria.addEqualTo(KFSConstants.TRANSACTION_DEBIT_CREDIT_CODE, transactionDebitCreditCode);
152    
153            ReportQueryByCriteria reportQuery = QueryFactory.newReportQuery(Entry.class, criteria);
154            reportQuery.setAttributes(new String[] { "count(*)", "sum(" + KFSConstants.TRANSACTION_LEDGER_ENTRY_AMOUNT + ")"});
155            reportQuery.addGroupBy(new String[] { KFSConstants.UNIVERSITY_FISCAL_YEAR_PROPERTY_NAME, KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME, KFSConstants.FINANCIAL_OBJECT_CODE_PROPERTY_NAME, KFSConstants.FINANCIAL_BALANCE_TYPE_CODE_PROPERTY_NAME, KFSConstants.UNIVERSITY_FISCAL_PERIOD_CODE_PROPERTY_NAME, KFSConstants.TRANSACTION_DEBIT_CREDIT_CODE});
156            
157            Iterator<Object[]> iterator = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(reportQuery);
158            Object[] returnResult = TransactionalServiceUtils.retrieveFirstAndExhaustIterator(iterator);
159            
160            if (ObjectUtils.isNull(returnResult)) {
161                // Do nothing, we'll return null. Data wasn't found.
162            } else if (returnResult[0] instanceof BigDecimal) {
163                returnResult[0] = ((BigDecimal) returnResult[0]).intValue();
164            } else {
165                returnResult[0] = ((Long) returnResult[0]).intValue();
166            }
167            
168            return returnResult;
169        }
170        
171        /**
172         * @see org.kuali.kfs.gl.dataaccess.LedgerEntryBalancingDao#findCountGreaterOrEqualThan(java.lang.Integer)
173         */
174        public Integer findCountGreaterOrEqualThan(Integer year) {
175            Criteria criteria = new Criteria();
176            criteria.addGreaterOrEqualThan(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, year);
177            
178            ReportQueryByCriteria query = QueryFactory.newReportQuery(Entry.class, criteria);
179            
180            return getPersistenceBrokerTemplate().getCount(query);
181        }
182    }