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.module.bc.document.service.impl;
017    
018    import java.math.BigDecimal;
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    
025    import org.apache.commons.lang.StringUtils;
026    import org.apache.ojb.broker.PersistenceBrokerException;
027    import org.kuali.kfs.module.bc.BCConstants;
028    import org.kuali.kfs.module.bc.BCKeyConstants;
029    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAccountSalaryDetailReport;
030    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAccountSalaryDetailReportTotal;
031    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAdministrativePost;
032    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionCalculatedSalaryFoundationTracker;
033    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionIntendedIncumbent;
034    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionPosition;
035    import org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding;
036    import org.kuali.kfs.module.bc.document.service.BudgetConstructionAccountSalaryDetailReportService;
037    import org.kuali.kfs.module.bc.document.service.BudgetConstructionReportsServiceHelper;
038    import org.kuali.kfs.module.bc.document.service.SalarySettingService;
039    import org.kuali.kfs.module.bc.report.BudgetConstructionReportHelper;
040    import org.kuali.kfs.sys.KFSPropertyConstants;
041    import org.kuali.rice.kns.service.KualiConfigurationService;
042    import org.kuali.rice.kns.util.KualiInteger;
043    import org.springframework.transaction.annotation.Transactional;
044    
045    /**
046     * Service implementation of BudgetConstructionLevelSummaryReportService.
047     */
048    @Transactional
049    public class BudgetConstructionAccountSalaryDetailReportServiceImpl implements BudgetConstructionAccountSalaryDetailReportService {
050    
051        private KualiConfigurationService kualiConfigurationService;
052        private BudgetConstructionReportsServiceHelper budgetConstructionReportsServiceHelper;
053        private SalarySettingService salarySettingService;
054    
055        /**
056         * @see org.kuali.kfs.module.bc.document.service.BudgetConstructionLevelSummaryReportService#buildReports(java.lang.Integer,
057         *      java.util.Collection)
058         */
059        public Collection<BudgetConstructionAccountSalaryDetailReport> buildReports(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String subAccountNumber) {
060            Collection<BudgetConstructionAccountSalaryDetailReport> reportSet = new ArrayList<BudgetConstructionAccountSalaryDetailReport>();
061    
062            Map<String, Object> searchCriteria = buildSearchCriteria(universityFiscalYear, chartOfAccountsCode, accountNumber, subAccountNumber);
063            List<String> orderList = buildOrderByList();
064            
065            Collection<PendingBudgetConstructionAppointmentFunding> pendingAppointmentFundingList = budgetConstructionReportsServiceHelper.getDataForBuildingReports(PendingBudgetConstructionAppointmentFunding.class, searchCriteria, orderList);
066            List<PendingBudgetConstructionAppointmentFunding> listForTotal = BudgetConstructionReportHelper.deleteDuplicated((List) pendingAppointmentFundingList, fieldsForTotal());
067    
068            Collection<BudgetConstructionAccountSalaryDetailReportTotal> accountSalaryDetailTotal = calculateTotal(pendingAppointmentFundingList, listForTotal);
069            for (PendingBudgetConstructionAppointmentFunding pendingAppointmentFunding : pendingAppointmentFundingList) {
070                BudgetConstructionAccountSalaryDetailReport accountSalaryDetailReport = new BudgetConstructionAccountSalaryDetailReport();
071                
072                buildReportsHeader(universityFiscalYear, pendingAppointmentFunding, accountSalaryDetailReport);
073                buildReportsBody(universityFiscalYear, pendingAppointmentFunding, accountSalaryDetailReport);
074                buildReportsTotal(pendingAppointmentFunding, accountSalaryDetailReport, accountSalaryDetailTotal);
075                
076                reportSet.add(accountSalaryDetailReport);
077            }
078    
079            return reportSet;
080        }
081    
082        /**
083         * builds report Header
084         * 
085         * @param BudgetConstructionObjectSummary bcas
086         */
087        protected void buildReportsHeader(Integer universityFiscalYear, PendingBudgetConstructionAppointmentFunding pendingAppointmentFunding, BudgetConstructionAccountSalaryDetailReport accountSalaryDetailReport) {
088    
089            Integer prevFiscalyear = universityFiscalYear - 1;
090            accountSalaryDetailReport.setFiscalYear(prevFiscalyear.toString() + "-" + universityFiscalYear.toString().substring(2, 4));
091    
092    
093            accountSalaryDetailReport.setAccountNumber(pendingAppointmentFunding.getAccountNumber());
094            accountSalaryDetailReport.setSubAccountNumber(pendingAppointmentFunding.getSubAccountNumber());
095            accountSalaryDetailReport.setChartOfAccountsCode(pendingAppointmentFunding.getChartOfAccountsCode());
096            accountSalaryDetailReport.setOrganizationCode(pendingAppointmentFunding.getAccount().getOrganizationCode());
097    
098            String chartOfAccountDescription = "";
099            if (pendingAppointmentFunding.getChartOfAccounts() != null) {
100                try {
101                    chartOfAccountDescription = pendingAppointmentFunding.getChartOfAccounts().getFinChartOfAccountDescription();
102                }
103                catch (PersistenceBrokerException e) {
104                    chartOfAccountDescription = kualiConfigurationService.getPropertyString(BCKeyConstants.ERROR_REPORT_GETTING_CHART_DESCRIPTION);
105                }
106            }
107            else {
108                chartOfAccountDescription = BCConstants.Report.CHART + BCConstants.Report.NOT_DEFINED;
109            }
110    
111            accountSalaryDetailReport.setChartOfAccountDescription(chartOfAccountDescription);
112    
113            String orgName = null;
114            try {
115                orgName = pendingAppointmentFunding.getAccount().getOrganization().getOrganizationName();
116            }
117            catch (PersistenceBrokerException e) {
118            }
119            String accountName = pendingAppointmentFunding.getAccount().getAccountName();
120            String fundGroupCode = pendingAppointmentFunding.getAccount().getSubFundGroup().getFundGroupCode();
121            String fundGroupName = pendingAppointmentFunding.getAccount().getSubFundGroup().getFundGroup().getName();
122    
123            if (orgName == null) {
124                accountSalaryDetailReport.setOrganizationName(kualiConfigurationService.getPropertyString(BCKeyConstants.ERROR_REPORT_GETTING_ORGANIZATION_NAME));
125            }
126            else {
127                accountSalaryDetailReport.setOrganizationName(orgName);
128            }
129    
130            if (fundGroupCode == null) {
131                accountSalaryDetailReport.setFundGroupCode(kualiConfigurationService.getPropertyString(BCKeyConstants.ERROR_REPORT_GETTING_FUNDGROUP_CODE));
132            }
133            else {
134                accountSalaryDetailReport.setFundGroupCode(fundGroupCode);
135            }
136    
137            if (fundGroupName == null) {
138                accountSalaryDetailReport.setFundGroupName(kualiConfigurationService.getPropertyString(BCKeyConstants.ERROR_REPORT_GETTING_FUNDGROUP_NAME));
139            }
140            else {
141                accountSalaryDetailReport.setFundGroupName(fundGroupName);
142            }
143    
144            if (accountName == null) {
145                accountSalaryDetailReport.setAccountName(kualiConfigurationService.getPropertyString(BCKeyConstants.ERROR_REPORT_GETTING_ACCOUNT_DESCRIPTION));
146            }
147            else {
148                accountSalaryDetailReport.setAccountName(accountName);
149            }
150    
151            String subAccountName = "";
152    
153            if (!pendingAppointmentFunding.getSubAccountNumber().equals(BCConstants.Report.DASHES_SUB_ACCOUNT_CODE)) {
154                try {
155                    subAccountName = pendingAppointmentFunding.getSubAccount().getSubAccountName();
156                }
157                catch (PersistenceBrokerException e) {
158                    subAccountName = kualiConfigurationService.getPropertyString(BCKeyConstants.ERROR_REPORT_GETTING_SUB_ACCOUNT_DESCRIPTION);
159                }
160            }
161            accountSalaryDetailReport.setSubAccountName(subAccountName);
162    
163    
164        }
165    
166        /**
167         * builds report body
168         * 
169         * @param BudgetConstructionLevelSummary bcas
170         */
171        protected void buildReportsBody(Integer universityFiscalYear, PendingBudgetConstructionAppointmentFunding pendingAppointmentFunding, BudgetConstructionAccountSalaryDetailReport accountMonthlyDetailReport) {
172            Integer amountChange = new Integer(0);
173            BigDecimal percentChange = BigDecimal.ZERO;
174    
175            BudgetConstructionIntendedIncumbent intendedIncumbent = budgetConstructionReportsServiceHelper.getBudgetConstructionIntendedIncumbent(pendingAppointmentFunding);
176            BudgetConstructionAdministrativePost administrativePost = budgetConstructionReportsServiceHelper.getBudgetConstructionAdministrativePost(pendingAppointmentFunding);
177            BudgetConstructionPosition position = budgetConstructionReportsServiceHelper.getBudgetConstructionPosition(universityFiscalYear, pendingAppointmentFunding);
178            BudgetConstructionCalculatedSalaryFoundationTracker csfTracker = pendingAppointmentFunding.getEffectiveCSFTracker();
179    
180            // from PendingBudgetConstructionAppointmentFunding
181            accountMonthlyDetailReport.setFinancialSubObjectCode(pendingAppointmentFunding.getFinancialSubObjectCode());
182    
183            // from BudgetConstructionIntendedIncumbent
184            if (intendedIncumbent != null) {
185                accountMonthlyDetailReport.setIuClassificationLevel(intendedIncumbent.getIuClassificationLevel());
186            }
187    
188            // from BudgetConstructionAdministrativePost
189            if (administrativePost != null) {
190                accountMonthlyDetailReport.setAdministrativePost(administrativePost.getAdministrativePost());
191            }
192    
193            // from BudgetConstructionPosition
194            if (position != null) {
195                accountMonthlyDetailReport.setPositionNumber(position.getPositionNumber());
196                accountMonthlyDetailReport.setPositionSalaryPlanDefault(position.getPositionSalaryPlanDefault());
197                accountMonthlyDetailReport.setPositionGradeDefault(position.getPositionGradeDefault());
198                accountMonthlyDetailReport.setNormalWorkMonthsAndiuPayMonths(position.getIuNormalWorkMonths() + "/" + position.getIuPayMonths());
199            }
200    
201            // from BudgetConstructionCalculatedSalaryFoundationTracker
202            if (csfTracker != null) {
203                accountMonthlyDetailReport.setPositionCsfAmount(csfTracker.getCsfAmount().intValue());
204                accountMonthlyDetailReport.setCsfTimePercent(BudgetConstructionReportHelper.setDecimalDigit(csfTracker.getCsfTimePercent(), 2, false));
205                accountMonthlyDetailReport.setPositionCsfFullTimeEmploymentQuantity(BudgetConstructionReportHelper.setDecimalDigit(csfTracker.getCsfFullTimeEmploymentQuantity(), 5, false));
206                accountMonthlyDetailReport.setPositionCsfFundingStatusCode(csfTracker.getCsfFundingStatusCode());
207                
208                BigDecimal csfFte = BudgetConstructionReportHelper.setDecimalDigit(csfTracker.getCsfFullTimeEmploymentQuantity(), 5, false);
209                BigDecimal reqFte = BudgetConstructionReportHelper.setDecimalDigit(pendingAppointmentFunding.getAppointmentRequestedFteQuantity(), 5, false);
210                if (reqFte.compareTo(csfFte) == 0) {
211                    amountChange = pendingAppointmentFunding.getAppointmentRequestedAmount().subtract(csfTracker.getCsfAmount()).intValue();
212    
213                    if (!csfTracker.getCsfAmount().equals(KualiInteger.ZERO)) {
214                        percentChange = BudgetConstructionReportHelper.calculatePercent(amountChange, csfTracker.getCsfAmount().intValue());
215                    }
216                }
217            }
218    
219            // from PendingBudgetConstructionAppointmentFunding
220            accountMonthlyDetailReport.setAppointmentFundingMonth(pendingAppointmentFunding.getAppointmentFundingMonth());
221            if (salarySettingService.isHourlyPaidObject(pendingAppointmentFunding.getUniversityFiscalYear(), pendingAppointmentFunding.getChartOfAccountsCode(), pendingAppointmentFunding.getFinancialObjectCode())){
222                accountMonthlyDetailReport.setAppointmentRequestedPayRate(pendingAppointmentFunding.getAppointmentRequestedPayRate());
223            }
224    
225            accountMonthlyDetailReport.setAppointmentRequestedAmount(pendingAppointmentFunding.getAppointmentRequestedAmount().intValue());
226            accountMonthlyDetailReport.setAppointmentRequestedTimePercent(BudgetConstructionReportHelper.setDecimalDigit(pendingAppointmentFunding.getAppointmentRequestedTimePercent(), 2, false));
227            accountMonthlyDetailReport.setAppointmentRequestedFteQuantity(BudgetConstructionReportHelper.setDecimalDigit(pendingAppointmentFunding.getAppointmentRequestedFteQuantity(), 5, false));
228            accountMonthlyDetailReport.setAppointmentRequestedCsfAmount(pendingAppointmentFunding.getAppointmentRequestedCsfAmount().intValue());
229            accountMonthlyDetailReport.setAppointmentRequestedCsfTimePercent(BudgetConstructionReportHelper.setDecimalDigit(pendingAppointmentFunding.getAppointmentRequestedCsfTimePercent(), 2, false));
230            accountMonthlyDetailReport.setAppointmentRequestedCsfFteQuantity(BudgetConstructionReportHelper.setDecimalDigit(pendingAppointmentFunding.getAppointmentRequestedCsfFteQuantity(), 5, false));
231            accountMonthlyDetailReport.setAppointmentFundingDurationCode(pendingAppointmentFunding.getAppointmentFundingDurationCode());
232            accountMonthlyDetailReport.setAppointmentTotalIntendedAmount(pendingAppointmentFunding.getAppointmentTotalIntendedAmount().intValue());
233            accountMonthlyDetailReport.setAppointmentTotalIntendedFteQuantity(BudgetConstructionReportHelper.setDecimalDigit(pendingAppointmentFunding.getAppointmentTotalIntendedFteQuantity(), 5, false));
234    
235            accountMonthlyDetailReport.setFinancialObjectCode(pendingAppointmentFunding.getFinancialObjectCode());
236            accountMonthlyDetailReport.setFinancialObjectCodeName(pendingAppointmentFunding.getFinancialObject().getFinancialObjectCodeName());
237    
238            String deleteBox = pendingAppointmentFunding.isAppointmentFundingDeleteIndicator() ? BCConstants.Report.DELETE_MARK : BCConstants.Report.BLANK;
239            accountMonthlyDetailReport.setDeleteBox(deleteBox);
240    
241            if (pendingAppointmentFunding.getEmplid().equals(BCConstants.Report.VACANT)){
242                accountMonthlyDetailReport.setName(BCConstants.Report.VACANT); 
243            } else {
244                int nameLength = intendedIncumbent.getName().length();
245                accountMonthlyDetailReport.setName(intendedIncumbent.getName().substring(0, (nameLength > 35) ? 35 : nameLength));
246    
247            }
248    
249            accountMonthlyDetailReport.setAmountChange(amountChange);
250            accountMonthlyDetailReport.setPercentChange(percentChange);
251        }
252    
253        protected void buildReportsTotal(PendingBudgetConstructionAppointmentFunding pendingAppointmentFunding, BudgetConstructionAccountSalaryDetailReport accountMonthlyDetailReport, Collection<BudgetConstructionAccountSalaryDetailReportTotal> accountSalaryDetailTotal) {
254    
255            for (BudgetConstructionAccountSalaryDetailReportTotal totalEntry : accountSalaryDetailTotal) {
256                if (BudgetConstructionReportHelper.isSameEntry(totalEntry.getPendingBudgetConstructionAppointmentFunding(), pendingAppointmentFunding, fieldsForTotal())) {
257    
258                    String objectCodeName = StringUtils.EMPTY;
259                    if (pendingAppointmentFunding.getFinancialObject() != null) {
260                        try {
261                            objectCodeName = pendingAppointmentFunding.getFinancialObject().getFinancialObjectCodeName();
262                        }
263                        catch (PersistenceBrokerException e) {
264                            objectCodeName = kualiConfigurationService.getPropertyString(BCKeyConstants.ERROR_REPORT_GETTING_OBJECT_NAME);
265                        }
266                    }
267                    else {
268                        objectCodeName = BCConstants.Report.OBJECT + BCConstants.Report.NOT_DEFINED;
269                    }
270                    accountMonthlyDetailReport.setTotalDescription(objectCodeName);
271    
272                    accountMonthlyDetailReport.setTotalBaseAmount(totalEntry.getTotalBaseAmount());
273                    accountMonthlyDetailReport.setTotalBaseFte(totalEntry.getTotalBaseFte());
274                    accountMonthlyDetailReport.setTotalRequestAmount(totalEntry.getTotalRequestAmount());
275                    accountMonthlyDetailReport.setTotalRequestFte(totalEntry.getTotalRequestFte());
276    
277                    accountMonthlyDetailReport.setTotalAmountChange(totalEntry.getTotalRequestAmount() - totalEntry.getTotalBaseAmount());
278                    accountMonthlyDetailReport.setTotalPercentChange(BudgetConstructionReportHelper.calculatePercent(accountMonthlyDetailReport.getTotalAmountChange(), totalEntry.getTotalBaseAmount()));
279                }
280            }
281        }
282    
283    
284        protected Collection<BudgetConstructionAccountSalaryDetailReportTotal> calculateTotal(Collection<PendingBudgetConstructionAppointmentFunding> pendingAppointmentFundingList, List<PendingBudgetConstructionAppointmentFunding> listForTotal) {
285            Collection<BudgetConstructionAccountSalaryDetailReportTotal> reportTotals = new ArrayList<BudgetConstructionAccountSalaryDetailReportTotal>();
286    
287            for (PendingBudgetConstructionAppointmentFunding totalEntry : listForTotal) {
288                KualiInteger totalBaseAmount = KualiInteger.ZERO;
289                BigDecimal totalBaseFte = BigDecimal.ZERO;
290                Integer totalRequestAmount = new Integer(0);
291                BigDecimal totalRequestFte = BigDecimal.ZERO;
292    
293                BudgetConstructionAccountSalaryDetailReportTotal budgetConstructionAccountSalaryDetailReportTotal = new BudgetConstructionAccountSalaryDetailReportTotal();
294                for (PendingBudgetConstructionAppointmentFunding appointmentFundingEntry : pendingAppointmentFundingList) {
295                    if (BudgetConstructionReportHelper.isSameEntry(totalEntry, appointmentFundingEntry, fieldsForTotal())) {
296                        BudgetConstructionCalculatedSalaryFoundationTracker csfTracker = appointmentFundingEntry.getEffectiveCSFTracker();
297    
298                        if (csfTracker != null) {
299                            totalBaseAmount = totalBaseAmount.add(csfTracker.getCsfAmount());
300                            totalBaseFte = totalBaseFte.add(csfTracker.getCsfFullTimeEmploymentQuantity());
301                        }
302    
303                        totalRequestAmount = totalRequestAmount + new Integer(appointmentFundingEntry.getAppointmentRequestedAmount().intValue());
304                        totalRequestFte = totalRequestFte.add(appointmentFundingEntry.getAppointmentRequestedFteQuantity());
305                    }
306                }
307    
308                budgetConstructionAccountSalaryDetailReportTotal.setTotalBaseAmount(totalBaseAmount.intValue());
309                budgetConstructionAccountSalaryDetailReportTotal.setTotalBaseFte(totalBaseFte);
310                budgetConstructionAccountSalaryDetailReportTotal.setTotalRequestAmount(totalRequestAmount);
311                budgetConstructionAccountSalaryDetailReportTotal.setTotalRequestFte(totalRequestFte);
312                budgetConstructionAccountSalaryDetailReportTotal.setPendingBudgetConstructionAppointmentFunding(totalEntry);
313    
314                reportTotals.add(budgetConstructionAccountSalaryDetailReportTotal);
315            }
316    
317            return reportTotals;
318        }
319    
320    
321        protected List<String> fieldsForTotal() {
322            List<String> fieldList = new ArrayList<String>();
323            fieldList.add(KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
324    
325            return fieldList;
326        }
327    
328        /**
329         * builds orderByList for sort order.
330         * 
331         * @return returnList
332         */
333        protected List<String> buildOrderByList() {
334            List<String> returnList = new ArrayList<String>();
335            returnList.add(KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
336            returnList.add(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE);
337            returnList.add(KFSPropertyConstants.POSITION_NUMBER);
338            returnList.add(KFSPropertyConstants.EMPLID);
339    
340            return returnList;
341        }
342    
343        protected Map<String, Object> buildSearchCriteria(Integer universityFiscalYear, String chartOfAccountsCode, String accountNumber, String subAccountNumber) {
344            Map<String, Object> searchCriteria = new HashMap<String, Object>();
345            searchCriteria.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityFiscalYear);
346            searchCriteria.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartOfAccountsCode);
347            searchCriteria.put(KFSPropertyConstants.ACCOUNT_NUMBER, accountNumber);
348            searchCriteria.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, subAccountNumber);
349    
350            return searchCriteria;
351        }
352    
353        /**
354         * Sets the kualiConfigurationService attribute value.
355         * 
356         * @param kualiConfigurationService The kualiConfigurationService to set.
357         */
358        public void setKualiConfigurationService(KualiConfigurationService kualiConfigurationService) {
359            this.kualiConfigurationService = kualiConfigurationService;
360        }
361    
362        /**
363         * Sets the budgetConstructionReportsServiceHelper attribute value.
364         * 
365         * @param budgetConstructionReportsServiceHelper The budgetConstructionReportsServiceHelper to set.
366         */
367        public void setBudgetConstructionReportsServiceHelper(BudgetConstructionReportsServiceHelper budgetConstructionReportsServiceHelper) {
368            this.budgetConstructionReportsServiceHelper = budgetConstructionReportsServiceHelper;
369        }
370    
371        /**
372         * Sets the salarySettingService attribute value.
373         * @param salarySettingService The salarySettingService to set.
374         */
375        public void setSalarySettingService(SalarySettingService salarySettingService) {
376            this.salarySettingService = salarySettingService;
377        }
378    }