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.ar.businessobject.lookup;
017    
018    import java.text.DateFormat;
019    import java.text.ParseException;
020    import java.text.SimpleDateFormat;
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.Date;
024    import java.util.HashMap;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.Properties;
028    import java.util.Set;
029    
030    import org.apache.commons.lang.StringUtils;
031    import org.apache.commons.lang.time.DateUtils;
032    import org.kuali.kfs.module.ar.ArConstants;
033    import org.kuali.kfs.module.ar.ArPropertyConstants;
034    import org.kuali.kfs.module.ar.businessobject.CustomerAgingReportDetail;
035    import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail;
036    import org.kuali.kfs.module.ar.dataaccess.CustomerAgingReportDao;
037    import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument;
038    import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDetailService;
039    import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService;
040    import org.kuali.kfs.module.ar.web.struts.CustomerAgingReportForm;
041    import org.kuali.kfs.sys.KFSConstants;
042    import org.kuali.kfs.sys.KFSPropertyConstants;
043    import org.kuali.kfs.sys.context.SpringContext;
044    import org.kuali.rice.kim.bo.Person;
045    import org.kuali.rice.kns.authorization.BusinessObjectRestrictions;
046    import org.kuali.rice.kns.bo.BusinessObject;
047    import org.kuali.rice.kns.bo.PersistableBusinessObject;
048    import org.kuali.rice.kns.lookup.CollectionIncomplete;
049    import org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl;
050    import org.kuali.rice.kns.service.BusinessObjectAuthorizationService;
051    import org.kuali.rice.kns.service.BusinessObjectService;
052    import org.kuali.rice.kns.service.DataDictionaryService;
053    import org.kuali.rice.kns.service.DateTimeService;
054    import org.kuali.rice.kns.service.ParameterService;
055    import org.kuali.rice.kns.util.GlobalVariables;
056    import org.kuali.rice.kns.util.KNSConstants;
057    import org.kuali.rice.kns.util.KualiDecimal;
058    import org.kuali.rice.kns.util.ObjectUtils;
059    import org.kuali.rice.kns.web.comparator.CellComparatorHelper;
060    import org.kuali.rice.kns.web.format.BooleanFormatter;
061    import org.kuali.rice.kns.web.format.CollectionFormatter;
062    import org.kuali.rice.kns.web.format.DateFormatter;
063    import org.kuali.rice.kns.web.format.Formatter;
064    import org.kuali.rice.kns.web.struts.form.LookupForm;
065    import org.kuali.rice.kns.web.ui.Column;
066    import org.kuali.rice.kns.web.ui.ResultRow;
067    
068    
069    public class CustomerAgingReportLookupableHelperServiceImpl extends KualiLookupableHelperServiceImpl {
070    
071        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CustomerAgingReportLookupableHelperServiceImpl.class);
072    
073        private DataDictionaryService dataDictionaryService;
074        private DateTimeService dateTimeService;
075    
076        private Map fieldConversions;
077    
078        private CustomerInvoiceDetailService customerInvoiceDetailService = SpringContext.getBean(CustomerInvoiceDetailService.class);
079        private CustomerInvoiceDocumentService customerInvoiceDocumentService = SpringContext.getBean(CustomerInvoiceDocumentService.class);
080        private BusinessObjectService businessObjectService;
081    
082        private String customerNameLabel;
083        private String customerNumberLabel;
084        private String cutoffdate30Label;
085        private String cutoffdate60Label;
086        private String cutoffdate90Label;
087    
088        private KualiDecimal total0to30 = KualiDecimal.ZERO;
089        private KualiDecimal total31to60 = KualiDecimal.ZERO;
090        private KualiDecimal total61to90 = KualiDecimal.ZERO;
091        private KualiDecimal total91toSYSPR = KualiDecimal.ZERO;
092        private KualiDecimal totalSYSPRplus1orMore = KualiDecimal.ZERO;
093    
094        private Date reportRunDate;
095        private String reportOption;
096        private String accountNumber;
097        private String processingOrBillingChartCode;
098        private String accountChartCode;
099        private String orgCode;
100        private String nbrDaysForLastBucket = SpringContext.getBean(ParameterService.class).getParameterValue(CustomerAgingReportDetail.class, "CUSTOMER_INVOICE_AGE"); // ArConstants.CUSTOMER_INVOICE_AGE);
101        // default is 120 days
102        private String cutoffdate91toSYSPRlabel = "91-" + nbrDaysForLastBucket + " days";
103        private String cutoffdateSYSPRplus1orMorelabel = Integer.toString((Integer.parseInt(nbrDaysForLastBucket)) + 1) + "+ days";
104    
105    
106        /**
107         * Get the search results that meet the input search criteria.
108         * 
109         * @param fieldValues - Map containing prop name keys and search values
110         * @return a List of found business objects
111         */
112        @Override
113        public List getSearchResults(Map fieldValues) {
114            CustomerAgingReportDao agingReportDao = SpringContext.getBean(CustomerAgingReportDao.class);
115    
116            setBackLocation((String) fieldValues.get(KFSConstants.BACK_LOCATION));
117            setDocFormKey((String) fieldValues.get(KFSConstants.DOC_FORM_KEY));
118    
119            reportOption = (String) fieldValues.get(ArPropertyConstants.CustomerAgingReportFields.REPORT_OPTION);
120            accountNumber = (String) fieldValues.get(KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME);
121            processingOrBillingChartCode = (String) fieldValues.get("processingOrBillingChartOfAccountsCode");
122            accountChartCode = (String) fieldValues.get("accountChartOfAccountsCode");
123            orgCode = (String) fieldValues.get(KFSConstants.ORGANIZATION_CODE_PROPERTY_NAME);
124    
125    
126            total0to30 = KualiDecimal.ZERO;
127            total31to60 = KualiDecimal.ZERO;
128            total61to90 = KualiDecimal.ZERO;
129            total91toSYSPR = KualiDecimal.ZERO;
130            totalSYSPRplus1orMore = KualiDecimal.ZERO;
131            DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
132    
133            Date today = getDateTimeService().getCurrentDate();
134            try {
135                reportRunDate = dateFormat.parse((String) fieldValues.get(ArPropertyConstants.CustomerAgingReportFields.REPORT_RUN_DATE));
136            }
137            catch (ParseException e) {
138                reportRunDate = today;
139                e.printStackTrace();
140            }
141            Date cutoffdate30 = DateUtils.addDays(reportRunDate, -30);
142            Date cutoffdate31 = DateUtils.addDays(reportRunDate, -31);
143            Date cutoffdate60 = DateUtils.addDays(reportRunDate, -60);
144            Date cutoffdate61 = DateUtils.addDays(reportRunDate, -61);
145            Date cutoffdate90 = DateUtils.addDays(reportRunDate, -90);
146            Date cutoffdate91 = DateUtils.addDays(reportRunDate, -91);
147            // Date cutoffdate120 = DateUtils.addDays(reportRunDate, -120);
148            Date cutoffdate120 = DateUtils.addDays(reportRunDate, -1 * Integer.parseInt(nbrDaysForLastBucket));
149            Date cutoffdate121 = DateUtils.addDays(cutoffdate120, -1);
150    
151            // LOG.info("\t\t********** REPORT DATE\t\t"+reportRunDate.toString());
152            // LOG.info("\t\t*********************** cutoffdate 30:\t\t"+cutoffdate30.toString());
153            // LOG.info("\t\t*********************** cutoffdate 60:\t\t"+cutoffdate60.toString());
154            // LOG.info("\t\t*********************** cutoffdate 90:\t\t"+cutoffdate90.toString());
155            // LOG.info("\t\t*********************** cutoffdate 120:\t\t"+cutoffdate120.toString());
156    
157    
158            Collection<CustomerInvoiceDocument> invoices = new ArrayList<CustomerInvoiceDocument>();
159            Map<String, CustomerAgingReportDetail> knownCustomers = new HashMap<String, CustomerAgingReportDetail>();
160    
161            CustomerAgingReportDetail custDetail;
162            if (reportOption.equalsIgnoreCase(ArConstants.CustomerAgingReportFields.PROCESSING_ORG) && StringUtils.isNotBlank(processingOrBillingChartCode) && StringUtils.isNotBlank(orgCode)) {
163                // 30 days
164                computeFor0To30DaysByProcessingChartAndOrg(agingReportDao, new java.sql.Date(cutoffdate30.getTime()), new java.sql.Date(reportRunDate.getTime()), knownCustomers);
165                // 60 days
166                computeFor31To60DaysByProcessingChartAndOrg(agingReportDao, new java.sql.Date(cutoffdate60.getTime()), new java.sql.Date(cutoffdate31.getTime()), knownCustomers);
167                // 90 days
168                computeFor61To90DaysByProcessingChartAndOrg(agingReportDao, new java.sql.Date(cutoffdate90.getTime()), new java.sql.Date(cutoffdate61.getTime()), knownCustomers);
169                // 120 days
170                computeFor91ToSYSPRDaysByProcessingChartAndOrg(agingReportDao, new java.sql.Date(cutoffdate120.getTime()), new java.sql.Date(cutoffdate91.getTime()), knownCustomers);
171                // 120 + older
172                computeForSYSPRplus1orMoreDaysByProcessingChartAndOrg(agingReportDao, null, new java.sql.Date(cutoffdate121.getTime()), knownCustomers);
173            }
174            if (reportOption.equalsIgnoreCase(ArConstants.CustomerAgingReportFields.BILLING_ORG) && StringUtils.isNotBlank(processingOrBillingChartCode) && StringUtils.isNotBlank(orgCode)) {
175                // 30 days
176                computeFor0To30DaysByBillingChartAndOrg(agingReportDao, new java.sql.Date(cutoffdate30.getTime()), new java.sql.Date(reportRunDate.getTime()), knownCustomers);
177                // 60 days
178                computeFor31To60DaysByBillingChartAndOrg(agingReportDao, new java.sql.Date(cutoffdate60.getTime()), new java.sql.Date(cutoffdate31.getTime()), knownCustomers);
179                // 90 days
180                computeFor61To90DaysByBillingChartAndOrg(agingReportDao, new java.sql.Date(cutoffdate90.getTime()), new java.sql.Date(cutoffdate61.getTime()), knownCustomers);
181                // 120 days
182                computeFor91ToSYSPRDaysByBillingChartAndOrg(agingReportDao, new java.sql.Date(cutoffdate120.getTime()), new java.sql.Date(cutoffdate91.getTime()), knownCustomers);
183                // 120 + older
184                computeForSYSPRplus1orMoreDaysByBillingChartAndOrg(agingReportDao, null, new java.sql.Date(cutoffdate121.getTime()), knownCustomers);
185            }
186            if (reportOption.equalsIgnoreCase(ArConstants.CustomerAgingReportFields.ACCT) && StringUtils.isNotBlank(accountChartCode) && StringUtils.isNotBlank(accountNumber)) {
187                // 30 days
188                computeFor0To30DaysByAccount(agingReportDao, new java.sql.Date(cutoffdate30.getTime()), new java.sql.Date(reportRunDate.getTime()), knownCustomers);
189                // 60 days
190                computeFor31To60DaysByAccount(agingReportDao, new java.sql.Date(cutoffdate60.getTime()), new java.sql.Date(cutoffdate31.getTime()), knownCustomers);
191                // 90 days
192                computeFor61To90DaysByAccount(agingReportDao, new java.sql.Date(cutoffdate90.getTime()), new java.sql.Date(cutoffdate61.getTime()), knownCustomers);
193                // 120 days
194                computeFor91ToSYSPRDaysByAccount(agingReportDao, new java.sql.Date(cutoffdate120.getTime()), new java.sql.Date(cutoffdate91.getTime()), knownCustomers);
195                // 120 + older
196                computeForSYSPRplus1orMoreDaysByAccount(agingReportDao, null, new java.sql.Date(cutoffdate121.getTime()), knownCustomers);
197            }
198    
199            List<CustomerAgingReportDetail> results = new ArrayList<CustomerAgingReportDetail>();
200            for (CustomerAgingReportDetail detail : knownCustomers.values()) {
201                results.add(detail);
202            }
203    
204            return new CollectionIncomplete<CustomerAgingReportDetail>(results, (long) results.size());
205        }
206    
207    
208        /**
209         * @return a List of the CustomerInvoiceDetails associated with a given Account Number
210         */
211        @SuppressWarnings("unchecked")
212        public Collection<CustomerInvoiceDetail> getCustomerInvoiceDetailsByAccountNumber(String accountChartCode, String accountNumber) {
213            Map args = new HashMap();
214            args.put(KFSPropertyConstants.ACCOUNT_NUMBER, accountNumber);
215            args.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, accountChartCode);
216            return businessObjectService.findMatching(CustomerInvoiceDetail.class, args);
217        }
218    
219        /**
220         * @return a List of the names of fields which are marked in data dictionary as return fields.
221         */
222        @Override
223        public List getReturnKeys() {
224            return new ArrayList(fieldConversions.keySet());
225        }
226    
227        /**
228         * @return a List of the names of fields which are marked in data dictionary as return fields.
229         */
230        @SuppressWarnings("deprecation")
231        @Override
232        protected Properties getParameters(BusinessObject bo, Map fieldConversions, String lookupImpl, List pkNames) {
233            Properties parameters = new Properties();
234            parameters.put(KNSConstants.DISPATCH_REQUEST_PARAMETER, KNSConstants.RETURN_METHOD_TO_CALL);
235            parameters.put(KNSConstants.DOC_FORM_KEY, getDocFormKey());
236            parameters.put(KNSConstants.REFRESH_CALLER, lookupImpl);
237            if (getReferencesToRefresh() != null) {
238                parameters.put(KNSConstants.REFERENCES_TO_REFRESH, getReferencesToRefresh());
239            }
240    
241            for (Object o : getReturnKeys()) {
242                String fieldNm = (String) o;
243    
244                Object fieldVal = ObjectUtils.getPropertyValue(bo, fieldNm);
245                if (fieldVal == null) {
246                    fieldVal = KNSConstants.EMPTY_STRING;
247                }
248    
249                // Encrypt value if it is a secure field
250                if (fieldConversions.containsKey(fieldNm)) {
251                    fieldNm = (String) fieldConversions.get(fieldNm);
252                }
253    
254                if (SpringContext.getBean(BusinessObjectAuthorizationService.class).attributeValueNeedsToBeEncryptedOnFormsAndLinks(bo.getClass(), fieldNm)) {
255                    // try {
256                    // fieldVal = encryptionService.encrypt(fieldVal);
257                    // }
258                    // catch (GeneralSecurityException e) {
259                    // LOG.error("Exception while trying to encrypted value for inquiry framework.", e);
260                    // throw new RuntimeException(e);
261                    // }
262                }
263    
264                // need to format date in url
265                if (fieldVal instanceof Date) {
266                    DateFormatter dateFormatter = new DateFormatter();
267                    fieldVal = dateFormatter.format(fieldVal);
268                }
269    
270                parameters.put(fieldNm, fieldVal.toString());
271            }
272    
273            return parameters;
274        }
275    
276        /**
277         * This method performs the lookup and returns a collection of lookup items
278         * 
279         * @param lookupForm
280         * @param kualiLookupable
281         * @param resultTable
282         * @param bounded
283         * @return
284         */
285        @Override
286        public Collection performLookup(LookupForm lookupForm, Collection resultTable, boolean bounded) {
287            Collection displayList;
288    
289            // call search method to get results
290            if (bounded) {
291                displayList = getSearchResults(lookupForm.getFieldsForLookup());
292            } else {
293                displayList = getSearchResultsUnbounded(lookupForm.getFieldsForLookup());
294            }
295            // MJM get resultTable populated here
296    
297            HashMap<String, Class> propertyTypes = new HashMap<String, Class>();
298    
299            boolean hasReturnableRow = false;
300    
301            Person user = GlobalVariables.getUserSession().getPerson();
302    
303            try {
304                // iterate through result list and wrap rows with return url and action urls
305                for (Object aDisplayList : displayList) {
306                    BusinessObject element = (BusinessObject) aDisplayList;
307    
308                    BusinessObjectRestrictions businessObjectRestrictions = getBusinessObjectAuthorizationService().getLookupResultRestrictions(element, user);
309                    // String returnUrl = getReturnUrl(element, lookupForm.getFieldConversions(),
310                    // lookupForm.getLookupableImplServiceName());
311                    // String actionUrls = getActionUrls(element);
312                    String returnUrl = "www.bigfrickenRETURNurl";
313                    String actionUrls = "www.someACTIONurl";
314    
315    
316                    if (ObjectUtils.isNotNull(getColumns())) {
317                        List<Column> columns = getColumns();
318                        populateCutoffdateLabels();
319                        for (Object column : columns) {
320    
321                            Column col = (Column) column;
322                            Formatter formatter = col.getFormatter();
323    
324                            // pick off result column from result list, do formatting
325                            String propValue = KNSConstants.EMPTY_STRING;
326                            Object prop = ObjectUtils.getPropertyValue(element, col.getPropertyName());
327    
328                            // set comparator and formatter based on property type
329                            Class propClass = propertyTypes.get(col.getPropertyName());
330                            // if ( propClass == null ) {
331                            // try {
332                            // propClass = ObjectUtils.getPropertyType( element, col.getPropertyName(), getPersistenceStructureService()
333                            // );
334                            // propertyTypes.put( col.getPropertyName(), propClass );
335                            // } catch (Exception e) {
336                            // throw new RuntimeException("Cannot access PropertyType for property " + "'" + col.getPropertyName() + "'
337                            // " +
338                            // " on an instance of '" + element.getClass().getName() + "'.", e);
339                            // }
340                            // }
341    
342                            // formatters
343                            if (prop != null) {
344                                // for Booleans, always use BooleanFormatter
345                                if (prop instanceof Boolean) {
346                                    formatter = new BooleanFormatter();
347                                }
348    
349                                // for Dates, always use DateFormatter
350                                if (prop instanceof Date) {
351                                    formatter = new DateFormatter();
352                                }
353    
354                                // for collection, use the list formatter if a formatter hasn't been defined yet
355                                if (prop instanceof Collection && formatter == null) {
356                                    formatter = new CollectionFormatter();
357                                }
358    
359                                if (formatter != null) {
360                                    propValue = (String) formatter.format(prop);
361                                } else {
362                                    propValue = prop.toString();
363                                }
364                            }
365    
366                            // comparator
367                            col.setComparator(CellComparatorHelper.getAppropriateComparatorForPropertyClass(propClass));
368                            col.setValueComparator(CellComparatorHelper.getAppropriateValueComparatorForPropertyClass(propClass));
369    
370                            propValue = super.maskValueIfNecessary(element.getClass(), col.getPropertyName(), propValue, businessObjectRestrictions);
371                            col.setPropertyValue(propValue);
372    
373                            // add correct label for sysparam
374                            if (StringUtils.equals("unpaidBalance91toSYSPR", col.getPropertyName())) {
375                                col.setColumnTitle(cutoffdate91toSYSPRlabel);
376                            }
377                            if (StringUtils.equals("unpaidBalanceSYSPRplus1orMore", col.getPropertyName())) {
378                                col.setColumnTitle(cutoffdateSYSPRplus1orMorelabel);
379                            }
380    
381                            if (StringUtils.isNotBlank(propValue)) {
382                                // do not add link to the values in column "Customer Name"
383                                if (StringUtils.equals(customerNameLabel, col.getColumnTitle())) {
384                                    col.setPropertyURL("");
385                                } else {
386                                    col.setPropertyURL(getCustomerOpenItemReportUrl(element, col.getColumnTitle()));
387                                }
388                            }
389    
390                        }
391    
392                        ResultRow row = new ResultRow(columns, returnUrl, actionUrls);
393                        if (element instanceof PersistableBusinessObject) {
394                            row.setObjectId(((PersistableBusinessObject) element).getObjectId());
395                        }
396    
397                        boolean rowReturnable = isResultReturnable(element);
398                        row.setRowReturnable(rowReturnable);
399                        if (rowReturnable) {
400                            hasReturnableRow = true;
401                        }
402                        resultTable.add(row);
403                    }
404    
405    
406                    lookupForm.setHasReturnableRow(hasReturnableRow);
407                }
408            }
409            catch (Exception e) {
410                // do nothing, try block needed to make CustomerAgingReportLookupableHelperServiceImpl
411                // e.printStackTrace();
412            }
413    
414    
415            if (displayList.size() != 0) {
416                ((CustomerAgingReportForm) lookupForm).setTotal0to30(total0to30.toString());
417                ((CustomerAgingReportForm) lookupForm).setTotal31to60(total31to60.toString());
418                ((CustomerAgingReportForm) lookupForm).setTotal61to90(total61to90.toString());
419                ((CustomerAgingReportForm) lookupForm).setTotal91toSYSPR(total91toSYSPR.toString());
420                ((CustomerAgingReportForm) lookupForm).setTotalSYSPRplus1orMore(totalSYSPRplus1orMore.toString());
421            }
422    
423            return displayList;
424        }
425    
426        private void populateCutoffdateLabels() {
427            customerNameLabel = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(CustomerAgingReportDetail.class.getName()).getAttributeDefinition(KFSConstants.CustomerAgingReport.CUSTOMER_NAME).getLabel();
428            customerNumberLabel = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(CustomerAgingReportDetail.class.getName()).getAttributeDefinition(KFSConstants.CustomerOpenItemReport.CUSTOMER_NUMBER).getLabel();
429            cutoffdate30Label = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(CustomerAgingReportDetail.class.getName()).getAttributeDefinition(KFSConstants.CustomerAgingReport.UNPAID_BALANCE_0_TO_30).getLabel();
430            cutoffdate60Label = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(CustomerAgingReportDetail.class.getName()).getAttributeDefinition(KFSConstants.CustomerAgingReport.UNPAID_BALANCE_31_TO_60).getLabel();
431            cutoffdate90Label = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(CustomerAgingReportDetail.class.getName()).getAttributeDefinition(KFSConstants.CustomerAgingReport.UNPAID_BALANCE_61_TO_90).getLabel();
432        }
433    
434        private String getCustomerOpenItemReportUrl(BusinessObject bo, String columnTitle) {
435    
436            CustomerAgingReportDetail detail = (CustomerAgingReportDetail) bo;
437            String href = "arCustomerOpenItemReportLookup.do" + "?businessObjectClassName=org.kuali.kfs.module.ar.businessobject.CustomerOpenItemReportDetail" + "&returnLocation=&lookupableImplementaionServiceName=arCustomerOpenItemReportLookupable" + "&methodToCall=search&reportName=" + KFSConstants.CustomerOpenItemReport.OPEN_ITEM_REPORT_NAME + "&docFormKey=88888888&customerNumber=" +
438            // Customer Name, Customer Number
439                    detail.getCustomerNumber() + "&customerName=" + detail.getCustomerName();
440            // Report Option
441            href += "&reportOption=" + reportOption;
442            if (reportOption.equals(ArConstants.CustomerAgingReportFields.ACCT)) {
443                // Account Number
444                href += "&accountChartOfAccountsCode=" + accountChartCode + "&accountNumber=" + accountNumber;
445            } else {
446                // Chart Code, Organization Code
447                href += "&processingOrBillingChartCode=" + processingOrBillingChartCode + "&orgCode=" + orgCode;
448            }
449            // Report Run Date
450            DateFormatter dateFormatter = new DateFormatter();
451            href += "&reportRunDate=" + dateFormatter.format(reportRunDate).toString();
452    
453            if (StringUtils.equals(columnTitle, customerNumberLabel)) {
454                href += "&columnTitle=" + KFSConstants.CustomerOpenItemReport.ALL_DAYS;
455            }
456            else {
457                if (StringUtils.equals(columnTitle, cutoffdate30Label)) {
458                    href += "&startDate=" + dateFormatter.format(DateUtils.addDays(reportRunDate, -30)).toString() + "&endDate=" + dateFormatter.format(reportRunDate).toString();
459                } else if (StringUtils.equals(columnTitle, cutoffdate60Label)) {
460                    href += "&startDate=" + dateFormatter.format(DateUtils.addDays(reportRunDate, -60)).toString() + "&endDate=" + dateFormatter.format(DateUtils.addDays(reportRunDate, -31)).toString();
461                } else if (StringUtils.equals(columnTitle, cutoffdate90Label)) {
462                    href += "&startDate=" + dateFormatter.format(DateUtils.addDays(reportRunDate, -90)).toString() + "&endDate=" + dateFormatter.format(DateUtils.addDays(reportRunDate, -61)).toString();
463                } else if (StringUtils.equals(columnTitle, cutoffdate91toSYSPRlabel)) {
464                    href += "&startDate=" + dateFormatter.format(DateUtils.addDays(reportRunDate, -120)).toString() + "&endDate=" + dateFormatter.format(DateUtils.addDays(reportRunDate, -91)).toString();
465                } else if (StringUtils.equals(columnTitle, cutoffdateSYSPRplus1orMorelabel)) {
466                    href += "&startDate=" + "&endDate=" + dateFormatter.format(DateUtils.addDays(reportRunDate, -121)).toString();
467                    columnTitle = Integer.toString((Integer.parseInt(nbrDaysForLastBucket)) + 1) + " days and older";
468                }
469                href += "&columnTitle=" + columnTitle;
470            }
471    
472            return href;
473        }
474    
475        /**
476         * @param businessObjectService
477         */
478        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
479            this.businessObjectService = businessObjectService;
480        }
481    
482        /**
483         * This method...
484         * 
485         * @return
486         */
487        public DateTimeService getDateTimeService() {
488            if (dateTimeService == null) {
489                dateTimeService = SpringContext.getBean(DateTimeService.class);
490            }
491            return dateTimeService;
492        }
493    
494        /**
495         * This method...
496         * 
497         * @param dateTimeService
498         */
499        public void setDateTimeService(DateTimeService dateTimeService) {
500            this.dateTimeService = dateTimeService;
501        }
502    
503        /**
504         * Gets the total0to30 attribute.
505         * 
506         * @return Returns the total0to30.
507         */
508        public KualiDecimal getTotal0to30() {
509            return total0to30;
510        }
511    
512        /**
513         * Sets the total0to30 attribute value.
514         * 
515         * @param total0to30 The total0to30 to set.
516         */
517        public void setTotal0to30(KualiDecimal total0to30) {
518            this.total0to30 = total0to30;
519        }
520    
521        /**
522         * Gets the total31to60 attribute.
523         * 
524         * @return Returns the total31to60.
525         */
526        public KualiDecimal getTotal31to60() {
527            return total31to60;
528        }
529    
530        /**
531         * Sets the total31to60 attribute value.
532         * 
533         * @param total31to60 The total31to60 to set.
534         */
535        public void setTotal31to60(KualiDecimal total31to60) {
536            this.total31to60 = total31to60;
537        }
538    
539        /**
540         * Gets the total61to90 attribute.
541         * 
542         * @return Returns the total61to90.
543         */
544        public KualiDecimal getTotal61to90() {
545            return total61to90;
546        }
547    
548        /**
549         * Sets the total61to90 attribute value.
550         * 
551         * @param total61to90 The total61to90 to set.
552         */
553        public void setTotal61to90(KualiDecimal total61to90) {
554            this.total61to90 = total61to90;
555        }
556    
557        /**
558         * Gets the total91toSYSPR attribute.
559         * 
560         * @return Returns the total91toSYSPR.
561         */
562        public KualiDecimal getTotal91toSYSPR() {
563            return total91toSYSPR;
564        }
565    
566        /**
567         * Sets the total91toSYSPR attribute value.
568         * 
569         * @param total91toSYSPR The total91toSYSPR to set.
570         */
571        public void setTotal91toSYSPR(KualiDecimal total91toSYSPR) {
572            this.total91toSYSPR = total91toSYSPR;
573        }
574    
575        /**
576         * Gets the totalSYSPRplus1orMore attribute.
577         * 
578         * @return Returns the totalSYSPRplus1orMore.
579         */
580        public KualiDecimal getTotalSYSPRplus1orMore() {
581            return totalSYSPRplus1orMore;
582        }
583    
584        /**
585         * Sets the totalSYSPRplus1orMore attribute value.
586         * 
587         * @param totalSYSPRplus1orMore The totalSYSPRplus1orMore to set.
588         */
589        public void setTotalSYSPRplus1orMore(KualiDecimal totalSYSPRplus1orMore) {
590            this.totalSYSPRplus1orMore = totalSYSPRplus1orMore;
591        }
592    
593        /**
594         * 
595         * This method...
596         * @param agingReportDao
597         * @param begin
598         * @param end
599         * @param knownCustomers
600         */
601        private void computeFor0To30DaysByProcessingChartAndOrg(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
602            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
603            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
604            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
605            Set<String> customerIds = invAmountDays.keySet();
606            for (String customer : customerIds) {
607                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
608                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
609                agingReportDetail.setUnpaidBalance0to30(amount);
610                total0to30 = total0to30.add(amount);
611            }
612        }
613    
614        /**
615         * 
616         * This method...
617         * @param agingReportDao
618         * @param begin
619         * @param end
620         * @param knownCustomers
621         */
622        private void computeFor31To60DaysByProcessingChartAndOrg(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
623            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
624            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
625            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
626            Set<String> customerIds = invAmountDays.keySet();
627            for (String customer : customerIds) {
628                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
629                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
630                agingReportDetail.setUnpaidBalance31to60(amount);
631                total31to60 = total31to60.add(amount);
632            }
633        }
634    
635        /**
636         * 
637         * This method...
638         * @param agingReportDao
639         * @param begin
640         * @param end
641         * @param knownCustomers
642         */
643        private void computeFor61To90DaysByProcessingChartAndOrg(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
644            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
645            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
646            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
647            Set<String> customerIds = invAmountDays.keySet();
648            for (String customer : customerIds) {
649                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
650                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
651                agingReportDetail.setUnpaidBalance61to90(amount);
652                total61to90 = total61to90.add(amount);
653            }
654        }
655    
656        /**
657         * 
658         * This method...
659         * @param agingReportDao
660         * @param begin
661         * @param end
662         * @param knownCustomers
663         */
664        private void computeFor91ToSYSPRDaysByProcessingChartAndOrg(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
665            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
666            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
667            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
668            Set<String> customerIds = invAmountDays.keySet();
669            for (String customer : customerIds) {
670                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
671                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
672                agingReportDetail.setUnpaidBalance91toSYSPR(amount);
673                total91toSYSPR = total91toSYSPR.add(amount);
674            }
675        }
676    
677        /**
678         * 
679         * This method...
680         * @param agingReportDao
681         * @param begin
682         * @param end
683         * @param knownCustomers
684         */
685        private void computeForSYSPRplus1orMoreDaysByProcessingChartAndOrg(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
686            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
687            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
688            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByProcessingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
689            Set<String> customerIds = invAmountDays.keySet();
690            for (String customer : customerIds) {
691                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
692                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
693                agingReportDetail.setUnpaidBalanceSYSPRplus1orMore(amount);
694                totalSYSPRplus1orMore = totalSYSPRplus1orMore.add(amount);
695            }
696        }
697    
698        /**
699         * 
700         * This method...
701         * @param agingReportDao
702         * @param begin
703         * @param end
704         * @param knownCustomers
705         */
706        private void computeFor0To30DaysByBillingChartAndOrg(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
707            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
708            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
709            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
710            Set<String> customerIds = invAmountDays.keySet();
711            for (String customer : customerIds) {
712                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
713                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
714                agingReportDetail.setUnpaidBalance0to30(amount);
715                total0to30 = total0to30.add(amount);
716            }
717        }
718    
719        /**
720         * 
721         * This method...
722         * @param agingReportDao
723         * @param begin
724         * @param end
725         * @param knownCustomers
726         */
727        private void computeFor31To60DaysByBillingChartAndOrg(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
728            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
729            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
730            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
731            Set<String> customerIds = invAmountDays.keySet();
732            for (String customer : customerIds) {
733                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
734                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
735                agingReportDetail.setUnpaidBalance31to60(amount);
736                total31to60 = total31to60.add(amount);
737            }
738        }
739    
740        /**
741         * 
742         * This method...
743         * @param agingReportDao
744         * @param begin
745         * @param end
746         * @param knownCustomers
747         */
748        private void computeFor61To90DaysByBillingChartAndOrg(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
749            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
750            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
751            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
752            Set<String> customerIds = invAmountDays.keySet();
753            for (String customer : customerIds) {
754                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
755                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
756                agingReportDetail.setUnpaidBalance61to90(amount);
757                total61to90 = total61to90.add(amount);
758            }
759        }
760    
761        /**
762         * 
763         * This method...
764         * @param agingReportDao
765         * @param begin
766         * @param end
767         * @param knownCustomers
768         */
769        private void computeFor91ToSYSPRDaysByBillingChartAndOrg(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
770            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
771            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
772            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
773            Set<String> customerIds = invAmountDays.keySet();
774            for (String customer : customerIds) {
775                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
776                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
777                agingReportDetail.setUnpaidBalance91toSYSPR(amount);
778                total91toSYSPR = total91toSYSPR.add(amount);
779            }
780        }
781    
782        /**
783         * 
784         * This method...
785         * @param agingReportDao
786         * @param begin
787         * @param end
788         * @param knownCustomers
789         */
790        private void computeForSYSPRplus1orMoreDaysByBillingChartAndOrg(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
791            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
792            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
793            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByBillingChartAndOrg(processingOrBillingChartCode, orgCode, begin, end);
794            Set<String> customerIds = invAmountDays.keySet();
795            for (String customer : customerIds) {
796                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
797                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
798                agingReportDetail.setUnpaidBalanceSYSPRplus1orMore(amount);
799                totalSYSPRplus1orMore = totalSYSPRplus1orMore.add(amount);
800            }
801        }
802    
803        /**
804         * 
805         * This method...
806         * @param agingReportDao
807         * @param begin
808         * @param end
809         * @param knownCustomers
810         */
811        private void computeFor0To30DaysByAccount(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
812            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByAccount(accountChartCode, accountNumber, begin, end);
813            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByAccount(accountChartCode, accountNumber, begin, end);
814            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByAccount(accountChartCode, accountNumber, begin, end);
815            Set<String> customerIds = invAmountDays.keySet();
816            for (String customer : customerIds) {
817                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
818                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
819                agingReportDetail.setUnpaidBalance0to30(amount);
820                total0to30 = total0to30.add(amount);
821            }
822        }
823    
824        /**
825         * 
826         * This method...
827         * @param agingReportDao
828         * @param begin
829         * @param end
830         * @param knownCustomers
831         */
832        private void computeFor31To60DaysByAccount(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
833            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByAccount(accountChartCode, accountNumber, begin, end);
834            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByAccount(accountChartCode, accountNumber, begin, end);
835            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByAccount(accountChartCode, accountNumber, begin, end);
836            Set<String> customerIds = invAmountDays.keySet();
837            for (String customer : customerIds) {
838                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
839                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
840                agingReportDetail.setUnpaidBalance31to60(amount);
841                total31to60 = total31to60.add(amount);
842            }
843        }
844    
845        /**
846         * 
847         * This method...
848         * @param agingReportDao
849         * @param begin
850         * @param end
851         * @param knownCustomers
852         */
853        private void computeFor61To90DaysByAccount(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
854            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByAccount(accountChartCode, accountNumber, begin, end);
855            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByAccount(accountChartCode, accountNumber, begin, end);
856            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByAccount(accountChartCode, accountNumber, begin, end);
857            Set<String> customerIds = invAmountDays.keySet();
858            for (String customer : customerIds) {
859                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
860                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
861                agingReportDetail.setUnpaidBalance61to90(amount);
862                total61to90 = total61to90.add(amount);
863            }
864        }
865    
866        /**
867         * 
868         * This method...
869         * @param agingReportDao
870         * @param begin
871         * @param end
872         * @param knownCustomers
873         */
874        private void computeFor91ToSYSPRDaysByAccount(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
875            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByAccount(accountChartCode, accountNumber, begin, end);
876            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByAccount(accountChartCode, accountNumber, begin, end);
877            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByAccount(accountChartCode, accountNumber, begin, end);
878            Set<String> customerIds = invAmountDays.keySet();
879            for (String customer : customerIds) {
880                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
881                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
882                agingReportDetail.setUnpaidBalance91toSYSPR(amount);
883                total91toSYSPR = total91toSYSPR.add(amount);
884            }
885        }
886    
887        /**
888         * 
889         * This method...
890         * @param agingReportDao
891         * @param begin
892         * @param end
893         * @param knownCustomers
894         */
895        private void computeForSYSPRplus1orMoreDaysByAccount(CustomerAgingReportDao agingReportDao, java.sql.Date begin, java.sql.Date end, Map<String, CustomerAgingReportDetail> knownCustomers) {
896            HashMap<String, KualiDecimal> invAmountDays = agingReportDao.findInvoiceAmountByAccount(accountChartCode, accountNumber, begin, end);
897            HashMap<String, KualiDecimal> appliedAmountDays = agingReportDao.findAppliedAmountByAccount(accountChartCode, accountNumber, begin, end);
898            HashMap<String, KualiDecimal> discountAmountDays = agingReportDao.findDiscountAmountByAccount(accountChartCode, accountNumber, begin, end);
899            Set<String> customerIds = invAmountDays.keySet();
900            for (String customer : customerIds) {
901                CustomerAgingReportDetail agingReportDetail = pickCustomerAgingReportDetail(knownCustomers, customer);
902                KualiDecimal amount = (replaceNull(invAmountDays, customer).subtract(replaceNull(discountAmountDays, customer))).subtract(replaceNull(appliedAmountDays, customer));
903                agingReportDetail.setUnpaidBalanceSYSPRplus1orMore(amount);
904                totalSYSPRplus1orMore = totalSYSPRplus1orMore.add(amount);
905            }
906        }
907    
908        /**
909         * 
910         * This method...
911         * @param knownCustomers
912         * @param customer
913         * @return
914         */
915        private CustomerAgingReportDetail pickCustomerAgingReportDetail(Map<String, CustomerAgingReportDetail> knownCustomers, String customer) {
916            CustomerAgingReportDetail agingReportDetail = null;
917            if ((agingReportDetail = knownCustomers.get(customer)) == null) {
918                agingReportDetail = new CustomerAgingReportDetail();
919                agingReportDetail.setCustomerNumber(customer.substring(0, customer.indexOf('-')));
920                agingReportDetail.setCustomerName(customer.substring(customer.indexOf('-') + 1));
921                knownCustomers.put(customer, agingReportDetail);
922            }
923            return agingReportDetail;
924        }
925    
926        /**
927         * 
928         * This method...
929         * @param amountMap
930         * @param customer
931         * @return
932         */
933        private KualiDecimal replaceNull(HashMap<String, KualiDecimal> amountMap, String customer) {
934            return amountMap.get(customer) != null ? amountMap.get(customer) : KualiDecimal.ZERO;
935        }
936    
937    }