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.service.impl;
017    
018    import java.util.Comparator;
019    import java.util.Map;
020    
021    import org.apache.commons.lang.StringUtils;
022    import org.kuali.kfs.coa.businessobject.Account;
023    import org.kuali.kfs.coa.businessobject.SubFundGroup;
024    import org.kuali.kfs.gl.batch.service.AccountingCycleCachingService;
025    import org.kuali.kfs.gl.businessobject.OriginEntryInformation;
026    import org.kuali.kfs.gl.businessobject.PosterOutputSummaryAmountHolder;
027    import org.kuali.kfs.gl.businessobject.PosterOutputSummaryEntry;
028    import org.kuali.kfs.gl.businessobject.Transaction;
029    import org.kuali.kfs.gl.service.PosterOutputSummaryService;
030    import org.kuali.rice.kns.bo.PersistableBusinessObject;
031    import org.kuali.rice.kns.util.KualiDecimal;
032    
033    /**
034     * The default implementation of the PosterOutputSummaryService
035     */
036    public class PosterOutputSummaryServiceImpl implements PosterOutputSummaryService {
037        private AccountingCycleCachingService accountingCycleCachingService;
038    
039        /**
040         * Default implementation
041         * @see org.kuali.kfs.gl.service.PosterOutputSummaryService#addOriginEntryAmountToAmountHolder(org.kuali.kfs.gl.businessobject.OriginEntryInformation, org.kuali.kfs.gl.businessobject.PosterOutputSummaryAmountHolder)
042         */
043        public void addAmountToAmountHolder(OriginEntryInformation originEntry, PosterOutputSummaryAmountHolder amountHolder) {
044            final String debitCreditCode = originEntry.getTransactionDebitCreditCode();
045            final KualiDecimal amount = originEntry.getTransactionLedgerEntryAmount();
046            final String objectTypeCode = originEntry.getFinancialObjectTypeCode();
047            
048            amountHolder.addAmount(debitCreditCode, objectTypeCode, amount);
049        }
050    
051        /**
052         * Default implementation
053         * @see org.kuali.kfs.gl.service.PosterOutputSummaryService#addTransactionAmountToAmountHolder(org.kuali.kfs.gl.businessobject.Transaction, org.kuali.kfs.gl.businessobject.PosterOutputSummaryAmountHolder)
054         */
055        public void addAmountToAmountHolder(Transaction transaction, PosterOutputSummaryAmountHolder amountHolder) {
056            final String debitCreditCode = transaction.getTransactionDebitCreditCode();
057            final KualiDecimal amount = transaction.getTransactionLedgerEntryAmount();
058            final String objectTypeCode = transaction.getFinancialObjectTypeCode();
059    
060            amountHolder.addAmount(debitCreditCode, objectTypeCode, amount);
061        }
062    
063        /**
064         * @see org.kuali.kfs.gl.service.PosterOutputSummaryService#getEntryComparator()
065         */
066        public Comparator<PosterOutputSummaryEntry> getEntryComparator() {
067            return new Comparator<PosterOutputSummaryEntry>() {
068                
069                /**
070                 * Compares the first PosterOutputSummaryEntry given to the second, based on - in order - balance type code,
071                 * university fiscal year, fiscal period code, and finally fund group
072                 * @param vladimir the first PosterOutputSummaryEntry to compare
073                 * @param estragon the second PosterOutputSummaryEntry to compare
074                 * @return the standard result of a compare operation: 0 if there's equality, less than 0 if vladimir is "less" than estragon, and more than 0 if vladimir is "greater" than estragon
075                 */
076                public int compare(PosterOutputSummaryEntry vladimir, PosterOutputSummaryEntry estragon) {
077                    if (shouldCompare(vladimir.getBalanceTypeCode(), estragon.getBalanceTypeCode())) {
078                        return vladimir.getBalanceTypeCode().toUpperCase().compareTo(estragon.getBalanceTypeCode().toUpperCase());
079                    } else if (shouldCompare(vladimir.getUniversityFiscalYear(), estragon.getUniversityFiscalYear())) {
080                        return vladimir.getUniversityFiscalYear().compareTo(estragon.getUniversityFiscalYear());
081                    } else if (shouldCompare(vladimir.getFiscalPeriodCode(), estragon.getFiscalPeriodCode())) {
082                        return vladimir.getFiscalPeriodCode().toUpperCase().compareTo(estragon.getFiscalPeriodCode().toUpperCase());
083                    } else if (shouldCompare(vladimir.getFundGroup(), estragon.getFundGroup())) {
084                        return vladimir.getFundGroup().toUpperCase().compareTo(estragon.getFundGroup().toUpperCase());
085                    } else {
086                        return 0;
087                    }
088                }
089                
090                /**
091                 * Determines if it's safe to compare two Strings
092                 * @param s1 the first String we may compare
093                 * @param s2 the second String we may compare
094                 * @return true if comparison of these two Strings would be meaningful
095                 */
096                protected boolean shouldCompare(String s1, String s2) {
097                    return !StringUtils.isBlank(s1) && !StringUtils.isBlank(s2) && !s1.equalsIgnoreCase(s2);
098                }
099                
100                /**
101                 * Determine if it's safe to compare two Integers
102                 * @param i1 the first Integer we may compare
103                 * @param i2 the second Integer we may compare
104                 * @return true if comparison of the two Integers would be meaningful
105                 */
106                protected boolean shouldCompare(Integer i1, Integer i2) {
107                    return i1 != null && i2 != null && !i1.equals(i2);
108                }
109            };
110        }
111    
112        /**
113         * @see org.kuali.kfs.gl.service.PosterOutputSummaryService#getPosterOutputSummaryEntryMapKey(org.kuali.kfs.gl.businessobject.OriginEntryInformation)
114         */
115        protected String getPosterOutputSummaryEntryMapKey(OriginEntryInformation originEntry) {
116            return buildKey(originEntry.getFinancialBalanceTypeCode(), originEntry.getUniversityFiscalYear(), originEntry.getUniversityFiscalPeriodCode(), originEntry.getChartOfAccountsCode(), originEntry.getAccountNumber());
117        }
118    
119        /**
120         * @see org.kuali.kfs.gl.service.PosterOutputSummaryService#getPosterOutputSummaryEntryMapKey(org.kuali.kfs.gl.businessobject.Transaction)
121         */
122        protected String getPosterOutputSummaryEntryMapKey(Transaction transaction) {
123            return buildKey(transaction.getFinancialBalanceTypeCode(), transaction.getUniversityFiscalYear(), transaction.getUniversityFiscalPeriodCode(), transaction.getChartOfAccountsCode(), transaction.getAccountNumber());
124        }
125    
126        /**
127         * Builds a map key based on the given information
128         * @param balanceTypeCode the balance type code to put in the key
129         * @param universityFiscalYear the fiscal year to put in the key
130         * @param fiscalPeriodCode the period code to put in the key
131         * @param subFundGroupCode the sub fund group code to put in the key
132         * @return a key build from the various attributes
133         */
134        protected String buildKey(String balanceTypeCode, Integer universityFiscalYear, String fiscalPeriodCode, String chartOfAccountsCode, String accountNumber) {
135            return StringUtils.join(new String[] {balanceTypeCode, universityFiscalYear == null ? "" : universityFiscalYear.toString(), fiscalPeriodCode, getFundGroupCodeForAccount(chartOfAccountsCode, accountNumber)}, ':');
136        }
137        
138        /**
139         * Returns the sub fund group for the given origin entry
140         * @param originEntry the origin entry to find the sub fund group for, from its account
141         * @return the sub fund group code related to the account used by this origin entry
142         */
143        protected String getFundGroupCodeForAccount(String chartOfAccountsCode, String accountNumber) {
144            final Account account = this.getAccountingCycleCachingService().getAccount(chartOfAccountsCode, accountNumber);
145            if (account != null) {
146                final SubFundGroup subFundGroup = this.getAccountingCycleCachingService().getSubFundGroup(account.getSubFundGroupCode());
147                if (subFundGroup != null) {
148                    return subFundGroup.getFundGroupCode();
149                }
150            }
151            return "";
152        }
153    
154        /**
155         * @see org.kuali.kfs.gl.service.PosterOutputSummaryService#summarizeOriginEntry(org.kuali.kfs.gl.businessobject.OriginEntryInformation, java.util.Map)
156         */
157        public void summarize(OriginEntryInformation originEntry, Map<String, PosterOutputSummaryEntry> entries) {
158            final String key = getPosterOutputSummaryEntryMapKey(originEntry);
159            PosterOutputSummaryEntry entry = entries.get(key);
160            if (entry == null) {
161                entry = new PosterOutputSummaryEntry(originEntry.getFinancialBalanceTypeCode(), originEntry.getUniversityFiscalYear(), originEntry.getUniversityFiscalPeriodCode(), getFundGroupCodeForAccount(originEntry.getChartOfAccountsCode(), originEntry.getAccountNumber()));
162                entries.put(key, entry);
163            }
164            addAmountToAmountHolder(originEntry, entry);
165        }
166    
167        /**
168         * @see org.kuali.kfs.gl.service.PosterOutputSummaryService#summarizeTransaction(org.kuali.kfs.gl.businessobject.Transaction, java.util.Map)
169         */
170        public void summarize(Transaction transaction, Map<String, PosterOutputSummaryEntry> entries) {
171            final String key = getPosterOutputSummaryEntryMapKey(transaction);
172            PosterOutputSummaryEntry entry = entries.get(key);
173            if (entry == null) {
174                entry = new PosterOutputSummaryEntry(transaction.getFinancialBalanceTypeCode(), transaction.getUniversityFiscalYear(), transaction.getUniversityFiscalPeriodCode(), getFundGroupCodeForAccount(transaction.getChartOfAccountsCode(), transaction.getAccountNumber()));
175                entries.put(key, entry);
176            }
177            addAmountToAmountHolder(transaction, entry);
178        }
179    
180        /**
181         * Gets the accountingCycleCachingService attribute. 
182         * @return Returns the accountingCycleCachingService.
183         */
184        public AccountingCycleCachingService getAccountingCycleCachingService() {
185            return accountingCycleCachingService;
186        }
187    
188        /**
189         * Sets the accountingCycleCachingService attribute value.
190         * @param accountingCycleCachingService The accountingCycleCachingService to set.
191         */
192        public void setAccountingCycleCachingService(AccountingCycleCachingService accountingCycleCachingService) {
193            this.accountingCycleCachingService = accountingCycleCachingService;
194        }
195    }