/* * 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.pdp.service.impl; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.fp.document.DisbursementVoucherConstants; import org.kuali.kfs.pdp.PdpKeyConstants; import org.kuali.kfs.pdp.PdpParameterConstants; import org.kuali.kfs.pdp.PdpPropertyConstants; import org.kuali.kfs.pdp.batch.ExtractAchPaymentsStep; import org.kuali.kfs.pdp.batch.LoadPaymentsStep; import org.kuali.kfs.pdp.batch.SendAchAdviceNotificationsStep; import org.kuali.kfs.pdp.businessobject.ACHBank; import org.kuali.kfs.pdp.businessobject.Batch; import org.kuali.kfs.pdp.businessobject.CustomerProfile; import org.kuali.kfs.pdp.businessobject.PaymentDetail; import org.kuali.kfs.pdp.businessobject.PaymentFileLoad; import org.kuali.kfs.pdp.businessobject.PaymentGroup; import org.kuali.kfs.pdp.businessobject.PaymentNoteText; import org.kuali.kfs.pdp.service.AchBankService; import org.kuali.kfs.pdp.service.CustomerProfileService; import org.kuali.kfs.pdp.service.PdpEmailService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.document.PaymentSource; import org.kuali.kfs.sys.service.impl.KfsParameterConstants; 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.core.api.util.type.KualiDecimal; import org.kuali.rice.core.web.format.CurrencyFormatter; import org.kuali.rice.core.web.format.Formatter; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.kim.api.identity.Person; import org.kuali.rice.kns.service.DataDictionaryService; import org.kuali.rice.krad.service.MailService; import org.kuali.rice.krad.util.ErrorMessage; import org.kuali.rice.krad.util.MessageMap; /** * @see org.kuali.kfs.pdp.service.PdpEmailService */ public class PdpEmailServiceImpl implements PdpEmailService { private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PdpEmailServiceImpl.class); protected CustomerProfileService customerProfileService; protected ConfigurationService kualiConfigurationService; protected MailService mailService; protected ParameterService parameterService; protected DataDictionaryService dataDictionaryService; protected AchBankService achBankService; /** * @see org.kuali.kfs.pdp.service.PdpEmailService#sendErrorEmail(org.kuali.kfs.pdp.businessobject.PaymentFileLoad, * org.kuali.rice.kns.util.ErrorMap) */ @Override public void sendErrorEmail(PaymentFileLoad paymentFile, MessageMap errors) { LOG.debug("sendErrorEmail() starting"); // check email configuration if (!isPaymentEmailEnabled()) { return; } MailMessage message = new MailMessage(); String returnAddress = parameterService.getParameterValueAsString(KfsParameterConstants.PRE_DISBURSEMENT_BATCH.class, KFSConstants.FROM_EMAIL_ADDRESS_PARM_NM); if(StringUtils.isEmpty(returnAddress)) { returnAddress = mailService.getBatchMailingList(); } message.setFromAddress(returnAddress); message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_FAILURE_EMAIL_SUBJECT_PARAMETER_NAME)); StringBuilder body = new StringBuilder(); List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC) ); if (paymentFile == null) { if (ccAddresses.isEmpty()) { LOG.error("sendErrorEmail() No HARD_EDIT_CC addresses. No email sent"); return; } message.getToAddresses().addAll(ccAddresses); body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_BAD_FILE_PARSE) + "\n\n"); } else { CustomerProfile customer = customerProfileService.get(paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit()); if (customer == null) { LOG.error("sendErrorEmail() Invalid Customer. Sending email to CC addresses"); if (ccAddresses.isEmpty()) { LOG.error("sendErrorEmail() No HARD_EDIT_CC addresses. No email sent"); return; } message.getToAddresses().addAll(ccAddresses); body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_INVALID_CUSTOMER) + "\n\n"); } else { String toAddresses = StringUtils.deleteWhitespace(customer.getProcessingEmailAddr()); List<String> toAddressList = Arrays.asList(toAddresses.split(",")); message.getToAddresses().addAll(toAddressList); message.getCcAddresses().addAll(ccAddresses); //TODO: for some reason the mail service does not work unless the bcc list has addresss. This is a temporary workaround message.getBccAddresses().addAll(ccAddresses); } } if (paymentFile != null) { body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_NOT_LOADED) + "\n\n"); addPaymentFieldsToBody(body, null, paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount()); } body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_ERROR_MESSAGES) + "\n"); List<ErrorMessage> errorMessages = errors.getMessages(KFSConstants.GLOBAL_ERRORS); if (errorMessages != null) { for (ErrorMessage errorMessage : errorMessages) { body.append(getMessage(errorMessage.getErrorKey(), (Object[]) errorMessage.getMessageParameters()) + "\n\n"); } message.setMessage(body.toString()); // KFSMI-6475 - if not a production instance, replace the recipients with the testers list alterMessageWhenNonProductionInstance(message, null); try { mailService.sendMessage(message); } catch (Exception e) { LOG.error("sendErrorEmail() caught an exception while trying to sendMessage. Message not sent", e); throw new RuntimeException (e); } } } /** * KFSMI-6475 - Alter the subject and switch all recipients * * @param message * @param environmentCode */ @SuppressWarnings("rawtypes") public void alterMessageWhenNonProductionInstance( MailMessage message, String environmentCode ) { if (! ConfigContext.getCurrentContextConfig().isProductionEnvironment()) { // insert the original recipients into the beginning of the message StringBuilder recipients = new StringBuilder(); recipients.append("Intended To : ").append(message.getToAddresses().toString()).append('\n'); recipients.append("Intended Cc : ").append(message.getCcAddresses().toString()).append('\n'); recipients.append("Intended Bcc: ").append(message.getBccAddresses().toString()).append('\n'); recipients.append('\n'); message.setMessage( recipients.toString() + message.getMessage() ); // Clear out the recipients message.setToAddresses(new HashSet()); message.setCcAddresses(Collections.emptySet()); message.setBccAddresses(Collections.emptySet()); // Set all to the batch mailing list message.addToAddress(mailService.getBatchMailingList()); } } /** * @see org.kuali.kfs.pdp.service.PdpEmailService#sendLoadEmail(org.kuali.kfs.pdp.businessobject.PaymentFileLoad, * java.util.List) */ @Override public void sendLoadEmail(PaymentFileLoad paymentFile, List<String> warnings) { LOG.debug("sendLoadEmail() starting"); // check email configuration if (!isPaymentEmailEnabled()) { return; } MailMessage message = new MailMessage(); String returnAddress = parameterService.getParameterValueAsString(KfsParameterConstants.PRE_DISBURSEMENT_BATCH.class, KFSConstants.FROM_EMAIL_ADDRESS_PARM_NM); if(StringUtils.isEmpty(returnAddress)) { returnAddress = mailService.getBatchMailingList(); } message.setFromAddress(returnAddress); message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_SUCCESS_EMAIL_SUBJECT_PARAMETER_NAME)); List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC) ); message.getCcAddresses().addAll(ccAddresses); message.getBccAddresses().addAll(ccAddresses); CustomerProfile customer = customerProfileService.get(paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit()); String toAddresses = StringUtils.deleteWhitespace(customer.getProcessingEmailAddr()); List<String> toAddressList = Arrays.asList(toAddresses.split(",")); message.getToAddresses().addAll(toAddressList); StringBuilder body = new StringBuilder(); body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_LOADED) + "\n\n"); addPaymentFieldsToBody(body, paymentFile.getBatchId().intValue(), paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount()); body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_WARNING_MESSAGES) + "\n"); for (String warning : warnings) { body.append(warning + "\n\n"); } message.setMessage(body.toString()); // KFSMI-6475 - if not a production instance, replace the recipients with the testers list alterMessageWhenNonProductionInstance(message, null); try { mailService.sendMessage(message); } catch (Exception e) { LOG.error("sendErrorEmail() Invalid email address. Message not sent", e); } if (paymentFile.isFileThreshold()) { sendThresholdEmail(true, paymentFile, customer); } if (paymentFile.isDetailThreshold()) { sendThresholdEmail(false, paymentFile, customer); } } /** * Sends email for a payment that was over the customer file threshold or the detail threshold * * @param fileThreshold indicates whether the file threshold (true) was violated or the detail threshold (false) * @param paymentFile parsed payment file object * @param customer payment customer */ protected void sendThresholdEmail(boolean fileThreshold, PaymentFileLoad paymentFile, CustomerProfile customer) { MailMessage message = new MailMessage(); String returnAddress = parameterService.getParameterValueAsString(KfsParameterConstants.PRE_DISBURSEMENT_BATCH.class, KFSConstants.FROM_EMAIL_ADDRESS_PARM_NM); if(StringUtils.isEmpty(returnAddress)) { returnAddress = mailService.getBatchMailingList(); } message.setFromAddress(returnAddress); message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_THRESHOLD_EMAIL_SUBJECT_PARAMETER_NAME)); StringBuilder body = new StringBuilder(); body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_LOADED) + "\n\n"); addPaymentFieldsToBody(body, paymentFile.getBatchId().intValue(), paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount()); if (fileThreshold) { String toAddresses = StringUtils.deleteWhitespace(customer.getFileThresholdEmailAddress()); List<String> toAddressList = Arrays.asList(toAddresses.split(",")); message.getToAddresses().addAll(toAddressList); body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_THRESHOLD, paymentFile.getPaymentTotalAmount(), customer.getFileThresholdAmount())); } else { String toAddresses = StringUtils.deleteWhitespace(customer.getPaymentThresholdEmailAddress()); List<String> toAddressList = Arrays.asList(toAddresses.split(",")); message.getToAddresses().addAll(toAddressList); body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_DETAIL_THRESHOLD, customer.getPaymentThresholdAmount()) + "\n\n"); for (PaymentDetail paymentDetail : paymentFile.getThresholdPaymentDetails()) { paymentDetail.refresh(); body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_THRESHOLD, paymentDetail.getPaymentGroup().getPayeeName(), paymentDetail.getNetPaymentAmount()) + "\n"); } } List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC) ); message.getCcAddresses().addAll(ccAddresses); message.getBccAddresses().addAll(ccAddresses); message.setMessage(body.toString()); // KFSMI-6475 - if not a production instance, replace the recipients with the testers list alterMessageWhenNonProductionInstance(message, null); try { mailService.sendMessage(message); } catch (Exception e) { LOG.error("sendErrorEmail() Invalid email address. Message not sent", e); } } /** * @see org.kuali.kfs.pdp.service.PdpEmailService#sendTaxEmail(org.kuali.kfs.pdp.businessobject.PaymentFileLoad) */ @Override public void sendTaxEmail(PaymentFileLoad paymentFile) { LOG.debug("sendTaxEmail() starting"); MailMessage message = new MailMessage(); String returnAddress = parameterService.getParameterValueAsString(KfsParameterConstants.PRE_DISBURSEMENT_BATCH.class, KFSConstants.FROM_EMAIL_ADDRESS_PARM_NM); if(StringUtils.isEmpty(returnAddress)) { returnAddress = mailService.getBatchMailingList(); } message.setFromAddress(returnAddress); message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_TAX_EMAIL_SUBJECT_PARAMETER_NAME)); StringBuilder body = new StringBuilder(); String taxEmail = parameterService.getParameterValueAsString(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_GROUP_EMAIL_ADDRESS); if (StringUtils.isBlank(taxEmail)) { LOG.error("No Tax E-mail Application Setting found to send notification e-mail"); return; } else { message.addToAddress(taxEmail); } List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC) ); message.getCcAddresses().addAll(ccAddresses); message.getBccAddresses().addAll(ccAddresses); body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_TAX_LOADED) + "\n\n"); addPaymentFieldsToBody(body, paymentFile.getBatchId().intValue(), paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount()); body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_GO_TO_PDP) + "\n"); message.setMessage(body.toString()); // KFSMI-6475 - if not a production instance, replace the recipients with the testers list alterMessageWhenNonProductionInstance(message, null); try { mailService.sendMessage(message); } catch (Exception e) { LOG.error("sendErrorEmail() Invalid email address. Message not sent", e); } } /** * @see org.kuali.kfs.pdp.service.PdpEmailService#sendLoadEmail(org.kuali.kfs.pdp.businessobject.Batch) */ @Override public void sendLoadEmail(Batch batch) { LOG.debug("sendLoadEmail() starting"); // check email configuration if (!isPaymentEmailEnabled()) { return; } MailMessage message = new MailMessage(); String returnAddress = parameterService.getParameterValueAsString( KfsParameterConstants.PRE_DISBURSEMENT_BATCH.class, KFSConstants.FROM_EMAIL_ADDRESS_PARM_NM); if(StringUtils.isEmpty(returnAddress)) { returnAddress = mailService.getBatchMailingList(); } message.setFromAddress(returnAddress); message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_SUCCESS_EMAIL_SUBJECT_PARAMETER_NAME)); StringBuilder body = new StringBuilder(); List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC) ); message.getCcAddresses().addAll(ccAddresses); message.getBccAddresses().addAll(ccAddresses); CustomerProfile customer = batch.getCustomerProfile(); String toAddresses = StringUtils.deleteWhitespace(customer.getProcessingEmailAddr()); List<String> toAddressList = Arrays.asList(toAddresses.split(",")); message.getToAddresses().addAll(toAddressList); body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_LOADED) + "\n\n"); addPaymentFieldsToBody(body, batch.getId().intValue(), customer.getChartCode(), customer.getUnitCode(), customer.getSubUnitCode(), batch.getCustomerFileCreateTimestamp(), batch.getPaymentCount().intValue(), batch.getPaymentTotalAmount()); message.setMessage(body.toString()); // KFSMI-6475 - if not a production instance, replace the recipients with the testers list alterMessageWhenNonProductionInstance(message, null); try { mailService.sendMessage(message); } catch (Exception e) { LOG.error("sendErrorEmail() Invalid email address. Message not sent", e); } } /** * @see org.kuali.kfs.pdp.service.PdpEmailService#sendExceedsMaxNotesWarningEmail(java.util.List, java.util.List, int, int) */ @Override public void sendExceedsMaxNotesWarningEmail(List<String> creditMemos, List<String> paymentRequests, int lineTotal, int maxNoteLines) { LOG.debug("sendExceedsMaxNotesWarningEmail() starting"); // check email configuration if (!isPaymentEmailEnabled()) { return; } MailMessage message = new MailMessage(); String returnAddress = parameterService.getParameterValueAsString(KFSConstants.ParameterNamespaces.PDP, "Batch", KFSConstants.FROM_EMAIL_ADDRESS_PARM_NM); if(StringUtils.isEmpty(returnAddress)) { returnAddress = mailService.getBatchMailingList(); } message.setFromAddress(returnAddress); StringBuilder body = new StringBuilder(); message.setSubject(getMessage(PdpKeyConstants.MESSAGE_PURAP_EXTRACT_MAX_NOTES_SUBJECT)); // Get recipient email address String toAddresses = parameterService.getParameterValueAsString(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.PDP_ERROR_EXCEEDS_NOTE_LIMIT_EMAIL); List<String> toAddressList = Arrays.asList(toAddresses.split(",")); message.getToAddresses().addAll(toAddressList); List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.SOFT_EDIT_CC) ); message.getCcAddresses().addAll(ccAddresses); message.getBccAddresses().addAll(ccAddresses); body.append(getMessage(PdpKeyConstants.MESSAGE_PURAP_EXTRACT_MAX_NOTES_MESSAGE, StringUtils.join(creditMemos, ","), StringUtils.join(paymentRequests, ","), lineTotal, maxNoteLines)); message.setMessage(body.toString()); // KFSMI-6475 - if not a production instance, replace the recipients with the testers list alterMessageWhenNonProductionInstance(message, null); try { mailService.sendMessage(message); } catch (Exception e) { LOG.error("sendExceedsMaxNotesWarningEmail() Invalid email address. Message not sent", e); } } /** * @see org.kuali.kfs.pdp.service.PdpEmailService#sendAchSummaryEmail(java.util.Map, java.util.Map, java.util.Date) */ @Override public void sendAchSummaryEmail(Map<String, Integer> unitCounts, Map<String, KualiDecimal> unitTotals, Date disbursementDate) { LOG.debug("sendAchSummaryEmail() starting"); MailMessage message = new MailMessage(); List<String> toAddressList = new ArrayList<String>( parameterService.getParameterValuesAsString(ExtractAchPaymentsStep.class, PdpParameterConstants.ACH_SUMMARY_TO_EMAIL_ADDRESS_PARMAETER_NAME) ); message.getToAddresses().addAll(toAddressList); message.getCcAddresses().addAll(toAddressList); message.getBccAddresses().addAll(toAddressList); String returnAddress = parameterService.getParameterValueAsString(KFSConstants.ParameterNamespaces.PDP, "Batch", KFSConstants.FROM_EMAIL_ADDRESS_PARM_NM); if(StringUtils.isEmpty(returnAddress)) { returnAddress = mailService.getBatchMailingList(); } message.setFromAddress(returnAddress); String subject = parameterService.getParameterValueAsString(ExtractAchPaymentsStep.class, PdpParameterConstants.ACH_SUMMARY_EMAIL_SUBJECT_PARAMETER_NAME); message.setSubject(subject); StringBuilder body = new StringBuilder(); body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_SUMMARY_EMAIL_DISB_DATE, disbursementDate) + "\n"); Integer totalCount = 0; KualiDecimal totalAmount = KualiDecimal.ZERO; for (String unit : unitCounts.keySet()) { body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_SUMMARY_EMAIL_UNIT_TOTAL, StringUtils.leftPad(unit, 13), StringUtils.leftPad(unitCounts.get(unit).toString(), 10), StringUtils.leftPad(unitTotals.get(unit).toString(), 20)) + "\n"); totalCount = totalCount + unitCounts.get(unit); totalAmount = totalAmount.add(unitTotals.get(unit)); } body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_SUMMARY_EMAIL_EXTRACT_TOTALS, StringUtils.leftPad(totalCount.toString(), 10), StringUtils.leftPad(totalAmount.toString(), 20)) + "\n"); body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_SUMMARY_EMAIL_COMPLETE)); message.setMessage(body.toString()); // KFSMI-6475 - if not a production instance, replace the recipients with the testers list alterMessageWhenNonProductionInstance(message, null); try { mailService.sendMessage(message); } catch (Exception e) { LOG.error("sendAchSummaryEmail() Invalid email address. Message not sent", e); } } /** * @see org.kuali.kfs.pdp.service.PdpEmailService#sendAchAdviceEmail(org.kuali.kfs.pdp.businessobject.PaymentGroup, * org.kuali.kfs.pdp.businessobject.CustomerProfile, org.kuali.kfs.pdp.businessobject.PaymentDetail) */ @Override public void sendAchAdviceEmail(PaymentGroup paymentGroup, PaymentDetail paymentDetail, CustomerProfile customer) { LOG.debug("sendAchAdviceEmail() starting"); MailMessage message = new MailMessage(); String fromAddresses = customer.getAdviceReturnEmailAddr(); String toAddresses = paymentGroup.getAdviceEmailAddress(); Collection<String> ccAddresses = parameterService.getParameterValuesAsString(SendAchAdviceNotificationsStep.class, PdpParameterConstants.ACH_SUMMARY_CC_EMAIL_ADDRESSES_PARMAETER_NAME); Collection<String> bccAddresses = parameterService.getParameterValuesAsString(SendAchAdviceNotificationsStep.class, PdpParameterConstants.ACH_SUMMARY_BCC_EMAIL_ADDRESSES_PARMAETER_NAME); String batchAddresses = mailService.getBatchMailingList(); String subject = customer.getAdviceSubjectLine(); message.addToAddress(toAddresses); if(!ccAddresses.isEmpty()){ message.getCcAddresses().addAll(ccAddresses); } if(!bccAddresses.isEmpty()){ message.getBccAddresses().addAll(bccAddresses); } message.setFromAddress(fromAddresses); message.setSubject(subject); /* NOTE: The following code is unnecessary and counter-productive, because alterMessageWhenNonProductionInstance called below handles non-prd env * email to/cc addresses and subject properly, while Rice MailService handles adding app and env code in front of the subject line. * There's no need to add another layer to replace these addresses and subject. Replacing the real address with batchAddress will only result * in wiping out the original real addresses, which would have been added to the message body by MailService, for testing purpose. if (StringUtils.equals(productionEnvironmentCode, environmentCode)) { message.addToAddress(toAddresses); message.addCcAddress(ccAddresses); message.addBccAddress(ccAddresses); message.setFromAddress(fromAddresses); message.setSubject(subject); } else { message.addToAddress(batchAddresses); message.addCcAddress(batchAddresses); message.addBccAddress(batchAddresses); message.setFromAddress(fromAddresses); message.setSubject(environmentCode + ": " + subject + ":" + toAddresses); } */ if (LOG.isDebugEnabled()) { LOG.debug("sending email to " + toAddresses + " for disb # " + paymentGroup.getDisbursementNbr()); } StringBuilder body = new StringBuilder(); body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_EMAIL_TOFROM, paymentGroup.getPayeeName(), customer.getAchPaymentDescription())); // formatter for payment amounts Formatter formatter = new CurrencyFormatter(); // get bank name to which the payment is being transferred String bankName = ""; ACHBank achBank = achBankService.getByPrimaryId(paymentGroup.getAchBankRoutingNbr()); if (achBank == null) { LOG.error("Bank cound not be found for routing number " + paymentGroup.getAchBankRoutingNbr()); } else { bankName = achBank.getBankName(); } body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_EMAIL_BANKAMOUNT, bankName, formatter.formatForPresentation(paymentDetail.getNetPaymentAmount()))); // print detail amounts int labelPad = 25; String newPaymentAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_NET_AMOUNT); body.append(StringUtils.rightPad(newPaymentAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getNetPaymentAmount()) + "\n"); if (paymentDetail.getOrigInvoiceAmount().isNonZero()) { String origInvoiceAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_ORIGINAL_INVOICE_AMOUNT); body.append(StringUtils.rightPad(origInvoiceAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getOrigInvoiceAmount()) + "\n"); } if (paymentDetail.getInvTotDiscountAmount().isNonZero()) { String invTotDiscountAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_DISCOUNT_AMOUNT); body.append(StringUtils.rightPad(invTotDiscountAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotDiscountAmount()) + "\n"); } if (paymentDetail.getInvTotShipAmount().isNonZero()) { String invTotShippingAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_SHIPPING_AMOUNT); body.append(StringUtils.rightPad(invTotShippingAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotShipAmount()) + "\n"); } if (paymentDetail.getInvTotOtherDebitAmount().isNonZero()) { String invTotOtherDebitAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_OTHER_DEBIT_AMOUNT); body.append(StringUtils.rightPad(invTotOtherDebitAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotOtherDebitAmount()) + "\n"); } if (paymentDetail.getInvTotOtherCreditAmount().isNonZero()) { String invTotOtherCreditAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_OTHER_CREDIT_AMOUNT); body.append(StringUtils.rightPad(invTotOtherCreditAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotOtherCreditAmount()) + "\n"); } body.append("\n" + customer.getAdviceHeaderText() + "\n"); if (StringUtils.isNotBlank(paymentDetail.getPurchaseOrderNbr())) { String purchaseOrderNbrLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_PURCHASE_ORDER_NUMBER); body.append(StringUtils.rightPad(purchaseOrderNbrLabel, labelPad) + paymentDetail.getPurchaseOrderNbr() + "\n"); } if (StringUtils.isNotBlank(paymentDetail.getInvoiceNbr())) { String invoiceNbrLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_NUMBER); body.append(StringUtils.rightPad(invoiceNbrLabel, labelPad) + paymentDetail.getInvoiceNbr() + "\n"); } if (StringUtils.isNotBlank(paymentDetail.getCustPaymentDocNbr())) { String custPaymentDocNbrLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_CUSTOMER_DOC_NUMBER); body.append(StringUtils.rightPad(custPaymentDocNbrLabel, labelPad) + paymentDetail.getCustPaymentDocNbr() + "\n"); } if (StringUtils.isNotBlank(paymentDetail.getCustomerInstitutionNumber())) { String customerInstituitionNbrLabel = dataDictionaryService.getAttributeLabel(PaymentGroup.class, PdpPropertyConstants.CUSTOMER_INSTITUTION_NUMBER); body.append(StringUtils.rightPad(customerInstituitionNbrLabel, labelPad) + paymentDetail.getCustomerInstitutionNumber() + "\n"); } body.append("\n"); // print payment notes for (PaymentNoteText paymentNoteText : paymentDetail.getNotes()) { body.append(paymentNoteText.getCustomerNoteText() + "\n"); } if (paymentDetail.getNotes().isEmpty()) { body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_EMAIL_NONOTES)); } message.setMessage(body.toString()); // KFSMI-6475 - if not a production instance, replace the recipients with the testers list alterMessageWhenNonProductionInstance(message, null); try { mailService.sendMessage(message); } catch (Exception e) { LOG.error("sendAchAdviceEmail() Invalid email address. Sending message to " + customer.getAdviceReturnEmailAddr(), e); // send notification to advice return address with payment details- need a new MailMessage here of course MailMessage msg = new MailMessage(); msg.addToAddress(customer.getAdviceReturnEmailAddr()); String returnAddress = parameterService.getParameterValueAsString(KFSConstants.ParameterNamespaces.PDP, "Batch", KFSConstants.FROM_EMAIL_ADDRESS_PARM_NM); if(StringUtils.isEmpty(returnAddress)) { returnAddress = mailService.getBatchMailingList(); } msg.setFromAddress(returnAddress); msg.setSubject(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_INVALID_EMAIL_ADDRESS)); LOG.warn("bouncing email to " + customer.getAdviceReturnEmailAddr() + " for disb # " + paymentGroup.getDisbursementNbr()); // KFSMI-6475 - if not a production instance, replace the recipients with the testers list alterMessageWhenNonProductionInstance(msg, null); try { mailService.sendMessage(msg); } catch (Exception e1) { LOG.error("Could not send email to advice return email address on customer profile: " + customer.getAdviceReturnEmailAddr(), e1); throw new RuntimeException("Could not send email to advice return email address on customer profile: " + customer.getAdviceReturnEmailAddr()); } } } /** * * @see org.kuali.kfs.pdp.service.PdpEmailService#sendCancelEmail(org.kuali.kfs.pdp.businessobject.PaymentGroup, java.lang.String, org.kuali.rice.kim.bo.Person) */ @Override public void sendCancelEmail(PaymentGroup paymentGroup, String note, Person user) { LOG.debug("sendCancelEmail() starting"); MailMessage message = new MailMessage(); message.setSubject("PDP --- Cancelled Payment by Tax"); CustomerProfile cp = paymentGroup.getBatch().getCustomerProfile(); String toAddresses = cp.getAdviceReturnEmailAddr(); String toAddressList[] = toAddresses.split(","); if (toAddressList.length > 0) { for (int i = 0; i < toAddressList.length; i++) { if (toAddressList[i] != null) { message.addToAddress(toAddressList[i].trim()); message.addBccAddress(toAddressList[i].trim()); } } } // message.addToAddress(cp.getAdviceReturnEmailAddr()); String ccAddresses = parameterService.getParameterValueAsString(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_CANCEL_EMAIL_LIST); String ccAddressList[] = ccAddresses.split(","); if (ccAddressList.length > 0) { for (int i = 0; i < ccAddressList.length; i++) { if (ccAddressList[i] != null) { message.addCcAddress(ccAddressList[i].trim()); } } } String fromAddressList[] = { mailService.getBatchMailingList() }; if (fromAddressList.length > 0) { for (int i = 0; i < fromAddressList.length; i++) { if (fromAddressList[i] != null) { message.setFromAddress(fromAddressList[i].trim()); } } } StringBuilder body = new StringBuilder(); String messageKey = kualiConfigurationService.getPropertyValueAsString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_1); body.append(MessageFormat.format(messageKey, new Object[] { null }) + " \n\n"); body.append(note + "\n\n"); String taxEmail = parameterService.getParameterValueAsString(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_GROUP_EMAIL_ADDRESS); String taxContactDepartment = parameterService.getParameterValueAsString(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_CANCEL_CONTACT); if (StringUtils.isBlank(taxEmail)) { messageKey = kualiConfigurationService.getPropertyValueAsString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_2); body.append(MessageFormat.format(messageKey, new Object[] { taxContactDepartment }) + " \n\n"); } else { messageKey = kualiConfigurationService.getPropertyValueAsString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_3); body.append(MessageFormat.format(messageKey, new Object[] { taxContactDepartment, taxEmail }) + " \n\n"); } messageKey = kualiConfigurationService.getPropertyValueAsString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_4); body.append(MessageFormat.format(messageKey, new Object[] { null }) + " \n\n"); for (PaymentDetail pd : paymentGroup.getPaymentDetails()) { String payeeLabel = dataDictionaryService.getAttributeLabel(PaymentGroup.class, PdpPropertyConstants.PaymentGroup.PAYMENT_GROUP_PAYEE_NAME); String netPaymentAccountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_NET_AMOUNT); String sourceDocumentNumberLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_DISBURSEMENT_CUST_PAYMENT_DOC_NBR); String invoiceNumberLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_NUMBER); String purchaseOrderNumberLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_PURCHASE_ORDER_NUMBER); String paymentDetailIdLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_ID); body.append(payeeLabel + ": " + paymentGroup.getPayeeName() + " \n"); body.append(netPaymentAccountLabel + ": " + pd.getNetPaymentAmount() + " \n"); body.append(sourceDocumentNumberLabel + ": " + pd.getCustPaymentDocNbr() + " \n"); body.append(invoiceNumberLabel + ": " + pd.getInvoiceNbr() + " \n"); body.append(purchaseOrderNumberLabel + ": " + pd.getPurchaseOrderNbr() + " \n"); body.append(paymentDetailIdLabel + ": " + pd.getId() + "\n"); } body.append(MessageFormat.format(messageKey, new Object[] { null }) + " \n\n"); String batchIdLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.BATCH_ID); String chartMessageLabel = dataDictionaryService.getAttributeLabel(CustomerProfile.class, PdpPropertyConstants.CustomerProfile.CUSTOMER_PROFILE_CHART_CODE); String organizationLabel = dataDictionaryService.getAttributeLabel(CustomerProfile.class, PdpPropertyConstants.CustomerProfile.CUSTOMER_PROFILE_UNIT_CODE); String subUnitLabel = dataDictionaryService.getAttributeLabel(CustomerProfile.class, PdpPropertyConstants.CustomerProfile.CUSTOMER_PROFILE_SUB_UNIT_CODE); String creationDateLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.FILE_CREATION_TIME); String paymentCountLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.PAYMENT_COUNT); String paymentTotalLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.PAYMENT_TOTAL_AMOUNT); body.append(batchIdLabel + ": " + paymentGroup.getBatch().getId() + " \n"); body.append(chartMessageLabel + ": " + cp.getChartCode() + " \n"); body.append(organizationLabel + ": " + cp.getUnitCode() + " \n"); body.append(subUnitLabel + ": " + cp.getSubUnitCode() + " \n"); body.append(creationDateLabel + ": " + paymentGroup.getBatch().getCustomerFileCreateTimestamp() + " \n\n"); body.append(paymentCountLabel + ": " + paymentGroup.getBatch().getPaymentCount() + " \n\n"); body.append(paymentTotalLabel + ": " + paymentGroup.getBatch().getPaymentTotalAmount() + " \n\n"); message.setMessage(body.toString()); // KFSMI-6475 - if not a production instance, replace the recipients with the testers list alterMessageWhenNonProductionInstance(message, null); try { mailService.sendMessage(message); } catch (Exception e) { LOG.error("sendErrorEmail() Invalid email address. Message not sent", e); } } /** * Writes out payment file field labels and values to <code>StringBuffer</code> * * @param body <code>StringBuffer</code> */ protected void addPaymentFieldsToBody(StringBuilder body, Integer batchId, String chart, String unit, String subUnit, Date createDate, int paymentCount, KualiDecimal paymentTotal) { String batchIdLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.BATCH_ID); body.append(batchIdLabel + ": " + batchId + "\n"); String chartLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, KFSPropertyConstants.CHART); body.append(chartLabel + ": " + chart + "\n"); String orgLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.UNIT); body.append(orgLabel + ": " + unit + "\n"); String subUnitLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.SUB_UNIT); body.append(subUnitLabel + ": " + subUnit + "\n"); String createDateLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.CREATION_DATE); body.append(createDateLabel + ": " + createDate + "\n"); String paymentCountLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.PAYMENT_COUNT); body.append("\n" + paymentCountLabel + ": " + paymentCount + "\n"); String paymentTotalLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.PAYMENT_TOTAL_AMOUNT); body.append(paymentTotalLabel + ": " + paymentTotal + "\n"); } /** * Sends notification e-mail that an immediate extract Disbursement Voucher has been extracted * @param disbursementVoucher the disbursement voucher which was immediately extracted * @param fromAddress the address that the e-mail should be sent from * @param toAddresses the addresses that the e-mail should be sent to */ @Override public void sendPaymentSourceImmediateExtractEmail(PaymentSource paymentSource, String fromAddress, Collection<String> toAddresses) { MailMessage message = new MailMessage(); final String disbursementVoucherDocumentLabel = dataDictionaryService.getDocumentLabelByTypeName(DisbursementVoucherConstants.DOCUMENT_TYPE_CODE); final String subject = getMessage(KFSKeyConstants.MESSAGE_PAYMENT_SOURCE_IMMEDIATE_EXTRACT_EMAIL_SUBJECT, disbursementVoucherDocumentLabel, paymentSource.getCampusCode()); final String body = getMessage(KFSKeyConstants.MESSAGE_PAYMENT_SOURCE_IMMEDIATE_EXTRACT_EMAIL_BODY, disbursementVoucherDocumentLabel, paymentSource.getCampusCode(), paymentSource.getDocumentNumber()); message.setFromAddress(fromAddress); for (String toAddress : toAddresses) { message.addToAddress(toAddress); } message.setSubject(subject); message.setMessage(body); try { mailService.sendMessage(message); } catch (Exception e) { LOG.error("sendErrorEmail() Invalid email address. Message not sent", e); } } /** * Reads system parameter indicating whether to status emails should be sent * * @return true if email should be sent, false otherwise */ @Override public boolean isPaymentEmailEnabled() { boolean sendEmail = parameterService.getParameterValueAsBoolean(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.SEND_ACH_EMAIL_NOTIFICATION); if (!sendEmail) { LOG.debug("sendLoadEmail() sending payment file email is disabled"); } return sendEmail; } /** * 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) { return parameterService.getParameterValueAsString(LoadPaymentsStep.class, subjectParmaterName); } /** * Helper method to retrieve a message from resources and substitute place holder values * * @param messageKey key of message in resource file * @param messageParameters parameter for message * @return <code>String</code> Message with substituted values */ protected String getMessage(String messageKey, Object... messageParameters) { String message = kualiConfigurationService.getPropertyValueAsString(messageKey); return MessageFormat.format(message, messageParameters); } /** * Sets the customerProfileService attribute value. * * @param customerProfileService The customerProfileService to set. */ public void setCustomerProfileService(CustomerProfileService customerProfileService) { this.customerProfileService = customerProfileService; } /** * Sets the kualiConfigurationService attribute value. * * @param kualiConfigurationService The kualiConfigurationService to set. */ public void setConfigurationService(ConfigurationService kualiConfigurationService) { this.kualiConfigurationService = kualiConfigurationService; } /** * Sets the mailService attribute value. * * @param mailService The mailService to set. */ public void setMailService(MailService 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; } /** * Sets the achBankService attribute value. * * @param achBankService The achBankService to set. */ public void setAchBankService(AchBankService achBankService) { this.achBankService = achBankService; } }