/*
* 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.report.service.impl;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.time.DateUtils;
import org.kuali.kfs.module.ar.businessobject.Customer;
import org.kuali.kfs.module.ar.businessobject.CustomerAgingReportDetail;
import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail;
import org.kuali.kfs.module.ar.dataaccess.CustomerAgingReportDao;
import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument;
import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService;
import org.kuali.kfs.module.ar.report.service.CustomerAgingReportService;
import org.kuali.kfs.module.ar.report.util.CustomerAgingReportDataHolder;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.krad.util.ObjectUtils;
import org.springframework.transaction.annotation.Transactional;
/**
* This class...
*/
@Transactional
public class CustomerAgingReportServiceImpl implements CustomerAgingReportService {
protected ParameterService parameterService;
protected DateTimeService dateTimeService;
protected CustomerInvoiceDocumentService customerInvoiceDocumentService;
protected CustomerAgingReportDao customerAgingReportDao;
/**
* @see org.kuali.kfs.module.ar.report.service.CustomerAgingReportService#calculateAgingReportAmounts()
*/
@Override
public CustomerAgingReportDataHolder calculateAgingReportAmounts(Collection<CustomerInvoiceDetail> details, Date reportRunDate) {
CustomerAgingReportDataHolder agingData = new CustomerAgingReportDataHolder();
KualiDecimal total0to30 = KualiDecimal.ZERO;
KualiDecimal total31to60 = KualiDecimal.ZERO;
KualiDecimal total61to90 = KualiDecimal.ZERO;
KualiDecimal total91toSYSPR = KualiDecimal.ZERO;
KualiDecimal totalSYSPRplus1orMore = KualiDecimal.ZERO;
String nbrDaysForLastBucket = parameterService.getParameterValueAsString(CustomerAgingReportDetail.class, "CUSTOMER_INVOICE_AGE"); // ArConstants.CUSTOMER_INVOICE_AGE); // default is 120
Date cutoffdate30 = DateUtils.addDays(reportRunDate, -30);
Date cutoffdate60 = DateUtils.addDays(reportRunDate, -60);
Date cutoffdate90 = DateUtils.addDays(reportRunDate, -90);
Date cutoffdate120 = DateUtils.addDays(reportRunDate, -1*Integer.parseInt(nbrDaysForLastBucket));
Map<String, Object> knownCustomers = new HashMap<String, Object>(details.size());
Map<String, Object> retrievedInvoices = new HashMap<String, Object>(); // Simple caching mechanism to try to lower overhead for retrieving invoices that have multiple details
KualiDecimal totalBalance = new KualiDecimal(0.00);
CustomerAgingReportDetail custDetail = null;
// iterate over all invoices consolidating balances for each customer
for (CustomerInvoiceDetail cid : details) {
String invoiceDocumentNumber = cid.getDocumentNumber();
CustomerInvoiceDocument custInvoice;
// check cache for already retrieved invoices before attempting to retrieve it from the DB
if(retrievedInvoices.containsKey(invoiceDocumentNumber)) {
custInvoice = (CustomerInvoiceDocument) retrievedInvoices.get(invoiceDocumentNumber);
} else {
custInvoice = customerInvoiceDocumentService.getInvoiceByInvoiceDocumentNumber(invoiceDocumentNumber);
retrievedInvoices.put(invoiceDocumentNumber, custInvoice);
}
Date approvalDate=custInvoice.getBillingDate();
if (ObjectUtils.isNull(approvalDate)) {
continue;
}
// only for items that have positive amounts and non-zero open amounts - e.g. a discount should not be added
if(ObjectUtils.isNotNull(custInvoice) && cid.getAmountOpen().isNonZero() && cid.getAmount().isPositive()) {
Customer customerobj = custInvoice.getCustomer();
String customerNumber = customerobj.getCustomerNumber(); // tested and works
String customerName = customerobj.getCustomerName(); // tested and works
if (knownCustomers.containsKey(customerNumber)) {
custDetail = (CustomerAgingReportDetail) knownCustomers.get(customerNumber);
} else {
custDetail = new CustomerAgingReportDetail();
custDetail.setCustomerName(customerName);
custDetail.setCustomerNumber(customerNumber);
knownCustomers.put(customerNumber, custDetail);
}
KualiDecimal amountOpenOnReportRunDate = cid.getAmountOpenByDateFromDatabase(reportRunDate);
if (!approvalDate.after(reportRunDate) && !approvalDate.before(cutoffdate30)) {
custDetail.setUnpaidBalance0to30(amountOpenOnReportRunDate.add(custDetail.getUnpaidBalance0to30()));
total0to30 = total0to30.add(amountOpenOnReportRunDate);
}
else if (approvalDate.before(cutoffdate30) && !approvalDate.before(cutoffdate60)) {
custDetail.setUnpaidBalance31to60(amountOpenOnReportRunDate.add(custDetail.getUnpaidBalance31to60()));
total31to60 = total31to60.add(amountOpenOnReportRunDate);
}
else if (approvalDate.before(cutoffdate60) && !approvalDate.before(cutoffdate90)) {
custDetail.setUnpaidBalance61to90(amountOpenOnReportRunDate.add(custDetail.getUnpaidBalance61to90()));
total61to90 = total61to90.add(amountOpenOnReportRunDate);
}
else if (approvalDate.before(cutoffdate90) && !approvalDate.before(cutoffdate120)) {
custDetail.setUnpaidBalance91toSYSPR(amountOpenOnReportRunDate.add(custDetail.getUnpaidBalance91toSYSPR()));
total91toSYSPR = total91toSYSPR.add(amountOpenOnReportRunDate);
}
else if (approvalDate.before(cutoffdate120)) {
custDetail.setUnpaidBalanceSYSPRplus1orMore(amountOpenOnReportRunDate.add(custDetail.getUnpaidBalanceSYSPRplus1orMore()));
totalSYSPRplus1orMore = totalSYSPRplus1orMore.add(amountOpenOnReportRunDate);
}
totalBalance = totalBalance.add(amountOpenOnReportRunDate);
}
}
agingData.setTotal0to30(total0to30);
agingData.setTotal31to60(total31to60);
agingData.setTotal61to90(total61to90);
agingData.setTotal91toSYSPR(total91toSYSPR);
agingData.setTotalSYSPRplus1orMore(totalSYSPRplus1orMore);
agingData.setTotalAmountDue(totalBalance);
agingData.setKnownCustomers(knownCustomers);
return agingData;
}
@Override
public HashMap<String, KualiDecimal> findInvoiceAmountByProcessingChartAndOrg(String chart, String org, java.sql.Date begin, java.sql.Date end) {
return getCustomerAgingReportDao().findInvoiceAmountByProcessingChartAndOrg(chart, org, begin, end);
}
@Override
public HashMap<String, KualiDecimal> findAppliedAmountByProcessingChartAndOrg(String chart, String org, java.sql.Date begin, java.sql.Date end) {
return getCustomerAgingReportDao().findAppliedAmountByProcessingChartAndOrg(chart, org, begin, end);
}
@Override
public HashMap<String, KualiDecimal> findDiscountAmountByProcessingChartAndOrg(String chart, String org, java.sql.Date begin, java.sql.Date end) {
return getCustomerAgingReportDao().findDiscountAmountByProcessingChartAndOrg(chart, org, begin, end);
}
@Override
public HashMap<String, KualiDecimal> findInvoiceAmountByBillingChartAndOrg(String chart, String org, java.sql.Date begin, java.sql.Date end) {
return getCustomerAgingReportDao().findInvoiceAmountByBillingChartAndOrg(chart, org, begin, end);
}
@Override
public HashMap<String, KualiDecimal> findAppliedAmountByBillingChartAndOrg(String chart, String org, java.sql.Date begin, java.sql.Date end) {
return getCustomerAgingReportDao().findAppliedAmountByBillingChartAndOrg(chart, org, begin, end);
}
@Override
public HashMap<String, KualiDecimal> findDiscountAmountByBillingChartAndOrg(String chart, String org, java.sql.Date begin, java.sql.Date end) {
return getCustomerAgingReportDao().findDiscountAmountByBillingChartAndOrg(chart, org, begin, end);
}
@Override
public HashMap<String, KualiDecimal> findInvoiceAmountByAccount(String chart, String account, java.sql.Date begin, java.sql.Date end) {
return getCustomerAgingReportDao().findInvoiceAmountByAccount(chart, account, begin, end);
}
@Override
public HashMap<String, KualiDecimal> findAppliedAmountByAccount(String chart, String account, java.sql.Date begin, java.sql.Date end) {
return getCustomerAgingReportDao().findAppliedAmountByAccount(chart, account, begin, end);
}
@Override
public HashMap<String, KualiDecimal> findDiscountAmountByAccount(String chart, String account, java.sql.Date begin, java.sql.Date end) {
return getCustomerAgingReportDao().findInvoiceAmountByAccount(chart, account, begin, end);
}
@Override
public KualiDecimal findWriteOffAmountByCustomerNumber(String customerNumber) {
return getCustomerAgingReportDao().findWriteOffAmountByCustomerNumber(customerNumber);
}
/**
*
* This method...
* @return
*/
public DateTimeService getDateTimeService() {
return dateTimeService;
}
/**
*
* This method...
* @param dateTimeService
*/
public void setDateTimeService(DateTimeService dateTimeService) {
this.dateTimeService = dateTimeService;
}
public void setParameterService(ParameterService parameterService) {
this.parameterService = parameterService;
}
public void setCustomerInvoiceDocumentService(CustomerInvoiceDocumentService customerInvoiceDocumentService) {
this.customerInvoiceDocumentService = customerInvoiceDocumentService;
}
public CustomerAgingReportDao getCustomerAgingReportDao() {
return customerAgingReportDao;
}
public void setCustomerAgingReportDao(CustomerAgingReportDao customerAgingReportDao) {
this.customerAgingReportDao = customerAgingReportDao;
}
}