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.report;
017    
018    import java.util.ArrayList;
019    import java.util.Collections;
020    import java.util.LinkedHashMap;
021    import java.util.List;
022    import java.util.Map;
023    
024    import org.apache.commons.lang.StringUtils;
025    import org.kuali.kfs.gl.businessobject.LedgerBalanceTypeSummaryTotalLine;
026    import org.kuali.kfs.gl.businessobject.LedgerSummaryDetailLine;
027    import org.kuali.kfs.gl.businessobject.LedgerSummaryTotalLine;
028    import org.kuali.kfs.gl.businessobject.OriginEntryInformation;
029    import org.kuali.kfs.sys.DynamicCollectionComparator;
030    import org.kuali.kfs.sys.KFSConstants;
031    import org.kuali.kfs.sys.service.ReportWriterService;
032    
033    /**
034     * Helper class which can summarize entries by balance type and then print out a ledger summary report
035     */
036    public class LedgerSummaryReport {
037        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LedgerSummaryReport.class);
038        
039        private LedgerSummaryTotalLine ledgerTotalLine;
040        private Map<String, LedgerBalanceTypeSummaryTotalLine> balanceTypeTotals;
041        Map<String, LedgerSummaryDetailLine> details;
042        
043        /**
044         * Constructs a LedgerSummaryReport
045         */
046        public LedgerSummaryReport() {
047            ledgerTotalLine = new LedgerSummaryTotalLine();
048            balanceTypeTotals = new LinkedHashMap<String, LedgerBalanceTypeSummaryTotalLine>();
049            details = new LinkedHashMap<String, LedgerSummaryDetailLine>();
050        }
051        
052        /**
053         * Summarizes an entry into the various totals which this report is keeping
054         * @param entry an entry to summarize
055         */
056        public void summarizeEntry(OriginEntryInformation entry) {
057            LedgerBalanceTypeSummaryTotalLine balanceTypeTotal = getBalanceTypeSummaryTotalLine(entry, balanceTypeTotals);
058            LedgerSummaryDetailLine detailLine = getDetailLine(entry, details);
059            addEntryToLedgerSummaries(entry, ledgerTotalLine, balanceTypeTotal, detailLine);
060        }
061        
062        /**
063         * Retrieves the proper balance type summarizer from the given map, or creates a new summarizer and puts it in the Map if it doesn't already exist
064         * @param entry the origin entry to find a balance type summarizer for
065         * @param balanceTypeTotals the Map of balance type summarizers
066         * @return the proper balance type summarizer
067         */
068        protected LedgerBalanceTypeSummaryTotalLine getBalanceTypeSummaryTotalLine(OriginEntryInformation entry, Map<String, LedgerBalanceTypeSummaryTotalLine> balanceTypeTotals) {
069            final String balanceTypeCode = (StringUtils.isBlank(entry.getFinancialBalanceTypeCode())) ? " " : entry.getFinancialBalanceTypeCode();
070            LedgerBalanceTypeSummaryTotalLine balanceTypeTotal = balanceTypeTotals.get(balanceTypeCode);
071            if (balanceTypeTotal == null) {
072                balanceTypeTotal = new LedgerBalanceTypeSummaryTotalLine(balanceTypeCode);
073                balanceTypeTotals.put(balanceTypeCode, balanceTypeTotal);
074            }
075            return balanceTypeTotal;
076        }
077        
078        /**
079         * Retrieves the proper detail line summarizer from the given map, or creates a new summarizer and adds it to the map if needed
080         * @param entry the origin entry to find a detail line summarizer for
081         * @param detailLines a Map of detail line summarizers
082         * @return the proper detail line summarizer
083         */
084        protected LedgerSummaryDetailLine getDetailLine(OriginEntryInformation entry, Map<String, LedgerSummaryDetailLine> detailLines) {
085            final String key = LedgerSummaryDetailLine.getKeyString(entry);
086            LedgerSummaryDetailLine detailLine = detailLines.get(key);
087            if (detailLine == null) {
088                detailLine = new LedgerSummaryDetailLine(entry.getFinancialBalanceTypeCode(), entry.getFinancialSystemOriginationCode(), entry.getUniversityFiscalYear(), entry.getUniversityFiscalPeriodCode());
089                detailLines.put(detailLine.getKey(), detailLine);
090            }
091            return detailLine;
092        }
093        
094        /**
095         * Adds the amount of the origin entry into the appropriate total - debit, credit, or budget - on the various ledger summarizers
096         * @param originEntry the origin entry to add the total from
097         * @param totalLine a complete total to add the amount to
098         * @param balanceTypeTotal the total for the entries with the same balance type as the origin entry to add the amount to
099         * @param detailLine the proper detail amount to add the amoun tto
100         */
101        protected void addEntryToLedgerSummaries(OriginEntryInformation originEntry, LedgerSummaryTotalLine totalLine, LedgerBalanceTypeSummaryTotalLine balanceTypeTotal, LedgerSummaryDetailLine detailLine) {
102            if (originEntry.getTransactionDebitCreditCode() != null && originEntry.getTransactionDebitCreditCode().equals(KFSConstants.GL_DEBIT_CODE)) {
103                totalLine.addDebitAmount(originEntry.getTransactionLedgerEntryAmount());
104                balanceTypeTotal.addDebitAmount(originEntry.getTransactionLedgerEntryAmount());
105                detailLine.addDebitAmount(originEntry.getTransactionLedgerEntryAmount());
106            } else if (originEntry.getTransactionDebitCreditCode() != null && originEntry.getTransactionDebitCreditCode().equals(KFSConstants.GL_CREDIT_CODE)) {
107                totalLine.addCreditAmount(originEntry.getTransactionLedgerEntryAmount());
108                balanceTypeTotal.addCreditAmount(originEntry.getTransactionLedgerEntryAmount());
109                detailLine.addCreditAmount(originEntry.getTransactionLedgerEntryAmount());
110            } else{
111                totalLine.addBudgetAmount(originEntry.getTransactionLedgerEntryAmount());
112                balanceTypeTotal.addBudgetAmount(originEntry.getTransactionLedgerEntryAmount());
113                detailLine.addBudgetAmount(originEntry.getTransactionLedgerEntryAmount());
114            }
115        }
116        
117        /**
118         * Writes the report of totals to the given reportWriterService
119         * @param reportWriterService a report writer service to write the ledger summary report to
120         */
121        public void writeReport(ReportWriterService reportWriterService) {
122            if (details.size() > 0) {
123                List<LedgerSummaryDetailLine> detailList = new ArrayList<LedgerSummaryDetailLine>(details.values());
124                DynamicCollectionComparator.sort(detailList, LedgerSummaryDetailLine.keyFields);
125            
126                reportWriterService.writeTableHeader(detailList.get(0));
127                String currentBalanceType = detailList.get(0).getFinancialBalanceTypeCode();
128                currentBalanceType = StringUtils.isBlank(currentBalanceType) ? " " : currentBalanceType;
129                
130                for (LedgerSummaryDetailLine detailLine : detailList) {
131                    String detailLineBalanceType = (StringUtils.isBlank(detailLine.getFinancialBalanceTypeCode())) ? " " : detailLine.getFinancialBalanceTypeCode();
132                    if (!detailLineBalanceType.equals(currentBalanceType)) {
133                        LedgerBalanceTypeSummaryTotalLine subTitleLine = balanceTypeTotals.get(currentBalanceType);
134                        
135                        if (subTitleLine != null) {
136                            reportWriterService.writeTableRow(subTitleLine);
137                            reportWriterService.writeTableRowSeparationLine(subTitleLine);
138                        }
139                        currentBalanceType = detailLineBalanceType;
140                    }
141    
142                    reportWriterService.writeTableRow(detailLine);
143                }
144                final LedgerBalanceTypeSummaryTotalLine lastLine = balanceTypeTotals.get(detailList.get(detailList.size()-1).getFinancialBalanceTypeCode());
145                if (lastLine != null) {
146                    reportWriterService.writeTableRow(lastLine);
147                }
148                
149                reportWriterService.writeTableRowSeparationLine(ledgerTotalLine);
150                reportWriterService.writeTableRow(ledgerTotalLine);
151            }
152        }
153        
154    }