/*
* 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.batch.service.impl;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.module.ar.ArConstants;
import org.kuali.kfs.module.ar.ArParameterKeyConstants;
import org.kuali.kfs.module.ar.ArPropertyConstants;
import org.kuali.kfs.module.ar.batch.CustomerAgingReportNotificationStep;
import org.kuali.kfs.module.ar.batch.service.CustomerNotificationService;
import org.kuali.kfs.module.ar.businessobject.Customer;
import org.kuali.kfs.module.ar.businessobject.CustomerAgingReportDetail;
import org.kuali.kfs.module.ar.businessobject.OrganizationOptions;
import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument;
import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.service.KfsNotificationService;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.kuali.rice.core.api.mail.MailMessage;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.util.ObjectUtils;
import org.springframework.transaction.annotation.Transactional;
/**
* implement the customer notification service
*/
@Transactional
public class CustomerNotificationServiceImpl implements CustomerNotificationService {
private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CustomerNotificationServiceImpl.class);
private String agingReportTemplate;
private BusinessObjectService businessObjectService;
private CustomerInvoiceDocumentService customerInvoiceDocumentService;
private KfsNotificationService kfsNotificationService;
private ParameterService parameterService;
private DateTimeService dateTimeService;
/**
* @see org.kuali.kfs.module.ar.batch.service.CustomerNotificationService#sendCustomerAgingReport()
*/
@Override
public void sendCustomerAgingReport() {
Collection<CustomerInvoiceDocument> openAgingInvoiceDocuments = getQualifiedAgingInvoiceDocument();
Timestamp agingReportSentTime = this.getDateTimeService().getCurrentTimestamp();
for (CustomerInvoiceDocument invoiceDocument : openAgingInvoiceDocuments) {
this.sendCustomerAgingReport(invoiceDocument, agingReportSentTime);
}
}
/**
* @see org.kuali.kfs.module.ar.batch.service.CustomerNotificationService#sendCustomerAgingReport(org.kuali.kfs.module.ar.document.CustomerInvoiceDocument, java.sql.Timestamp)
*/
@Override
public void sendCustomerAgingReport(CustomerInvoiceDocument invoiceDocument, Timestamp agingReportSentTime) {
if (ObjectUtils.isNotNull(invoiceDocument)) {
invoiceDocument.setAgingReportSentTime(agingReportSentTime);
this.getBusinessObjectService().save(invoiceDocument);
}
MailMessage mailMessage = buildAgingReportMailMessage(invoiceDocument);
this.getKfsNotificationService().sendNotificationByMail(mailMessage);
}
/**
* get qualified aging customer invoice documents
*/
protected Collection<CustomerInvoiceDocument> getQualifiedAgingInvoiceDocument() {
Collection<CustomerInvoiceDocument> agingInvoiceDocuments = new ArrayList<CustomerInvoiceDocument>();
Integer invoiceAge = this.getCustomerAgingNotificationOnDays();
String selectionOption = this.getNotificationSelectionOption();
if(StringUtils.equals(ArConstants.ArNotificationOptions.PROCESSING_ORG.option, selectionOption)){
List<String> charts = this.getNotificationChartSelection();
List<String> organizations = this.getNotificationOrganizationSelection();
agingInvoiceDocuments = customerInvoiceDocumentService.getAllAgingInvoiceDocumentsByProcessing(charts, organizations, invoiceAge);
}
else if(StringUtils.equals(ArConstants.ArNotificationOptions.BILLING_ORG.option, selectionOption)){
List<String> charts = this.getNotificationChartSelection();
List<String> organizations = this.getNotificationOrganizationSelection();
agingInvoiceDocuments = customerInvoiceDocumentService.getAllAgingInvoiceDocumentsByBilling(charts, organizations, invoiceAge);
}
else if(StringUtils.equals(ArConstants.ArNotificationOptions.ACCOUNT.option, selectionOption)){
List<String> charts = this.getNotificationChartSelection();
List<String> accounts = this.getNotificationAccountSelection();
agingInvoiceDocuments = customerInvoiceDocumentService.getAllAgingInvoiceDocumentsByAccounts(charts, accounts, invoiceAge);
}
else{
throw new RuntimeException("The given notification option only can be one of the following values: " + ArConstants.ArNotificationOptions.values());
}
return agingInvoiceDocuments;
}
/**
* build mail message object from the given invoice document for aging report
*/
protected MailMessage buildAgingReportMailMessage(CustomerInvoiceDocument invoiceDocument) {
MailMessage mailMessage = new MailMessage();
Customer customer = invoiceDocument.getCustomer();
String senderEmailAddress = this.getNotificationSender();
mailMessage.setFromAddress(senderEmailAddress);
String customerEmailAddress = customer.getCustomerEmailAddress();
mailMessage.addToAddress(customerEmailAddress);
String notificationSubject = this.getNotificationSubject() + KFSConstants.SQUARE_BRACKET_LEFT + invoiceDocument.getCustomerName() + KFSConstants.SQUARE_BRACKET_RIGHT;
mailMessage.setSubject(notificationSubject);
String notificationBody = this.buildNotificationBody(invoiceDocument);
mailMessage.setMessage(notificationBody);
return mailMessage;
}
/**
* get the organization option that is associated with the given customer invoice document
*/
protected OrganizationOptions getOrganizationOptions(CustomerInvoiceDocument invoiceDocument) {
Map<String, String> criteria = new HashMap<String, String>();
criteria.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, invoiceDocument.getBillByChartOfAccountCode());
criteria.put(KFSPropertyConstants.ORGANIZATION_CODE, invoiceDocument.getBilledByOrganizationCode());
return businessObjectService.findByPrimaryKey(OrganizationOptions.class, criteria);
}
/**
* collect all the information from the given customer invoice document and build the notification body
*/
protected String buildNotificationBody(CustomerInvoiceDocument invoiceDocument) {
Map<String, Object> agingReportInformationHolder = new HashMap<String, Object>();
Customer customer = invoiceDocument.getCustomer();
String customerEmail = customer.getCustomerEmailAddress();
OrganizationOptions organizationOptions = this.getOrganizationOptions(invoiceDocument);
agingReportInformationHolder.put(ArPropertyConstants.CustomerInvoiceDocumentFields.CUSTOMER, customer);
agingReportInformationHolder.put(ArPropertyConstants.CUSTOMER_INVOICE_DOCUMENT, invoiceDocument);
agingReportInformationHolder.put(ArPropertyConstants.ORGANIZATION_OPTIONS, organizationOptions);
agingReportInformationHolder.put(KFSConstants.NOTIFICATION_TEXT_KEY, this.getNotificationText());
updateAgingAmount(invoiceDocument, agingReportInformationHolder);
return this.getKfsNotificationService().generateNotificationContent(this.getAgingReportTemplate(), agingReportInformationHolder);
}
/**
* update the aging amount bucket
*/
protected void updateAgingAmount(CustomerInvoiceDocument invoiceDocument, Map<String, Object> agingReportInformationHolder) {
agingReportInformationHolder.put(ArConstants.CustomerAgingReportFields.TOTAL_0_TO_30, KualiDecimal.ZERO);
agingReportInformationHolder.put(ArConstants.CustomerAgingReportFields.TOTAL_31_TO_60, KualiDecimal.ZERO);
agingReportInformationHolder.put(ArConstants.CustomerAgingReportFields.TOTAL_61_TO_90, KualiDecimal.ZERO);
agingReportInformationHolder.put(ArConstants.CustomerAgingReportFields.TOTAL_91_TO_SYSPR, KualiDecimal.ZERO);
Integer invoiceAge = invoiceDocument.getAge();
KualiDecimal openAmount = invoiceDocument.getOpenAmount();
if(invoiceAge <= 30){
agingReportInformationHolder.put(ArConstants.CustomerAgingReportFields.TOTAL_0_TO_30, openAmount);
}
else if(invoiceAge <= 60){
agingReportInformationHolder.put(ArConstants.CustomerAgingReportFields.TOTAL_31_TO_60, openAmount);
}
else if(invoiceAge <= 90){
agingReportInformationHolder.put(ArConstants.CustomerAgingReportFields.TOTAL_61_TO_90, openAmount);
}
else{
agingReportInformationHolder.put(ArConstants.CustomerAgingReportFields.TOTAL_91_TO_SYSPR, openAmount);
}
}
/**
* get the email notification sender from an application parameter
*/
protected String getNotificationSender() {
return this.getParameterService().getParameterValueAsString(CustomerAgingReportNotificationStep.class, ArParameterKeyConstants.FROM_EMAIL_ADDRESS_PARAM_NM);
}
/**
* get the timing of when the aging email notification should be sent
*/
protected Integer getCustomerAgingNotificationOnDays() {
String daysAsString = this.getParameterService().getParameterValueAsString(CustomerAgingReportNotificationStep.class, ArParameterKeyConstants.NOTIFICATION_DAYS_PARAM_NM);
if (!StringUtils.isNumeric(daysAsString)) {
daysAsString = this.getParameterService().getParameterValueAsString(CustomerAgingReportDetail.class, ArConstants.CUSTOMER_INVOICE_AGE);
}
return Integer.parseInt(daysAsString);
}
/**
* get the notification selection option from an application parameter
*/
protected String getNotificationSelectionOption() {
return this.getParameterService().getParameterValueAsString(CustomerAgingReportNotificationStep.class, ArParameterKeyConstants.NOTIFICATION_SELECTION_TYPE_PARAM_NM);
}
/**
* get the chart values from notification selection criteria.
*/
protected List<String> getNotificationChartSelection() {
return this.getNotificationSelection(ArConstants.ArNotificationSelectionField.CHART.fieldName);
}
/**
* get the organization values from notification selection criteria.
*/
protected List<String> getNotificationOrganizationSelection() {
return this.getNotificationSelection(ArConstants.ArNotificationSelectionField.ORGANIZATION.fieldName);
}
/**
* get the account values from notification selection criteria.
*/
protected List<String> getNotificationAccountSelection() {
return this.getNotificationSelection(ArConstants.ArNotificationSelectionField.ACCOUNT.fieldName);
}
/**
* get the values from notification selection criteria by search option
*/
protected List<String> getNotificationSelection(String fieldName) {
return new ArrayList<String>(this.getParameterService().getSubParameterValuesAsString(CustomerAgingReportNotificationStep.class, ArParameterKeyConstants.NOTIFICATION_SELECTION_PARAM_NM, fieldName));
}
/**
* get the notification text from an application parameter
*/
protected String getNotificationText() {
return this.getParameterService().getParameterValueAsString(CustomerAgingReportNotificationStep.class, ArParameterKeyConstants.NOTIFICATION_TEXT_PARAM_NM);
}
/**
* get the notification subject from an application parameter
*/
protected String getNotificationSubject() {
return this.getParameterService().getParameterValueAsString(CustomerAgingReportNotificationStep.class, ArParameterKeyConstants.NOTIFICATION_SUBJECT_PARAM_NM);
}
/**
* Gets the agingReportTemplate attribute.
*
* @return Returns the agingReportTemplate.
*/
public String getAgingReportTemplate() {
return agingReportTemplate;
}
/**
* Sets the agingReportTemplate attribute value.
*
* @param agingReportTemplate The agingReportTemplate to set.
*/
public void setAgingReportTemplate(String agingReportTemplate) {
this.agingReportTemplate = agingReportTemplate;
}
/**
* Gets the businessObjectService attribute.
*
* @return Returns the businessObjectService.
*/
public BusinessObjectService getBusinessObjectService() {
return businessObjectService;
}
/**
* Sets the businessObjectService attribute value.
*
* @param businessObjectService The businessObjectService to set.
*/
public void setBusinessObjectService(BusinessObjectService businessObjectService) {
this.businessObjectService = businessObjectService;
}
/**
* Gets the customerInvoiceDocumentService attribute.
*
* @return Returns the customerInvoiceDocumentService.
*/
public CustomerInvoiceDocumentService getCustomerInvoiceDocumentService() {
return customerInvoiceDocumentService;
}
/**
* Sets the customerInvoiceDocumentService attribute value.
*
* @param customerInvoiceDocumentService The customerInvoiceDocumentService to set.
*/
public void setCustomerInvoiceDocumentService(CustomerInvoiceDocumentService customerInvoiceDocumentService) {
this.customerInvoiceDocumentService = customerInvoiceDocumentService;
}
/**
* Gets the kfsNotificationService attribute.
*
* @return Returns the kfsNotificationService.
*/
public KfsNotificationService getKfsNotificationService() {
return kfsNotificationService;
}
/**
* Sets the kfsNotificationService attribute value.
*
* @param kfsNotificationService The kfsNotificationService to set.
*/
public void setKfsNotificationService(KfsNotificationService kfsNotificationService) {
this.kfsNotificationService = kfsNotificationService;
}
/**
* Gets the parameterService attribute.
*
* @return Returns the parameterService.
*/
public ParameterService getParameterService() {
return parameterService;
}
/**
* Sets the parameterService attribute value.
*
* @param parameterService The parameterService to set.
*/
public void setParameterService(ParameterService parameterService) {
this.parameterService = parameterService;
}
/**
* Gets the dateTimeService attribute.
* @return Returns the dateTimeService.
*/
public DateTimeService getDateTimeService() {
return dateTimeService;
}
/**
* Sets the dateTimeService attribute value.
* @param dateTimeService The dateTimeService to set.
*/
public void setDateTimeService(DateTimeService dateTimeService) {
this.dateTimeService = dateTimeService;
}
}