/*
* 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.service.impl;
import java.io.IOException;
import java.sql.Date;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.mail.MessagingException;
import javax.mail.Session;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.coa.businessobject.Organization;
import org.kuali.kfs.integration.cg.ContractsAndGrantsBillingAward;
import org.kuali.kfs.module.ar.ArConstants;
import org.kuali.kfs.module.ar.ArKeyConstants;
import org.kuali.kfs.module.ar.ArPropertyConstants;
import org.kuali.kfs.module.ar.batch.UpcomingMilestoneNotificationStep;
import org.kuali.kfs.module.ar.businessobject.CustomerAddress;
import org.kuali.kfs.module.ar.businessobject.InvoiceAddressDetail;
import org.kuali.kfs.module.ar.businessobject.Milestone;
import org.kuali.kfs.module.ar.document.ContractsGrantsInvoiceDocument;
import org.kuali.kfs.module.ar.service.AREmailService;
import org.kuali.kfs.module.ar.service.ContractsGrantsBillingUtilityService;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.mail.AttachmentMailMessage;
import org.kuali.kfs.sys.service.AttachmentMailService;
import org.kuali.kfs.sys.service.NonTransactional;
import org.kuali.rice.core.api.config.property.ConfigContext;
import org.kuali.rice.core.api.config.property.ConfigurationService;
import org.kuali.rice.core.api.mail.MailMessage;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kns.service.DataDictionaryService;
import org.kuali.rice.krad.bo.Attachment;
import org.kuali.rice.krad.bo.Note;
import org.kuali.rice.krad.exception.InvalidAddressException;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.service.DocumentService;
import org.kuali.rice.krad.service.KualiModuleService;
import org.kuali.rice.krad.service.NoteService;
import org.kuali.rice.krad.service.impl.MailServiceImpl;
import org.kuali.rice.krad.util.ObjectUtils;
/**
* Defines methods for sending AR emails.
*/
public class AREmailServiceImpl implements AREmailService {
private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AREmailServiceImpl.class);
protected AttachmentMailService mailService;
protected ParameterService parameterService;
protected DataDictionaryService dataDictionaryService;
protected ConfigurationService kualiConfigurationService;
protected BusinessObjectService businessObjectService;
protected DocumentService documentService;
protected NoteService noteService;
protected KualiModuleService kualiModuleService;
protected ContractsGrantsBillingUtilityService contractsGrantsBillingUtilityService;
/**
* Sets the kualiModuleService attribute value.
*
* @param kualiModuleService The kualiModuleService to set.
*/
@NonTransactional
public void setKualiModuleService(KualiModuleService kualiModuleService) {
this.kualiModuleService = kualiModuleService;
}
public void setBusinessObjectService(BusinessObjectService businessObjectService) {
this.businessObjectService = businessObjectService;
}
/**
* This method gets the document service
*
* @return the document service
*/
public DocumentService getDocumentService() {
return documentService;
}
/**
* This method sets the document service
*
* @param documentService
*/
public void setDocumentService(DocumentService documentService) {
this.documentService = documentService;
}
/**
* This method is used to send emails to the agency
*
* @param invoices
*/
@Override
public boolean sendInvoicesViaEmail(Collection<ContractsGrantsInvoiceDocument> invoices) throws InvalidAddressException, MessagingException {
LOG.debug("sendInvoicesViaEmail() starting.");
boolean success = true;
Properties props = getConfigProperties();
// Get session
Session session = Session.getInstance(props, null);
for (ContractsGrantsInvoiceDocument invoice : invoices) {
List<InvoiceAddressDetail> invoiceAddressDetails = invoice.getInvoiceAddressDetails();
for (InvoiceAddressDetail invoiceAddressDetail : invoiceAddressDetails) {
if (ArConstants.InvoiceTransmissionMethod.EMAIL.equals(invoiceAddressDetail.getInvoiceTransmissionMethodCode())) {
Note note = noteService.getNoteByNoteId(invoiceAddressDetail.getNoteId());
if (ObjectUtils.isNotNull(note)) {
AttachmentMailMessage message = new AttachmentMailMessage();
String sender = parameterService.getParameterValueAsString(KFSConstants.OptionalModuleNamespaces.ACCOUNTS_RECEIVABLE, ArConstants.CONTRACTS_GRANTS_INVOICE_COMPONENT, ArConstants.FROM_EMAIL_ADDRESS);
message.setFromAddress(sender);
CustomerAddress customerAddress = invoiceAddressDetail.getCustomerAddress();
String recipients = invoiceAddressDetail.getCustomerEmailAddress();
if (StringUtils.isNotEmpty(recipients)) {
message.getToAddresses().add(recipients);
}
else {
LOG.warn("No recipients indicated.");
}
String subject = getSubject(invoice);
message.setSubject(subject);
if (StringUtils.isEmpty(subject)) {
LOG.warn("Empty subject being sent.");
}
String bodyText = getMessageBody(invoice, customerAddress);
message.setMessage(bodyText);
if (StringUtils.isEmpty(bodyText)) {
LOG.warn("Empty bodyText being sent.");
}
Attachment attachment = note.getAttachment();
if (ObjectUtils.isNotNull(attachment)) {
try {
message.setContent(IOUtils.toByteArray(attachment.getAttachmentContents()));
}
catch (IOException ex) {
LOG.error("Error setting attachment contents", ex);
throw new RuntimeException(ex);
}
message.setFileName(attachment.getAttachmentFileName());
message.setType(attachment.getAttachmentMimeTypeCode());
}
setupMailServiceForNonProductionInstance();
mailService.sendMessage(message);
invoiceAddressDetail.setInitialTransmissionDate(new Date(new java.util.Date().getTime()));
documentService.updateDocument(invoice);
} else {
success = false;
}
}
}
}
return success;
}
protected String getSubject(ContractsGrantsInvoiceDocument invoice) {
String subject = kualiConfigurationService.getPropertyValueAsString(ArKeyConstants.CGINVOICE_EMAIL_SUBJECT);
return MessageFormat.format(subject, invoice.getInvoiceGeneralDetail().getAward().getProposal().getGrantNumber(),
invoice.getInvoiceGeneralDetail().getProposalNumber(),
invoice.getDocumentNumber());
}
protected String getMessageBody(ContractsGrantsInvoiceDocument invoice, CustomerAddress customerAddress) {
String message = kualiConfigurationService.getPropertyValueAsString(ArKeyConstants.CGINVOICE_EMAIL_BODY);
String department = "";
String[] orgCode = invoice.getInvoiceGeneralDetail().getAward().getAwardPrimaryFundManager().getFundManager().getPrimaryDepartmentCode().split("-");
Map<String, Object> key = new HashMap<String, Object>();
key.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, orgCode[0].trim());
key.put(KFSPropertyConstants.ORGANIZATION_CODE, orgCode[1].trim());
Organization org = businessObjectService.findByPrimaryKey(Organization.class, key);
if (ObjectUtils.isNotNull(org)) {
department = org.getOrganizationName();
}
return MessageFormat.format(message, customerAddress.getCustomer().getCustomerName(),
customerAddress.getCustomerAddressName(),
invoice.getInvoiceGeneralDetail().getAward().getAwardPrimaryFundManager().getFundManager().getName(),
invoice.getInvoiceGeneralDetail().getAward().getAwardPrimaryFundManager().getProjectTitle(),
department,
invoice.getInvoiceGeneralDetail().getAward().getAwardPrimaryFundManager().getFundManager().getPhoneNumber(),
invoice.getInvoiceGeneralDetail().getAward().getAwardPrimaryFundManager().getFundManager().getEmailAddress());
}
/**
* Setup properties to handle mail messages in a non-production environment as appropriate.
*
* NOTE: We should be setting up configuration properties for these values, and once that is done
* this method can be removed.
*/
public void setupMailServiceForNonProductionInstance() {
if (!ConfigContext.getCurrentContextConfig().isProductionEnvironment()) {
((MailServiceImpl)mailService).setRealNotificationsEnabled(false);
((MailServiceImpl)mailService).setNonProductionNotificationMailingList(mailService.getBatchMailingList());
}
}
/**
* Sets the mailService attribute value.
*
* @param mailService The mailService to set.
*/
public void setMailService(AttachmentMailService mailService) {
this.mailService = mailService;
}
/**
* Sets the parameterService attribute value.
*
* @param parameterService The parameterService to set.
*/
public void setParameterService(ParameterService parameterService) {
this.parameterService = parameterService;
}
/**
* Sets the dataDictionaryService attribute value.
*
* @param dataDictionaryService The dataDictionaryService to set.
*/
public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
this.dataDictionaryService = dataDictionaryService;
}
/**
* Retrieves the Properties used to configure the Mailer. The property names configured in the Workflow configuration should
* match those of Java Mail.
*
* @return
*/
protected Properties getConfigProperties() {
return ConfigContext.getCurrentContextConfig().getProperties();
}
/**
* This method sends out emails for upcoming milestones.
*
* @see org.kuali.kfs.module.ar.service.CGEmailService#sendEmail(java.util.List, org.kuali.kfs.module.ar.businessobject.Award)
*/
@Override
public void sendEmailNotificationsForMilestones(List<Milestone> milestones, ContractsAndGrantsBillingAward award) {
LOG.debug("sendEmail() starting");
MailMessage message = new MailMessage();
message.setFromAddress(mailService.getBatchMailingList());
message.setSubject(getEmailSubject(ArConstants.REMINDER_EMAIL_SUBJECT));
message.getToAddresses().add(award.getAwardPrimaryFundManager().getFundManager().getEmailAddress());
StringBuffer body = new StringBuffer();
String messageKey = kualiConfigurationService.getPropertyValueAsString(ArKeyConstants.MESSAGE_CG_UPCOMING_MILESTONES_EMAIL_LINE_1);
body.append(messageKey + "\n\n");
for (Milestone milestone : milestones) {
String proposalNumber = dataDictionaryService.getAttributeLabel(Milestone.class, KFSPropertyConstants.PROPOSAL_NUMBER);
String milestoneNumber = dataDictionaryService.getAttributeLabel(Milestone.class, ArPropertyConstants.MilestoneFields.MILESTONE_NUMBER);
String milestoneDescription = dataDictionaryService.getAttributeLabel(Milestone.class, ArPropertyConstants.MilestoneFields.MILESTONE_DESCRIPTION);
String milestoneAmount = dataDictionaryService.getAttributeLabel(Milestone.class, ArPropertyConstants.MilestoneFields.MILESTONE_AMOUNT);
String milestoneExpectedCompletionDate = dataDictionaryService.getAttributeLabel(Milestone.class, ArPropertyConstants.MilestoneFields.MILESTONE_EXPECTED_COMPLETION_DATE);
body.append(proposalNumber + ": " + milestone.getProposalNumber() + " \n");
body.append(milestoneNumber + ": " + milestone.getMilestoneNumber() + " \n");
body.append(milestoneDescription + ": " + milestone.getMilestoneDescription() + " \n");
body.append(milestoneAmount + ": " + milestone.getMilestoneAmount() + " \n");
body.append(milestoneExpectedCompletionDate + ": " + milestone.getMilestoneExpectedCompletionDate() + " \n");
body.append("\n\n");
}
body.append("\n\n");
messageKey = kualiConfigurationService.getPropertyValueAsString(ArKeyConstants.MESSAGE_CG_UPCOMING_MILESTONES_EMAIL_LINE_2);
body.append(MessageFormat.format(messageKey, new Object[] { null }) + "\n\n");
message.setMessage(body.toString());
try {
mailService.sendMessage(message);
}
catch (InvalidAddressException | MessagingException ex) {
LOG.error("Problems sending milestones e-mail", ex);
throw new RuntimeException("Problems sending milestones e-mail", ex);
}
}
/**
* Retrieves the email subject text from system parameter then checks environment code and prepends to message if not
* production.
*
* @param subjectParmaterName name of parameter giving the subject text
* @return subject text
*/
protected String getEmailSubject(String subjectParmaterName) {
String subject = parameterService.getParameterValueAsString(UpcomingMilestoneNotificationStep.class, subjectParmaterName);
String productionEnvironmentCode = kualiConfigurationService.getPropertyValueAsString(KFSConstants.PROD_ENVIRONMENT_CODE_KEY);
String environmentCode = kualiConfigurationService.getPropertyValueAsString(KFSConstants.ENVIRONMENT_KEY);
if (!StringUtils.equals(productionEnvironmentCode, environmentCode)) {
subject = environmentCode + ": " + subject;
}
return subject;
}
/**
* Sets the noteService attribute value.
*
* @param noteService The noteService to set.
*/
public void setNoteService(NoteService noteService) {
this.noteService = noteService;
}
public ConfigurationService getKualiConfigurationService() {
return kualiConfigurationService;
}
public void setKualiConfigurationService(ConfigurationService kualiConfigurationService) {
this.kualiConfigurationService = kualiConfigurationService;
}
public ContractsGrantsBillingUtilityService getContractsGrantsBillingUtilityService() {
return contractsGrantsBillingUtilityService;
}
public void setContractsGrantsBillingUtilityService(ContractsGrantsBillingUtilityService contractsGrantsBillingUtilityService) {
this.contractsGrantsBillingUtilityService = contractsGrantsBillingUtilityService;
}
}