/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.ar.document.service.impl; import java.sql.Timestamp; import java.text.ParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.module.ar.ArConstants; import org.kuali.kfs.module.ar.businessobject.AccountsReceivableDocumentHeader; import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail; import org.kuali.kfs.module.ar.businessobject.CustomerOpenItemReportDetail; import org.kuali.kfs.module.ar.businessobject.InvoicePaidApplied; import org.kuali.kfs.module.ar.businessobject.NonAppliedHolding; import org.kuali.kfs.module.ar.document.CustomerCreditMemoDocument; import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument; import org.kuali.kfs.module.ar.document.CustomerInvoiceWriteoffDocument; import org.kuali.kfs.module.ar.document.PaymentApplicationDocument; import org.kuali.kfs.module.ar.document.dataaccess.AccountsReceivableDocumentHeaderDao; import org.kuali.kfs.module.ar.document.dataaccess.CustomerInvoiceDetailDao; import org.kuali.kfs.module.ar.document.dataaccess.NonAppliedHoldingDao; import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService; import org.kuali.kfs.module.ar.document.service.CustomerOpenItemReportService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.kew.api.WorkflowDocument; import org.kuali.rice.kew.api.WorkflowDocumentFactory; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.krad.exception.InfrastructureException; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.service.DocumentService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; import org.springframework.transaction.annotation.Transactional; @Transactional public class CustomerOpenItemReportServiceImpl implements CustomerOpenItemReportService { private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CustomerOpenItemReportServiceImpl.class); protected AccountsReceivableDocumentHeaderDao accountsReceivableDocumentHeaderDao; protected CustomerInvoiceDocumentService customerInvoiceDocumentService; protected DocumentService documentService; protected DateTimeService dateTimeService; protected CustomerInvoiceDetailDao customerInvoiceDetailDao; protected NonAppliedHoldingDao nonAppliedHoldingDao; protected BusinessObjectService businessObjectService; @Override public List getPopulatedReportDetails(String customerNumber){ List results = new ArrayList(); Collection<String> documentNumbers = accountsReceivableDocumentHeaderDao.getARDocumentNumbersIncludingHiddenApplicationByCustomerNumber(customerNumber); if (documentNumbers.size() == 0) { return results; } String userId = GlobalVariables.getUserSession().getPrincipalId(); List finSysDocHeaderIds = new ArrayList(); List invoiceIds = new ArrayList(); List paymentApplicationIds = new ArrayList(); List unappliedHoldingIds = new ArrayList(); Hashtable details = new Hashtable(); WorkflowDocument workflowDocument; for (String docNumber : documentNumbers) { CustomerOpenItemReportDetail detail = new CustomerOpenItemReportDetail(); // populate workflow document workflowDocument = WorkflowDocumentFactory.loadDocument(userId, docNumber); // do not display not approved documents if (ObjectUtils.isNull(workflowDocument.getDateApproved())) { continue; } Date approvedDate = getSqlDate(workflowDocument.getDateApproved().toCalendar(Locale.getDefault())); // Document Type String documentType = workflowDocument.getDocumentTypeName(); detail.setDocumentType(documentType); // Document Number detail.setDocumentNumber(docNumber); if (documentType.equals(KFSConstants.FinancialDocumentTypeCodes.CUSTOMER_INVOICE) || documentType.equals(ArConstants.ArDocumentTypeCodes.CONTRACTS_GRANTS_INVOICE)) { invoiceIds.add(docNumber); } else { // Approved Date -> for invoices Due Date, for all other documents Approved Date detail.setDueApprovedDate(approvedDate); if (documentType.equals(ArConstants.PAYMENT_APPLICATION_DOCUMENT_TYPE_CODE)) { paymentApplicationIds.add(docNumber); } else { finSysDocHeaderIds.add(docNumber); } } details.put(docNumber, detail); } // add Unapplied Payment Applications Collection<NonAppliedHolding> arNonAppliedHoldings = nonAppliedHoldingDao.getNonAppliedHoldingsForCustomer(customerNumber); for (NonAppliedHolding nonAppliedHolding : arNonAppliedHoldings) { // populate workflow document workflowDocument = WorkflowDocumentFactory.loadDocument(userId, nonAppliedHolding.getReferenceFinancialDocumentNumber()); CustomerOpenItemReportDetail detail = new CustomerOpenItemReportDetail(); detail.setDocumentType(ArConstants.PAYMENT_APPLICATION_DOCUMENT_TYPE_CODE); detail.setDocumentNumber(nonAppliedHolding.getReferenceFinancialDocumentNumber()); if (ObjectUtils.isNull(workflowDocument.getDateApproved())) { continue; } Date documentApprovedDate = getSqlDate(workflowDocument.getDateApproved().toCalendar(Locale.getDefault())); detail.setDueApprovedDate(documentApprovedDate); details.put(nonAppliedHolding.getReferenceFinancialDocumentNumber(), detail); unappliedHoldingIds.add(nonAppliedHolding.getReferenceFinancialDocumentNumber()); } // for invoices if (invoiceIds.size() > 0) { populateReportDetailsForInvoices(invoiceIds, results, details); } try { // for payment applications if (paymentApplicationIds.size() > 0) { populateReportDetailsForPaymentApplications(paymentApplicationIds, results, details); } // for unapplied payment applications if (unappliedHoldingIds.size() > 0) { populateReportDetailsForUnappliedPaymentApplications(unappliedHoldingIds, results, details); } } catch (WorkflowException we) { LOG.error("WorkflowException while populating report details for PaymentApplicationDocument", we); throw new RuntimeException("WorkflowException while populating report details for PaymentApplicationDocument",we); } // for all other documents if (finSysDocHeaderIds.size() > 0) { populateReportDetails(finSysDocHeaderIds, results, details); } return results; } /** * This method populates CustomerOpenItemReportDetails for CustomerInvoiceDocuments (Customer History Report). * * @param finSysDocHeaderIds <=> documentNumbers of CustomerInvoiceDocuments * @param results <=> CustomerOpenItemReportDetails to display in the report * @param details <=> <key = documentNumber, value = customerOpenItemReportDetail> */ protected void populateReportDetailsForInvoices(List invoiceIds, List results, Hashtable details) { Collection invoices = getDocuments(CustomerInvoiceDocument.class, invoiceIds); for (Iterator itr = invoices.iterator(); itr.hasNext();) { CustomerInvoiceDocument invoice = (CustomerInvoiceDocument) itr.next(); String documentNumber = invoice.getDocumentNumber(); CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(documentNumber); // Document Description String documentDescription = invoice.getDocumentHeader().getDocumentDescription(); if (ObjectUtils.isNotNull(documentDescription)) { detail.setDocumentDescription(documentDescription); } else { detail.setDocumentDescription(""); } // Billing Date detail.setBillingDate(invoice.getBillingDate()); // Due/Approved Date -> for invoice it is Due Date, and for all other documents Approved Date detail.setDueApprovedDate(invoice.getInvoiceDueDate()); // Document Payment Amount detail.setDocumentPaymentAmount(invoice.getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount()); // Unpaid/Unapplied Amount detail.setUnpaidUnappliedAmount(customerInvoiceDocumentService.getOpenAmountForCustomerInvoiceDocument(invoice)); results.add(detail); } } /** * This method populates CustomerOpenItemReportDetails for PaymentApplicationDocuments (Customer History Report). * * @param paymentApplicationIds <=> documentNumbers of PaymentApplicationDocuments * @param results <=> CustomerOpenItemReportDetails to display in the report * @param details <=> <key = documentNumber, value = customerOpenItemReportDetail> */ protected void populateReportDetailsForPaymentApplications(List paymentApplicationIds, List results, Hashtable details) throws WorkflowException { Collection paymentApplications = getDocuments(PaymentApplicationDocument.class, paymentApplicationIds); for (Iterator itr = paymentApplications.iterator(); itr.hasNext();) { PaymentApplicationDocument paymentApplication = (PaymentApplicationDocument) itr.next(); String documentNumber = paymentApplication.getDocumentNumber(); CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(documentNumber); // populate Document Description String documentDescription = paymentApplication.getDocumentHeader().getDocumentDescription(); if (ObjectUtils.isNotNull(documentDescription)) { detail.setDocumentDescription(documentDescription); } else { detail.setDocumentDescription(""); } // populate Document Payment Amount detail.setDocumentPaymentAmount(paymentApplication.getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount().negated()); // populate Unpaid/Unapplied Amount if the customer number is the same if (ObjectUtils.isNotNull(paymentApplication.getNonAppliedHolding())) { if (paymentApplication.getNonAppliedHolding().getCustomerNumber().equals(paymentApplication.getAccountsReceivableDocumentHeader().getCustomerNumber())) { detail.setUnpaidUnappliedAmount(paymentApplication.getNonAppliedHolding().getAvailableUnappliedAmount().negated()); } else { detail.setUnpaidUnappliedAmount(KualiDecimal.ZERO); } } else { detail.setUnpaidUnappliedAmount(KualiDecimal.ZERO); } results.add(detail); } } /** * This method populates CustomerOpenItemReportDetails for UnappliedPaymentApplicationDocuments (Customer History Report). * * @param unappliedHoldingIds <=> documentNumbers of UnappliedPaymentApplicationDocuments * @param results <=> CustomerOpenItemReportDetails to display in the report * @param details <=> <key = documentNumber, value = customerOpenItemReportDetail> */ protected void populateReportDetailsForUnappliedPaymentApplications(List unappliedHoldingIds, List results, Hashtable details) throws WorkflowException { Collection paymentApplications = getDocuments(PaymentApplicationDocument.class, unappliedHoldingIds); for (Iterator itr = paymentApplications.iterator(); itr.hasNext();) { PaymentApplicationDocument paymentApplication = (PaymentApplicationDocument) itr.next(); String documentNumber = paymentApplication.getDocumentNumber(); if ((paymentApplication.getNonAppliedHolding().getCustomerNumber().equals(paymentApplication.getAccountsReceivableDocumentHeader().getCustomerNumber()))) { continue; } CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(documentNumber); // populate Document Description String documentDescription = paymentApplication.getDocumentHeader().getDocumentDescription(); if (ObjectUtils.isNotNull(documentDescription)) { detail.setDocumentDescription(documentDescription); } else { detail.setDocumentDescription(""); } // populate Document Payment Amount - original document amount detail.setDocumentPaymentAmount(paymentApplication.getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount().negated()); // populate Unpaid/Unapplied Amount detail.setUnpaidUnappliedAmount(paymentApplication.getNonAppliedHolding().getAvailableUnappliedAmount().negated()); results.add(detail); } } /** * This method populates CustomerOpenItemReportDetails for CustomerCreditMemoDocuments and WriteOffDocuments <=> all documents * but CustomerInvoiceDocument and PaymentApplicationDocument (Customer History Report). * * @param finSysDocHeaderIds <=> documentNumbers of FinancialSystemDocumentHeaders * @param results <=> CustomerOpenItemReportDetails to display in the report * @param details <=> <key = documentNumber, value = customerOpenItemReportDetail> */ public void populateReportDetails(List<String> finSysDocHeaderIds, List results, Hashtable details) { Collection<FinancialSystemDocumentHeader> financialSystemDocHeaders = new ArrayList<FinancialSystemDocumentHeader>(); for (String documentNumber : finSysDocHeaderIds) { FinancialSystemDocumentHeader header = businessObjectService.findBySinglePrimaryKey(FinancialSystemDocumentHeader.class, documentNumber); if ( header != null ) { financialSystemDocHeaders.add( header ); } } for ( FinancialSystemDocumentHeader fsDocumentHeader : financialSystemDocHeaders ) { CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(fsDocumentHeader.getDocumentNumber()); // populate Document Description detail.setDocumentDescription(StringUtils.trimToEmpty(fsDocumentHeader.getDocumentDescription())); // populate Document Payment Amount detail.setDocumentPaymentAmount(fsDocumentHeader.getFinancialDocumentTotalAmount().negated()); // Unpaid/Unapplied Amount detail.setUnpaidUnappliedAmount(KualiDecimal.ZERO); results.add(detail); } } /** * This method returns collection of documents of type classToSearchFrom Note: can be used for documents only, not for * *DocumentHeaders @param documentNumbers */ public Collection getDocuments(Class classToSearchFrom, List documentNumbers) { List docs; try { docs = documentService.getDocumentsByListOfDocumentHeaderIds(classToSearchFrom, documentNumbers); } catch (WorkflowException e) { throw new InfrastructureException("Unable to retrieve documents", e); } return docs; } /** * @param cal * @return */ protected Date getSqlDate(Calendar cal) { Date sqlDueDate = null; if (ObjectUtils.isNull(cal)) { return sqlDueDate; } try { sqlDueDate = dateTimeService.convertToSqlDate(new Timestamp(cal.getTime().getTime())); } catch (ParseException e) { // throw an error here, but don't die LOG.error("Error in converting given calendar to sql date"); } return sqlDueDate; } /** * This method populates CustomerOpenItemReportDetails (Customer Open Item Report) * * @param urlParameters */ @Override public List getPopulatedReportDetails(Map urlParameters) { List results = new ArrayList(); // get arDocumentHeaders Collection<AccountsReceivableDocumentHeader> arDocumentHeaders = getARDocumentHeaders(urlParameters); if (arDocumentHeaders.size() == 0) { return results; } // get ids of arDocumentHeaders List<String> arDocumentHeaderIds = new ArrayList<String>(); for (AccountsReceivableDocumentHeader arDocHeader : arDocumentHeaders) { arDocumentHeaderIds.add(arDocHeader.getDocumentNumber()); } // get invoices String reportOption = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.REPORT_OPTION))[0]; Collection<CustomerInvoiceDocument> invoices; Collection<CustomerInvoiceDetail> details = null; if (StringUtils.equals(reportOption, ArConstants.CustomerAgingReportFields.ACCT)) { String accountNumber = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.ACCOUNT_NUMBER))[0]; details = customerInvoiceDetailDao.getCustomerInvoiceDetailsByAccountNumberByInvoiceDocumentNumbers(accountNumber, arDocumentHeaderIds); invoices = getInvoicesByAccountNumberByDocumentIds(accountNumber, arDocumentHeaderIds, details); } else { invoices = getDocuments(CustomerInvoiceDocument.class, arDocumentHeaderIds); } if (ObjectUtils.isNull(invoices) | invoices.size() == 0) { return results; } List<CustomerInvoiceDocument> selectedInvoices = new ArrayList(); String columnTitle = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.COLUMN_TITLE))[0]; java.util.Date reportRunDate = null; java.util.Date beginDate = null; java.util.Date endDate = null; try { reportRunDate = dateTimeService.convertToDate(((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.REPORT_RUN_DATE))[0]); if (!StringUtils.equals(columnTitle, KFSConstants.CustomerOpenItemReport.ALL_DAYS)) { endDate = dateTimeService.convertToDate(((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.REPORT_END_DATE))[0]); String strBeginDate = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.REPORT_BEGIN_DATE))[0]; if (StringUtils.isNotEmpty(strBeginDate)) { beginDate = dateTimeService.convertToDate(strBeginDate); } } } catch (ParseException e) { LOG.error("problem during CustomerOpenItemReportServiceImpl.getPopulatedReportDetails()", e); } // Billing Organization if (StringUtils.equals(reportOption, ArConstants.ReportOptionFieldValues.BILLING_ORG)) { // All days // 1. invoice open amount > 0 // 2. billingDate <= reportRunDate // 3. billByChartOfAccountsCode = processingOrBillingChartCode // 4. billbyOrganizationCode = orgCode String chartCode = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.PROCESSING_OR_BILLING_CHART_CODE))[0]; String orgCode = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.ORGANIZATION_CODE))[0]; if (StringUtils.equals(columnTitle, KFSConstants.CustomerOpenItemReport.ALL_DAYS)) { for (CustomerInvoiceDocument invoice : invoices) { // get only invoices with open amounts if (ObjectUtils.isNull(invoice.getClosedDate()) && ObjectUtils.isNotNull(invoice.getBillingDate()) && !reportRunDate.before(invoice.getBillingDate()) && StringUtils.equals(chartCode, invoice.getBillByChartOfAccountCode()) && StringUtils.equals(orgCode, invoice.getBilledByOrganizationCode())) { selectedInvoices.add(invoice); } } } // *days // 1. invoice open amount > 0 // 2. beginDate <= invoice billing date <= endDate // 3. billByChartOfAccountsCode = chartCode // 4. billbyOrganizationCode = orgCode else { for (CustomerInvoiceDocument invoice : invoices) { if (ObjectUtils.isNull(invoice.getClosedDate()) && ObjectUtils.isNotNull(invoice.getBillingDate()) && StringUtils.equals(chartCode, invoice.getBillByChartOfAccountCode()) && StringUtils.equals(orgCode, invoice.getBilledByOrganizationCode())) { if ((ObjectUtils.isNotNull(beginDate) && !beginDate.after(invoice.getBillingDate()) && !endDate.before(invoice.getBillingDate())) || (ObjectUtils.isNull(beginDate) && !endDate.before(invoice.getBillingDate()))) { selectedInvoices.add(invoice); } } } } } // Processing Organization or Account else { // All days // 1. invoice open amount > 0 // 2. invoice billing dates <= reportRunDate if (StringUtils.equals(columnTitle, KFSConstants.CustomerOpenItemReport.ALL_DAYS)) { for (CustomerInvoiceDocument invoice : invoices) { if (ObjectUtils.isNull(invoice.getClosedDate()) && ObjectUtils.isNotNull(invoice.getBillingDate()) && !reportRunDate.before(invoice.getBillingDate())) { selectedInvoices.add(invoice); } } } // *days // 1. invoice open amount > 0 // 2. beginDate <= invoice billing date <= endDate else { for (CustomerInvoiceDocument invoice : invoices) { if (ObjectUtils.isNull(invoice.getClosedDate()) && ObjectUtils.isNotNull(invoice.getBillingDate())) { if ((ObjectUtils.isNotNull(beginDate) && !beginDate.after(invoice.getBillingDate()) && !endDate.before(invoice.getBillingDate())) || (ObjectUtils.isNull(beginDate) && !endDate.before(invoice.getBillingDate()))) { selectedInvoices.add(invoice); } } } } } if (selectedInvoices.size() == 0) { return results; } if (StringUtils.equals(reportOption, ArConstants.CustomerAgingReportFields.ACCT)) { populateReporDetails(selectedInvoices, results, details); } else { populateReportDetails(selectedInvoices, results); } return results; } /** * This method retrieves ARDocumentHeader objects for "Customer Open Item Report" * * @param urlParameters * @return ARDocumentHeader objects meeting the search criteria */ protected Collection getARDocumentHeaders(Map urlParameters) { Collection arDocumentHeaders; String reportOption = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.REPORT_OPTION))[0]; String customerNumber = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.CUSTOMER_NUMBER))[0]; if (StringUtils.equals(reportOption, ArConstants.ReportOptionFieldValues.PROCESSING_ORG)) { String processingChartCode = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.PROCESSING_OR_BILLING_CHART_CODE))[0]; String processingOrganizationCode = ((String[]) urlParameters.get(KFSConstants.CustomerOpenItemReport.ORGANIZATION_CODE))[0]; arDocumentHeaders = accountsReceivableDocumentHeaderDao.getARDocumentHeadersByCustomerNumberByProcessingOrgCodeAndChartCode(customerNumber, processingChartCode, processingOrganizationCode); } // reportOption is "Billing Organization" or "Account" else { arDocumentHeaders = accountsReceivableDocumentHeaderDao.getARDocumentHeadersIncludingHiddenApplicationByCustomerNumber(customerNumber); } return arDocumentHeaders; } /** * This method gets called only if reportOption is Account Gets invoices based on the selected invoice details <=> invoice * details meeting search criteria i.e. the accountNumber and the list of documentIds * * @param accountNumber * @param arDocumentHeaderIds * @param details (will get populated here) * @return invoices */ protected Collection<CustomerInvoiceDocument> getInvoicesByAccountNumberByDocumentIds(String accountNumber, List arDocumentHeaderIds, Collection<CustomerInvoiceDetail> details) { Collection<CustomerInvoiceDocument> invoices = null; if (ObjectUtils.isNull(details) | details.size() == 0) { return invoices; } // get list of invoice document ids (eliminate duplicate invoice document ids) List<String> documentIds = new ArrayList(); for (CustomerInvoiceDetail detail : details) { String documentNumber = detail.getDocumentNumber(); if (!documentIds.contains(documentNumber)) { documentIds.add(documentNumber); } } // get invoices for the document ids list if (documentIds.size() != 0) { invoices = getDocuments(CustomerInvoiceDocument.class, documentIds); } return invoices; } /** * @param selectedInvoices * @param results * @param invoiceDetails */ protected void populateReporDetails(List<CustomerInvoiceDocument> selectedInvoices, List results, Collection<CustomerInvoiceDetail> invoiceDetails) { for (Iterator<CustomerInvoiceDocument> iter = selectedInvoices.iterator(); iter.hasNext();) { CustomerInvoiceDocument invoice = iter.next(); String documentNumber = invoice.getDocumentNumber(); KualiDecimal amount = KualiDecimal.ZERO; KualiDecimal taxAmount = KualiDecimal.ZERO; KualiDecimal openAmount = KualiDecimal.ZERO; boolean foundFlag = false; for (CustomerInvoiceDetail invoiceDetail : invoiceDetails) { String tempDocumentNumber = invoiceDetail.getDocumentNumber(); if (!StringUtils.equals(documentNumber, tempDocumentNumber)) { continue; } foundFlag = true; KualiDecimal itemAmount = invoiceDetail.getAmount(); if (ObjectUtils.isNotNull(itemAmount)) { amount = amount.add(itemAmount); } KualiDecimal itemTaxAmount = invoiceDetail.getInvoiceItemTaxAmount(); if (ObjectUtils.isNotNull(itemTaxAmount)) { taxAmount = taxAmount.add(itemTaxAmount); } KualiDecimal openItemAmount = invoiceDetail.getAmountOpen(); if (ObjectUtils.isNotNull(openItemAmount)) { openAmount = openAmount.add(openItemAmount); } } // How is this possible? // invoiceDetails are for the list of invoices(invoices) meeting seach criteria including accountNumber and selected // arDocumentHeaders // -> list of invoices gets modified based on report run date and chosen date bucket -> selectedInvoices // selectedInvoices.size() <= invoices.size() if (!foundFlag) { continue; } CustomerOpenItemReportDetail detail = new CustomerOpenItemReportDetail(); // Document Type detail.setDocumentType(invoice.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); // Document Number detail.setDocumentNumber(documentNumber); // Document Description String documentDescription = invoice.getDocumentHeader().getDocumentDescription(); if (ObjectUtils.isNotNull(documentDescription)) { detail.setDocumentDescription(documentDescription); } else { detail.setDocumentDescription(""); } // Billing Date detail.setBillingDate(invoice.getBillingDate()); // Due Date detail.setDueApprovedDate(invoice.getInvoiceDueDate()); // Document Payment Amount detail.setDocumentPaymentAmount(amount.add(taxAmount)); // Unpaid/Unapplied Amount detail.setUnpaidUnappliedAmount(openAmount); results.add(detail); } } /** * @param invoices * @param results */ protected void populateReportDetails(List<CustomerInvoiceDocument> invoices, List results) { for (CustomerInvoiceDocument invoice : invoices) { CustomerOpenItemReportDetail detail = new CustomerOpenItemReportDetail(); // Document Type detail.setDocumentType(invoice.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); // Document Number detail.setDocumentNumber(invoice.getDocumentNumber()); // Document Description String documentDescription = invoice.getDocumentHeader().getDocumentDescription(); if (ObjectUtils.isNotNull(documentDescription)) { detail.setDocumentDescription(documentDescription); } else { detail.setDocumentDescription(""); } // Billing Date detail.setBillingDate(invoice.getBillingDate()); // Due Date detail.setDueApprovedDate(invoice.getInvoiceDueDate()); // Document Payment Amount detail.setDocumentPaymentAmount(invoice.getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount()); // Unpaid/Unapplied Amount detail.setUnpaidUnappliedAmount(customerInvoiceDocumentService.getOpenAmountForCustomerInvoiceDocument(invoice)); results.add(detail); } } @Override public Collection<String> getDocumentNumbersOfReferenceReports(String customerNumber) { Collection<String> documentNumbers = new ArrayList(); Collection arDocumentHeaders = accountsReceivableDocumentHeaderDao.getARDocumentHeadersIncludingHiddenApplicationByCustomerNumber(customerNumber); String userId = GlobalVariables.getUserSession().getPrincipalId(); List paymentApplicationIds = new ArrayList(); List creditMemoIds = new ArrayList(); List writeOffIds = new ArrayList(); WorkflowDocument workflowDocument; for (Iterator itr = arDocumentHeaders.iterator(); itr.hasNext();) { AccountsReceivableDocumentHeader documentHeader = (AccountsReceivableDocumentHeader) itr.next(); // populate workflow document workflowDocument = WorkflowDocumentFactory.loadDocument(userId, documentHeader.getDocumentNumber()); // do not display not approved documents if (ObjectUtils.isNull(workflowDocument.getDateApproved())) { continue; } Date approvedDate = getSqlDate(workflowDocument.getDateApproved().toCalendar(Locale.getDefault())); // Document Type String documentType = workflowDocument.getDocumentTypeName(); // Document Number String documentNumber = documentHeader.getDocumentNumber(); if (documentType.equals(ArConstants.PAYMENT_APPLICATION_DOCUMENT_TYPE_CODE)){ paymentApplicationIds.add(documentNumber); } else if (documentType.equals(KFSConstants.FinancialDocumentTypeCodes.CUSTOMER_CREDIT_MEMO)) { creditMemoIds.add(documentNumber); } else if (documentType.equals(ArConstants.INVOICE_WRITEOFF_DOCUMENT_TYPE_CODE)) { writeOffIds.add(documentNumber); } } if (paymentApplicationIds.size() > 0){ Collection<PaymentApplicationDocument> paymentApplications = getDocuments(PaymentApplicationDocument.class, paymentApplicationIds); for (PaymentApplicationDocument paymentApplicationDocument: paymentApplications ) { for (InvoicePaidApplied invoicePaidApplied : paymentApplicationDocument.getInvoicePaidApplieds()){ documentNumbers.add(invoicePaidApplied.getFinancialDocumentReferenceInvoiceNumber()); } } } if (creditMemoIds.size() > 0){ Collection<CustomerCreditMemoDocument> creditMemoDetailDocs = getDocuments(CustomerCreditMemoDocument.class, creditMemoIds); for (CustomerCreditMemoDocument creditMemo: creditMemoDetailDocs){ documentNumbers.add(creditMemo.getFinancialDocumentReferenceInvoiceNumber()); } } if (writeOffIds.size() > 0){ Collection<CustomerInvoiceWriteoffDocument> customerInvoiceWriteoffDocs = getDocuments(CustomerInvoiceWriteoffDocument.class, writeOffIds); for (CustomerInvoiceWriteoffDocument invoiceWriteoffDocument : customerInvoiceWriteoffDocs) { documentNumbers.add(invoiceWriteoffDocument.getFinancialDocumentReferenceInvoiceNumber()); } } return documentNumbers; } @Override public List getPopulatedUnpaidUnappliedAmountReportDetails(String customerNumber, String refDocumentNumber) { List results = new ArrayList(); Collection<AccountsReceivableDocumentHeader> arDocumentHeaders = accountsReceivableDocumentHeaderDao.getARDocumentHeadersIncludingHiddenApplicationByCustomerNumber(customerNumber); String userId = GlobalVariables.getUserSession().getPrincipalId(); Hashtable details = new Hashtable(); List paymentApplicationIds = new ArrayList(); List creditMemoIds = new ArrayList(); List writeOffIds = new ArrayList(); WorkflowDocument workflowDocument; for (AccountsReceivableDocumentHeader documentHeader : arDocumentHeaders) { CustomerOpenItemReportDetail detail = new CustomerOpenItemReportDetail(); // populate workflow document workflowDocument = WorkflowDocumentFactory.loadDocument(userId, documentHeader.getDocumentNumber()); // do not display not approved documents if (ObjectUtils.isNull(workflowDocument.getDateApproved())) { continue; } Date approvedDate = getSqlDate(workflowDocument.getDateApproved().toCalendar(Locale.getDefault())); // Document Type String documentType = workflowDocument.getDocumentTypeName(); detail.setDocumentType(documentType); // Document Number String documentNumber = documentHeader.getDocumentNumber(); detail.setDocumentNumber(documentNumber); // Approved Date -> for invoices Due Date, for all other documents Approved Date detail.setDueApprovedDate(approvedDate); if (documentType.equals("APP")) { paymentApplicationIds.add(documentNumber); } else if (documentType.equals("CRM")) { creditMemoIds.add(documentNumber); } else if (documentType.equals("INVW")) { writeOffIds.add(documentNumber); } details.put(documentNumber, detail); } if (paymentApplicationIds.size() > 0){ try { populateReportDetailsForUnpaidUnappliedPaymentApplications(paymentApplicationIds, results, details, refDocumentNumber); } catch(WorkflowException we) { LOG.error("WorkflowException while populating report details for PaymentApplicationDocument", we); throw new RuntimeException("WorkflowException while populating report details for PaymentApplicationDocument",we); } } if (creditMemoIds.size() > 0){ populateReportDetailsForCreditMemo(creditMemoIds, results, details, refDocumentNumber); } if (writeOffIds.size() > 0){ populateReportDetailsForWriteOff(writeOffIds, results, details, refDocumentNumber); } return results; } protected void populateReportDetailsForUnpaidUnappliedPaymentApplications(List paymentApplicationIds, List results, Hashtable details, String refDocumentNumber) throws WorkflowException { Collection<PaymentApplicationDocument> paymentApplications = getDocuments(PaymentApplicationDocument.class, paymentApplicationIds); for (PaymentApplicationDocument paymentApplication : paymentApplications) { for (InvoicePaidApplied invoicePaidApplied : paymentApplication.getInvoicePaidApplieds()){ if (invoicePaidApplied.getFinancialDocumentReferenceInvoiceNumber().equals(refDocumentNumber)){ String documentNumber = paymentApplication.getDocumentNumber(); CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(documentNumber); // populate Document Description String documentDescription = paymentApplication.getDocumentHeader().getDocumentDescription(); if (ObjectUtils.isNotNull(documentDescription)) { detail.setDocumentDescription(documentDescription); } else { detail.setDocumentDescription(""); } // populate Document Payment Amount detail.setDocumentPaymentAmount(paymentApplication.getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount().negated()); // populate Unpaid/Unapplied Amount if the customer number is the same if (ObjectUtils.isNotNull(paymentApplication.getNonAppliedHolding())) { if (paymentApplication.getNonAppliedHolding().getCustomerNumber().equals(paymentApplication.getAccountsReceivableDocumentHeader().getCustomerNumber())) { detail.setUnpaidUnappliedAmount(paymentApplication.getNonAppliedHolding().getAvailableUnappliedAmount().negated()); } } results.add(detail); } } } } protected void populateReportDetailsForCreditMemo(List creditMemoIds, List results, Hashtable details, String refDocumentNumber){ Collection<CustomerCreditMemoDocument> creditMemoDetailDocs = getDocuments(CustomerCreditMemoDocument.class, creditMemoIds); for (CustomerCreditMemoDocument creditMemo: creditMemoDetailDocs){ if (creditMemo.getFinancialDocumentReferenceInvoiceNumber().equals(refDocumentNumber)){ String documentNumber = creditMemo.getDocumentNumber(); CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(documentNumber); // populate Document Description String documentDescription = creditMemo.getDocumentHeader().getDocumentDescription(); if (ObjectUtils.isNotNull(documentDescription)) { detail.setDocumentDescription(documentDescription); } else { detail.setDocumentDescription(""); } // populate Document Payment Amount detail.setDocumentPaymentAmount(creditMemo.getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount().negated()); // Unpaid/Unapplied Amount detail.setUnpaidUnappliedAmount(KualiDecimal.ZERO); results.add(detail); } } } protected void populateReportDetailsForWriteOff(List writeOffIds, List results, Hashtable details, String refDocumentNumber){ Collection<CustomerInvoiceWriteoffDocument> customerInvoiceWriteoffDocs = getDocuments(CustomerInvoiceWriteoffDocument.class, writeOffIds); for (CustomerInvoiceWriteoffDocument invoiceWriteoffDocument : customerInvoiceWriteoffDocs) { if (invoiceWriteoffDocument.getFinancialDocumentReferenceInvoiceNumber().equals(refDocumentNumber)){ String documentNumber = invoiceWriteoffDocument.getDocumentNumber(); CustomerOpenItemReportDetail detail = (CustomerOpenItemReportDetail) details.get(documentNumber); // populate Document Description String documentDescription = invoiceWriteoffDocument.getDocumentHeader().getDocumentDescription(); if (ObjectUtils.isNotNull(documentDescription)) { detail.setDocumentDescription(documentDescription); } else { detail.setDocumentDescription(""); } // populate Document Payment Amount detail.setDocumentPaymentAmount(invoiceWriteoffDocument.getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount().negated()); // Unpaid/Unapplied Amount detail.setUnpaidUnappliedAmount(KualiDecimal.ZERO); results.add(detail); } } } public void setAccountsReceivableDocumentHeaderDao(AccountsReceivableDocumentHeaderDao accountsReceivableDocumentHeaderDao) { this.accountsReceivableDocumentHeaderDao = accountsReceivableDocumentHeaderDao; } public void setCustomerInvoiceDocumentService(CustomerInvoiceDocumentService customerInvoiceDocumentService) { this.customerInvoiceDocumentService = customerInvoiceDocumentService; } public void setDocumentService(DocumentService documentService) { this.documentService = documentService; } public void setDateTimeService(DateTimeService dateTimeService) { this.dateTimeService = dateTimeService; } public void setCustomerInvoiceDetailDao(CustomerInvoiceDetailDao customerInvoiceDetailDao) { this.customerInvoiceDetailDao = customerInvoiceDetailDao; } public void setNonAppliedHoldingDao(NonAppliedHoldingDao nonAppliedHoldingDao) { this.nonAppliedHoldingDao = nonAppliedHoldingDao; } public void setBusinessObjectService(BusinessObjectService businessObjectService) { this.businessObjectService = businessObjectService; } }