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.document.service.impl;
017    
018    import java.sql.Timestamp;
019    import java.text.DateFormat;
020    import java.text.ParseException;
021    import java.text.SimpleDateFormat;
022    import java.util.ArrayList;
023    import java.util.Calendar;
024    import java.util.Collection;
025    import java.util.Date;
026    import java.util.Hashtable;
027    import java.util.Iterator;
028    import java.util.List;
029    import java.util.Map;
030    
031    import org.apache.commons.lang.StringUtils;
032    import org.kuali.kfs.module.ar.ArConstants;
033    import org.kuali.kfs.module.ar.businessobject.AccountsReceivableDocumentHeader;
034    import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail;
035    import org.kuali.kfs.module.ar.businessobject.CustomerOpenItemReportDetail;
036    import org.kuali.kfs.module.ar.businessobject.NonAppliedHolding;
037    import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument;
038    import org.kuali.kfs.module.ar.document.PaymentApplicationDocument;
039    import org.kuali.kfs.module.ar.document.dataaccess.AccountsReceivableDocumentHeaderDao;
040    import org.kuali.kfs.module.ar.document.dataaccess.CustomerInvoiceDetailDao;
041    import org.kuali.kfs.module.ar.document.dataaccess.NonAppliedHoldingDao;
042    import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService;
043    import org.kuali.kfs.module.ar.document.service.CustomerOpenItemReportService;
044    import org.kuali.kfs.sys.KFSConstants;
045    import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader;
046    import org.kuali.kfs.sys.context.SpringContext;
047    import org.kuali.kfs.sys.document.dataaccess.FinancialSystemDocumentHeaderDao;
048    import org.kuali.rice.kew.exception.WorkflowException;
049    import org.kuali.rice.kim.bo.Person;
050    import org.kuali.rice.kns.exception.InfrastructureException;
051    import org.kuali.rice.kns.exception.UnknownDocumentIdException;
052    import org.kuali.rice.kns.service.DateTimeService;
053    import org.kuali.rice.kns.service.DocumentService;
054    import org.kuali.rice.kns.util.GlobalVariables;
055    import org.kuali.rice.kns.util.KualiDecimal;
056    import org.kuali.rice.kns.util.ObjectUtils;
057    import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
058    import org.kuali.rice.kns.workflow.service.WorkflowDocumentService;
059    import org.springframework.transaction.annotation.Transactional;
060    
061    @Transactional
062    public class CustomerOpenItemReportServiceImpl implements CustomerOpenItemReportService {
063    
064        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CustomerOpenItemReportServiceImpl.class);
065        
066        private AccountsReceivableDocumentHeaderDao accountsReceivableDocumentHeaderDao;
067        private WorkflowDocumentService workflowDocumentService;
068        private CustomerInvoiceDocumentService customerInvoiceDocumentService;
069        private FinancialSystemDocumentHeaderDao financialSystemDocumentHeaderDao;
070        private DocumentService documentService;
071        private DateTimeService dateTimeService;
072        private CustomerInvoiceDetailDao customerInvoiceDetailDao;
073        private NonAppliedHoldingDao nonAppliedHoldingDao;
074    
075        /**
076         * This method populates CustomerOpenItemReportDetails (Customer History Report).
077         * 
078         * @param customerNumber
079         */
080        public List getPopulatedReportDetails(String customerNumber) {
081            List results = new ArrayList();
082    
083            Collection arDocumentHeaders = accountsReceivableDocumentHeaderDao.getARDocumentHeadersByCustomerNumber(customerNumber);
084            if (arDocumentHeaders.size() == 0)
085                return results;
086    
087            Person user = GlobalVariables.getUserSession().getPerson();
088    
089            List finSysDocHeaderIds = new ArrayList();
090            List invoiceIds = new ArrayList();
091            List paymentApplicationIds = new ArrayList();
092            List unappliedHoldingIds = new ArrayList();
093    
094            Hashtable details = new Hashtable();
095            KualiWorkflowDocument workflowDocument;
096    
097    
098            for (Iterator itr = arDocumentHeaders.iterator(); itr.hasNext();) {
099                AccountsReceivableDocumentHeader documentHeader = (AccountsReceivableDocumentHeader) itr.next();
100                CustomerOpenItemReportDetail detail = new CustomerOpenItemReportDetail();
101    
102                // populate workflow document
103                try {
104                    workflowDocument = workflowDocumentService.createWorkflowDocument(Long.valueOf(documentHeader.getDocumentNumber()), user);
105                }
106                catch (WorkflowException e) {
107                    throw new UnknownDocumentIdException("No document found for documentHeaderId '" + documentHeader.getDocumentNumber() + "'", e);
108                }
109    
110                // do not display not approved documents
111                Date approvedDate = getSqlDate(workflowDocument.getRouteHeader().getDateApproved());
112                if (ObjectUtils.isNull(approvedDate)) {
113                    continue;
114                }
115    
116                // Document Type
117                String documentType = workflowDocument.getDocumentType();
118                detail.setDocumentType(documentType);
119    
120                // Document Number
121                String documentNumber = documentHeader.getDocumentNumber();
122                detail.setDocumentNumber(documentNumber);
123    
124                if (documentType.equals("INV"))
125                    invoiceIds.add(documentNumber);
126                else {
127                    // Approved Date -> for invoices Due Date, for all other documents Approved Date
128                    detail.setDueApprovedDate(approvedDate);
129    
130                    if (documentType.equals("APP"))
131                        paymentApplicationIds.add(documentNumber);
132                    else
133                        finSysDocHeaderIds.add(documentNumber);
134                }
135                details.put(documentNumber, detail);
136            }
137    
138            // add Unapplied Payment Applications
139            Collection<NonAppliedHolding> arNonAppliedHoldings = nonAppliedHoldingDao.getNonAppliedHoldingsForCustomer(customerNumber);
140            for (NonAppliedHolding nonAppliedHolding : arNonAppliedHoldings) {
141                // populate workflow document
142                try {
143                    workflowDocument = workflowDocumentService.createWorkflowDocument(Long.valueOf(nonAppliedHolding.getReferenceFinancialDocumentNumber()), user);
144                }
145                catch (WorkflowException e) {
146                    throw new UnknownDocumentIdException("No document found for documentHeaderId '" + nonAppliedHolding.getReferenceFinancialDocumentNumber() + "'", e);
147                }
148    
149                CustomerOpenItemReportDetail detail = new CustomerOpenItemReportDetail();
150                detail.setDocumentType("APP");
151                detail.setDocumentNumber(nonAppliedHolding.getReferenceFinancialDocumentNumber());
152                Date documentApprovedDate = getSqlDate(workflowDocument.getRouteHeader().getDateApproved());
153                detail.setDueApprovedDate(documentApprovedDate);
154                details.put(nonAppliedHolding.getReferenceFinancialDocumentNumber(), detail);
155                unappliedHoldingIds.add(nonAppliedHolding.getReferenceFinancialDocumentNumber());
156            }
157            
158            // for invoices
159            if (invoiceIds.size() > 0)
160                populateReportDetailsForInvoices(invoiceIds, results, details);
161    
162            // for payment applications
163            if (paymentApplicationIds.size() > 0) {
164                try {
165                    populateReportDetailsForPaymentApplications(paymentApplicationIds, results, details);
166                } catch(WorkflowException w) {
167                    LOG.error("WorkflowException while populating report details for PaymentApplicationDocument", w);
168                }
169            }
170            
171            // for unapplied payment applications
172            if (unappliedHoldingIds.size() > 0) {
173                try {
174                    populateReportDetailsForUnappliedPaymentApplications(unappliedHoldingIds, results, details);
175                } catch(WorkflowException w) {
176                    LOG.error("WorkflowException while populating report details for PaymentApplicationDocument", w);
177                }
178            }
179    
180            // for all other documents
181            if (finSysDocHeaderIds.size() > 0)
182                populateReportDetails(finSysDocHeaderIds, results, details);
183    
184            return results;
185        }
186    
187        /**
188         * This method populates CustomerOpenItemReportDetails for CustomerInvoiceDocuments (Customer History Report).
189         * 
190         * @param finSysDocHeaderIds <=> documentNumbers of CustomerInvoiceDocuments
191         * @param results <=> CustomerOpenItemReportDetails to display in the report
192         * @param details <=> <key = documentNumber, value = customerOpenItemReportDetail>
193         */
194        protected void populateReportDetailsForInvoices(List invoiceIds, List results, Hashtable details) {
195            CustomerInvoiceDocumentService customerInvoiceDocumentService = SpringContext.getBean(CustomerInvoiceDocumentService.class);
196            Collection invoices = getDocuments(CustomerInvoiceDocument.class, invoiceIds);
197    
198            for (Iterator itr = invoices.iterator(); itr.hasNext();) {
199                CustomerInvoiceDocument invoice = (CustomerInvoiceDocument) itr.next();
200                String documentNumber = invoice.getDocumentNumber();
201    
202                CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(documentNumber);
203    
204                // Document Description
205                String documentDescription = invoice.getDocumentHeader().getDocumentDescription();
206                    if (ObjectUtils.isNotNull(documentDescription))
207                        detail.setDocumentDescription(documentDescription);
208                    else
209                        detail.setDocumentDescription("");
210    
211                // Billing Date
212                detail.setBillingDate(invoice.getBillingDate());
213    
214                // Due/Approved Date -> for invoice it is Due Date, and for all other documents Approved Date
215                detail.setDueApprovedDate(invoice.getInvoiceDueDate());
216    
217                // Document Payment Amount
218                detail.setDocumentPaymentAmount(invoice.getDocumentHeader().getFinancialDocumentTotalAmount());
219    
220                // Unpaid/Unapplied Amount
221                detail.setUnpaidUnappliedAmount(customerInvoiceDocumentService.getOpenAmountForCustomerInvoiceDocument(invoice));
222    
223                results.add(detail);
224            }
225        }
226    
227        /**
228         * This method populates CustomerOpenItemReportDetails for PaymentApplicationDocuments (Customer History Report).
229         * 
230         * @param paymentApplicationIds <=> documentNumbers of PaymentApplicationDocuments
231         * @param results <=> CustomerOpenItemReportDetails to display in the report
232         * @param details <=> <key = documentNumber, value = customerOpenItemReportDetail>
233         */
234        protected void populateReportDetailsForPaymentApplications(List paymentApplicationIds, List results, Hashtable details) throws WorkflowException {
235            Collection paymentApplications = getDocuments(PaymentApplicationDocument.class, paymentApplicationIds);
236    
237            for (Iterator itr = paymentApplications.iterator(); itr.hasNext();) {
238                PaymentApplicationDocument paymentApplication = (PaymentApplicationDocument) itr.next();
239                String documentNumber = paymentApplication.getDocumentNumber();
240    
241                CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(documentNumber);
242    
243                // populate Document Description
244                String documentDescription = paymentApplication.getDocumentHeader().getDocumentDescription();
245                if (ObjectUtils.isNotNull(documentDescription))
246                    detail.setDocumentDescription(documentDescription);
247                else
248                    detail.setDocumentDescription("");
249    
250                // populate Document Payment Amount
251                detail.setDocumentPaymentAmount(paymentApplication.getDocumentHeader().getFinancialDocumentTotalAmount().negated());
252                
253                // populate Unpaid/Unapplied Amount if the customer number is the same
254                if (ObjectUtils.isNotNull(paymentApplication.getNonAppliedHolding())) {
255                    if (paymentApplication.getNonAppliedHolding().getCustomerNumber().equals(paymentApplication.getAccountsReceivableDocumentHeader().getCustomerNumber())) {
256                        detail.setUnpaidUnappliedAmount(paymentApplication.getNonAppliedHolding().getAvailableUnappliedAmount().negated()); 
257                    }
258                }
259                
260                results.add(detail);
261            }
262        }
263    
264        /**
265         * This method populates CustomerOpenItemReportDetails for UnappliedPaymentApplicationDocuments (Customer History Report).
266         * 
267         * @param unappliedHoldingIds <=> documentNumbers of UnappliedPaymentApplicationDocuments
268         * @param results <=> CustomerOpenItemReportDetails to display in the report
269         * @param details <=> <key = documentNumber, value = customerOpenItemReportDetail>
270         */
271        protected void populateReportDetailsForUnappliedPaymentApplications(List unappliedHoldingIds, List results, Hashtable details) throws WorkflowException {
272            Collection paymentApplications = getDocuments(PaymentApplicationDocument.class, unappliedHoldingIds);
273    
274            for (Iterator itr = paymentApplications.iterator(); itr.hasNext();) {
275                PaymentApplicationDocument paymentApplication = (PaymentApplicationDocument) itr.next();
276                String documentNumber = paymentApplication.getDocumentNumber();
277    
278                if ((paymentApplication.getNonAppliedHolding().getCustomerNumber().equals(paymentApplication.getAccountsReceivableDocumentHeader().getCustomerNumber()))) {
279                    continue;
280                }
281                
282                CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(documentNumber);
283    
284                // populate Document Description
285                String documentDescription = paymentApplication.getDocumentHeader().getDocumentDescription();
286                if (ObjectUtils.isNotNull(documentDescription))
287                    detail.setDocumentDescription(documentDescription);
288                else
289                    detail.setDocumentDescription("");
290    
291                // populate Document Payment Amount
292                detail.setDocumentPaymentAmount(KualiDecimal.ZERO);
293    
294                // populate Unpaid/Unapplied Amount if the customer number is not the same
295                detail.setUnpaidUnappliedAmount(paymentApplication.getNonAppliedHoldingAmount().negated());
296    
297                results.add(detail);
298            }
299        }
300    
301        /**
302         * This method populates CustomerOpenItemReportDetails for CustomerCreditMemoDocuments and WriteOffDocuments <=> all documents
303         * but CustomerInvoiceDocument and PaymentApplicationDocument (Customer History Report).
304         * 
305         * @param finSysDocHeaderIds <=> documentNumbers of FinancialSystemDocumentHeaders
306         * @param results <=> CustomerOpenItemReportDetails to display in the report
307         * @param details <=> <key = documentNumber, value = customerOpenItemReportDetail>
308         */
309        public void populateReportDetails(List finSysDocHeaderIds, List results, Hashtable details) {
310            Collection financialSystemDocHeaders = financialSystemDocumentHeaderDao.getByDocumentNumbers(finSysDocHeaderIds);
311    
312            for (Iterator itr = financialSystemDocHeaders.iterator(); itr.hasNext();) {
313                FinancialSystemDocumentHeader fsDocumentHeader = (FinancialSystemDocumentHeader) itr.next();
314                String documentNumber = fsDocumentHeader.getDocumentNumber();
315    
316                CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(documentNumber);
317    
318                // populate Document Description
319                String documentDescription = fsDocumentHeader.getDocumentDescription();
320                if (ObjectUtils.isNotNull(documentDescription))
321                    detail.setDocumentDescription(documentDescription);
322                else
323                    detail.setDocumentDescription("");
324    
325                // populate Document Payment Amount
326                detail.setDocumentPaymentAmount(fsDocumentHeader.getFinancialDocumentTotalAmount().negated());
327    
328                // Unpaid/Unapplied Amount
329                detail.setUnpaidUnappliedAmount(KualiDecimal.ZERO);
330    
331                results.add(detail);
332            }
333        }
334    
335        /**
336         * This method returns collection of documents of type classToSearchFrom Note: can be used for documents only, not for
337         * *DocumentHeaders @param documentNumbers
338         */
339        public Collection getDocuments(Class classToSearchFrom, List documentNumbers) {
340            List docs;
341    
342            try {
343                docs = documentService.getDocumentsByListOfDocumentHeaderIds(classToSearchFrom, documentNumbers);
344            }
345            catch (WorkflowException e) {
346                throw new InfrastructureException("Unable to retrieve documents", e);
347            }
348            return docs;
349        }
350    
351        protected Date getSqlDate(Calendar cal) {
352            Date sqlDueDate = null;
353    
354            if (ObjectUtils.isNull(cal))
355                return sqlDueDate;
356            try {
357                sqlDueDate = dateTimeService.convertToSqlDate(new Timestamp(cal.getTime().getTime()));
358            }
359            catch (ParseException e) {
360                // TODO: throw an error here, but don't die
361            }
362            return sqlDueDate;
363        }
364    
365        /**
366         * This method populates CustomerOpenItemReportDetails (Customer Open Item Report)
367         * 
368         * @param urlParameters
369         */
370        public List getPopulatedReportDetails(Map urlParameters) {
371            List results = new ArrayList();
372            
373            // get arDocumentHeaders
374            Collection<AccountsReceivableDocumentHeader> arDocumentHeaders = getARDocumentHeaders(urlParameters);
375            if (arDocumentHeaders.size() == 0)
376                return results;
377            
378            // get ids of arDocumentHeaders
379            List<String> arDocumentHeaderIds = new ArrayList<String>();
380            for (AccountsReceivableDocumentHeader arDocHeader : arDocumentHeaders) {
381                arDocumentHeaderIds.add(arDocHeader.getDocumentNumber());
382            }
383            
384            // get invoices
385            String reportOption = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.REPORT_OPTION))[0];
386            Collection<CustomerInvoiceDocument> invoices;
387            Collection<CustomerInvoiceDetail> details = null;
388            if (StringUtils.equals(reportOption, ArConstants.CustomerAgingReportFields.ACCT)) {
389                String accountNumber = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.ACCOUNT_NUMBER))[0];
390                details = customerInvoiceDetailDao.getCustomerInvoiceDetailsByAccountNumberByInvoiceDocumentNumbers(accountNumber, arDocumentHeaderIds);
391                invoices = getInvoicesByAccountNumberByDocumentIds(accountNumber, arDocumentHeaderIds, details);
392            }
393            else {
394                invoices = getDocuments(CustomerInvoiceDocument.class, arDocumentHeaderIds);
395            }
396            if (ObjectUtils.isNull(invoices) | invoices.size()==0 )
397                return results;
398            
399            List<CustomerInvoiceDocument> selectedInvoices = new ArrayList();
400    
401            String columnTitle = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.COLUMN_TITLE))[0];
402            DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
403            
404            java.util.Date reportRunDate= null;
405            java.util.Date beginDate = null;
406            java.util.Date endDate = null;
407            try {
408                reportRunDate = dateFormat.parse(((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.REPORT_RUN_DATE))[0]);
409                if (!StringUtils.equals(columnTitle, KFSConstants.CustomerOpenItemReport.ALL_DAYS)) {
410                    endDate = dateFormat.parse(((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.REPORT_END_DATE))[0]);
411                    String strBeginDate = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.REPORT_BEGIN_DATE))[0];
412                    if (StringUtils.isNotEmpty(strBeginDate))
413                        beginDate = dateFormat.parse(strBeginDate);
414                }
415            }
416            catch (ParseException e) {
417                e.printStackTrace();
418            }
419            
420            // Billing Organization
421            if (StringUtils.equals(reportOption, ArConstants.CustomerAgingReportFields.BILLING_ORG)) {
422                // All days
423                // 1. invoice open amount > 0
424                // 2. billingDate <= reportRunDate
425                // 3. billByChartOfAccountsCode = processingOrBillingChartCode
426                // 4. billbyOrganizationCode = orgCode
427                String chartCode = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.PROCESSING_OR_BILLING_CHART_CODE))[0];
428                String orgCode = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.ORGANIZATION_CODE))[0];
429                if (StringUtils.equals(columnTitle, KFSConstants.CustomerOpenItemReport.ALL_DAYS)) {
430                    for (CustomerInvoiceDocument invoice:invoices) {
431                        // get only invoices with open amounts
432                        if (ObjectUtils.isNull(invoice.getClosedDate())&& ObjectUtils.isNotNull(invoice.getBillingDate()) && !reportRunDate.before(invoice.getBillingDate()) && StringUtils.equals(chartCode, invoice.getBillByChartOfAccountCode()) && StringUtils.equals(orgCode, invoice.getBilledByOrganizationCode()) )
433                            selectedInvoices.add(invoice);
434                    }
435                }
436                // *days
437                // 1. invoice open amount > 0
438                // 2. beginDate <= invoice billing date <= endDate
439                // 3. billByChartOfAccountsCode = chartCode
440                // 4. billbyOrganizationCode = orgCode
441                else {
442                    for (CustomerInvoiceDocument invoice:invoices) {
443                        if (ObjectUtils.isNull(invoice.getClosedDate())&& ObjectUtils.isNotNull(invoice.getBillingDate()) && StringUtils.equals(chartCode, invoice.getBillByChartOfAccountCode()) && StringUtils.equals(orgCode, invoice.getBilledByOrganizationCode()) )
444                            if ( (ObjectUtils.isNotNull(beginDate) && !beginDate.after(invoice.getBillingDate()) && !endDate.before(invoice.getBillingDate())) || (ObjectUtils.isNull(beginDate) && !endDate.before(invoice.getBillingDate())) )
445                                selectedInvoices.add(invoice);
446                    }
447                }
448            } 
449            // Processing Organization or Account
450            else {
451                // All days
452                // 1. invoice open amount > 0
453                // 2. invoice billing dates <= reportRunDate
454                if (StringUtils.equals(columnTitle, KFSConstants.CustomerOpenItemReport.ALL_DAYS)) {
455                    for (CustomerInvoiceDocument invoice:invoices) {
456                        if (ObjectUtils.isNull(invoice.getClosedDate()) && ObjectUtils.isNotNull(invoice.getBillingDate())&& !reportRunDate.before(invoice.getBillingDate()))
457                            selectedInvoices.add(invoice);
458                    }
459                }
460                // *days
461                // 1. invoice open amount > 0
462                // 2. beginDate <= invoice billing date <= endDate
463                else {
464                    for (CustomerInvoiceDocument invoice:invoices) {
465                        if (ObjectUtils.isNull(invoice.getClosedDate())&& ObjectUtils.isNotNull(invoice.getBillingDate()))
466                            if ( (ObjectUtils.isNotNull(beginDate) && !beginDate.after(invoice.getBillingDate()) && !endDate.before(invoice.getBillingDate())) || (ObjectUtils.isNull(beginDate) && !endDate.before(invoice.getBillingDate())) )
467                                selectedInvoices.add(invoice);
468                    }  
469                }
470            }
471    
472            if (selectedInvoices.size() == 0)
473                return results;
474            
475            if (StringUtils.equals(reportOption, ArConstants.CustomerAgingReportFields.ACCT))
476                populateReporDetails(selectedInvoices,results,details);
477            else
478                populateReportDetails(selectedInvoices,results);
479            
480            return results;
481        }
482    
483        /**
484         * This method retrieves ARDocumentHeader objects for "Customer Open Item Report"
485         * 
486         * @param urlParameters
487         * @return ARDocumentHeader objects meeting the search criteria
488         */
489        protected Collection getARDocumentHeaders(Map urlParameters) {
490            Collection arDocumentHeaders;
491    
492            String reportOption = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.REPORT_OPTION))[0];
493            String customerNumber = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.CUSTOMER_NUMBER))[0];
494    
495            if (StringUtils.equals(reportOption, ArConstants.CustomerAgingReportFields.PROCESSING_ORG)) {
496                String processingChartCode = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.PROCESSING_OR_BILLING_CHART_CODE))[0];
497                String processingOrganizationCode = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.ORGANIZATION_CODE))[0];
498                arDocumentHeaders = accountsReceivableDocumentHeaderDao.getARDocumentHeadersByCustomerNumberByProcessingOrgCodeAndChartCode(customerNumber, processingChartCode, processingOrganizationCode);
499            } // reportOption is "Billing Organization" or "Account"
500            else {
501                arDocumentHeaders = accountsReceivableDocumentHeaderDao.getARDocumentHeadersByCustomerNumber(customerNumber);
502            }
503            return arDocumentHeaders;
504        }
505        
506        /*
507         * This method gets called only if reportOption is Account
508         * Gets invoices based on the selected invoice details <=> invoice details meeting search criteria i.e. the accountNumber and the list of documentIds
509         * @param accountNumber
510         * @param arDocumentHeaderIds
511         * @param details (will get populated here)
512         * @return invoices
513         */
514        protected Collection<CustomerInvoiceDocument> getInvoicesByAccountNumberByDocumentIds(String accountNumber, List arDocumentHeaderIds, Collection<CustomerInvoiceDetail> details) {
515            Collection<CustomerInvoiceDocument> invoices = null;
516            
517            if (ObjectUtils.isNull(details) | details.size()==0)
518                return invoices;
519            
520            // get list of invoice document ids (eliminate duplicate invoice document ids)
521            List<String> documentIds = new ArrayList();
522            for (CustomerInvoiceDetail detail:details) {
523                String documentNumber = ((CustomerInvoiceDetail)detail).getDocumentNumber();
524                if (!documentIds.contains(documentNumber))
525                    documentIds.add(documentNumber);
526            }
527            
528            // get invoices for the document ids list
529            if (documentIds.size() != 0)
530                invoices = getDocuments(CustomerInvoiceDocument.class, documentIds);
531            
532            return invoices;
533       }
534        
535        protected void populateReporDetails(List<CustomerInvoiceDocument> selectedInvoices,List results, Collection<CustomerInvoiceDetail> invoiceDetails) {
536            
537            for (Iterator<CustomerInvoiceDocument> iter = selectedInvoices.iterator(); iter.hasNext();) {
538                CustomerInvoiceDocument invoice = iter.next();
539                String documentNumber = invoice.getDocumentNumber();
540                        
541                KualiDecimal amount = KualiDecimal.ZERO;
542                KualiDecimal taxAmount = KualiDecimal.ZERO;
543                KualiDecimal openAmount = KualiDecimal.ZERO;
544                
545                boolean foundFlag = false;
546                        
547                for (CustomerInvoiceDetail invoiceDetail:invoiceDetails) {
548                    String tempDocumentNumber = ((CustomerInvoiceDetail)invoiceDetail).getDocumentNumber();
549                    if (!StringUtils.equals(documentNumber, tempDocumentNumber))
550                        continue;
551                    foundFlag = true;
552                    
553                    KualiDecimal itemAmount = ((CustomerInvoiceDetail)invoiceDetail).getAmount();
554                    if (ObjectUtils.isNotNull(itemAmount))
555                        amount = amount.add(itemAmount);
556                                
557                    KualiDecimal itemTaxAmount = ((CustomerInvoiceDetail)invoiceDetail).getInvoiceItemTaxAmount();
558                    if (ObjectUtils.isNotNull(itemTaxAmount))
559                        taxAmount = taxAmount.add(itemTaxAmount);
560                                
561                    KualiDecimal openItemAmount = ((CustomerInvoiceDetail)invoiceDetail).getAmountOpen();
562                    if (ObjectUtils.isNotNull(openItemAmount))
563                        openAmount = openAmount.add(openItemAmount);
564                }
565                // How is this possible?
566                // invoiceDetails are for the list of invoices(invoices) meeting seach criteria including accountNumber and selected arDocumentHeaders
567                // -> list of invoices gets modified based on report run date and chosen date bucket -> selectedInvoices
568                // selectedInvoices.size() <= invoices.size()
569                if (!foundFlag)
570                    continue;
571                
572                CustomerOpenItemReportDetail detail = new CustomerOpenItemReportDetail();
573                // Document Type
574                detail.setDocumentType(invoice.getDocumentHeader().getWorkflowDocument().getDocumentType());
575                // Document Number
576                detail.setDocumentNumber(documentNumber);
577                // Document Description
578                String  documentDescription = invoice.getDocumentHeader().getDocumentDescription();
579                    if (ObjectUtils.isNotNull(documentDescription))
580                        detail.setDocumentDescription(documentDescription);
581                    else
582                        detail.setDocumentDescription("");
583                // Billing Date
584                detail.setBillingDate(invoice.getBillingDate());
585                // Due Date
586                detail.setDueApprovedDate(invoice.getInvoiceDueDate());
587                // Document Payment Amount
588                detail.setDocumentPaymentAmount(amount.add(taxAmount));
589                // Unpaid/Unapplied Amount
590                detail.setUnpaidUnappliedAmount(openAmount);
591                results.add(detail);
592            }
593        }
594        
595        protected void populateReportDetails(List<CustomerInvoiceDocument> invoices, List results) {
596            for (CustomerInvoiceDocument invoice:invoices) {
597                CustomerOpenItemReportDetail detail = new CustomerOpenItemReportDetail();
598                // Document Type
599                detail.setDocumentType(invoice.getDocumentHeader().getWorkflowDocument().getDocumentType());
600                // Document Number
601                detail.setDocumentNumber(invoice.getDocumentNumber());
602                // Document Description
603                String documentDescription = invoice.getDocumentHeader().getDocumentDescription();
604                    if (ObjectUtils.isNotNull(documentDescription))
605                        detail.setDocumentDescription(documentDescription);
606                    else
607                        detail.setDocumentDescription("");
608                // Billing Date
609                detail.setBillingDate(invoice.getBillingDate());
610                // Due Date
611                detail.setDueApprovedDate(invoice.getInvoiceDueDate());
612                // Document Payment Amount
613                detail.setDocumentPaymentAmount(invoice.getDocumentHeader().getFinancialDocumentTotalAmount());
614                // Unpaid/Unapplied Amount
615                detail.setUnpaidUnappliedAmount(customerInvoiceDocumentService.getOpenAmountForCustomerInvoiceDocument(invoice));
616                results.add(detail);
617                
618            }
619        }
620    
621        public void setAccountsReceivableDocumentHeaderDao(AccountsReceivableDocumentHeaderDao accountsReceivableDocumentHeaderDao) {
622            this.accountsReceivableDocumentHeaderDao = accountsReceivableDocumentHeaderDao;
623        }
624    
625        public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) {
626            this.workflowDocumentService = workflowDocumentService;
627        }
628    
629        public void setCustomerInvoiceDocumentService(CustomerInvoiceDocumentService customerInvoiceDocumentService) {
630            this.customerInvoiceDocumentService = customerInvoiceDocumentService;
631        }
632    
633        public void setFinancialSystemDocumentHeaderDao(FinancialSystemDocumentHeaderDao financialSystemDocumentHeaderDao) {
634            this.financialSystemDocumentHeaderDao = financialSystemDocumentHeaderDao;
635        }
636    
637        public void setDocumentService(DocumentService documentService) {
638            this.documentService = documentService;
639        }
640    
641        public void setDateTimeService(DateTimeService dateTimeService) {
642            this.dateTimeService = dateTimeService;
643        }
644    
645        public void setCustomerInvoiceDetailDao(CustomerInvoiceDetailDao customerInvoiceDetailDao) {
646            this.customerInvoiceDetailDao = customerInvoiceDetailDao;
647        }
648    
649        public void setNonAppliedHoldingDao(NonAppliedHoldingDao nonAppliedHoldingDao) {
650            this.nonAppliedHoldingDao = nonAppliedHoldingDao;
651        }
652    }
653