001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.pdp.service.impl;
017    
018    import java.text.MessageFormat;
019    import java.util.Arrays;
020    import java.util.Collections;
021    import java.util.Date;
022    import java.util.HashSet;
023    import java.util.List;
024    import java.util.Map;
025    
026    import org.apache.commons.lang.StringUtils;
027    import org.kuali.kfs.pdp.PdpKeyConstants;
028    import org.kuali.kfs.pdp.PdpParameterConstants;
029    import org.kuali.kfs.pdp.PdpPropertyConstants;
030    import org.kuali.kfs.pdp.batch.ExtractAchPaymentsStep;
031    import org.kuali.kfs.pdp.batch.LoadPaymentsStep;
032    import org.kuali.kfs.pdp.businessobject.ACHBank;
033    import org.kuali.kfs.pdp.businessobject.Batch;
034    import org.kuali.kfs.pdp.businessobject.CustomerProfile;
035    import org.kuali.kfs.pdp.businessobject.PaymentDetail;
036    import org.kuali.kfs.pdp.businessobject.PaymentFileLoad;
037    import org.kuali.kfs.pdp.businessobject.PaymentGroup;
038    import org.kuali.kfs.pdp.businessobject.PaymentNoteText;
039    import org.kuali.kfs.pdp.service.AchBankService;
040    import org.kuali.kfs.pdp.service.CustomerProfileService;
041    import org.kuali.kfs.pdp.service.PdpEmailService;
042    import org.kuali.kfs.sys.KFSConstants;
043    import org.kuali.kfs.sys.KFSPropertyConstants;
044    import org.kuali.kfs.sys.service.impl.KfsParameterConstants;
045    import org.kuali.rice.kim.bo.Person;
046    import org.kuali.rice.kns.mail.InvalidAddressException;
047    import org.kuali.rice.kns.mail.MailMessage;
048    import org.kuali.rice.kns.service.DataDictionaryService;
049    import org.kuali.rice.kns.service.KualiConfigurationService;
050    import org.kuali.rice.kns.service.MailService;
051    import org.kuali.rice.kns.service.ParameterService;
052    import org.kuali.rice.kns.util.ErrorMessage;
053    import org.kuali.rice.kns.util.KualiDecimal;
054    import org.kuali.rice.kns.util.MessageMap;
055    import org.kuali.rice.kns.web.format.CurrencyFormatter;
056    import org.kuali.rice.kns.web.format.Formatter;
057    
058    /**
059     * @see org.kuali.kfs.pdp.service.PdpEmailService
060     */
061    public class PdpEmailServiceImpl implements PdpEmailService {
062        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PdpEmailServiceImpl.class);
063    
064        private CustomerProfileService customerProfileService;
065        private KualiConfigurationService kualiConfigurationService;
066        protected MailService mailService;
067        protected ParameterService parameterService;
068        private DataDictionaryService dataDictionaryService;
069        private AchBankService achBankService;
070    
071        /**
072         * @see org.kuali.kfs.pdp.service.PdpEmailService#sendErrorEmail(org.kuali.kfs.pdp.businessobject.PaymentFileLoad,
073         *      org.kuali.rice.kns.util.ErrorMap)
074         */
075        public void sendErrorEmail(PaymentFileLoad paymentFile, MessageMap errors) {
076            LOG.debug("sendErrorEmail() starting");
077    
078            // check email configuration
079            if (!isPaymentEmailEnabled()) {
080                return;
081            }
082    
083            MailMessage message = new MailMessage();
084    
085            message.setFromAddress(mailService.getBatchMailingList());
086            message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_FAILURE_EMAIL_SUBJECT_PARAMETER_NAME));
087    
088            StringBuffer body = new StringBuffer();
089            List<String> ccAddresses = parameterService.getParameterValues(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC);
090    
091            if (paymentFile == null) {
092                if (ccAddresses.isEmpty()) {
093                    LOG.error("sendErrorEmail() No HARD_EDIT_CC addresses.  No email sent");
094                    return;
095                }
096    
097                message.getToAddresses().addAll(ccAddresses);
098    
099                body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_BAD_FILE_PARSE) + "\n\n");
100            }
101            else {
102                CustomerProfile customer = customerProfileService.get(paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit());
103                if (customer == null) {
104                    LOG.error("sendErrorEmail() Invalid Customer.  Sending email to CC addresses");
105    
106                    if (ccAddresses.isEmpty()) {
107                        LOG.error("sendErrorEmail() No HARD_EDIT_CC addresses.  No email sent");
108                        return;
109                    }
110    
111                    message.getToAddresses().addAll(ccAddresses);
112    
113                    body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_INVALID_CUSTOMER) + "\n\n");
114                }
115                else {
116                    String toAddresses = StringUtils.deleteWhitespace(customer.getProcessingEmailAddr());
117                    List<String> toAddressList = Arrays.asList(toAddresses.split(","));
118    
119                    message.getToAddresses().addAll(toAddressList);
120                    message.getCcAddresses().addAll(ccAddresses);
121                    //TODO: for some reason the mail service does not work unless the bcc list has addresss. This is a temporary workaround
122                    message.getBccAddresses().addAll(ccAddresses);
123                }
124            }
125    
126            if (paymentFile != null) {
127                body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_NOT_LOADED) + "\n\n");
128                addPaymentFieldsToBody(body, null, paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount());
129            }
130    
131            body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_ERROR_MESSAGES) + "\n");
132            List<ErrorMessage> errorMessages = errors.getMessages(KFSConstants.GLOBAL_ERRORS);
133            for (ErrorMessage errorMessage : errorMessages) {
134                body.append(getMessage(errorMessage.getErrorKey(), (Object[]) errorMessage.getMessageParameters()) + "\n\n");
135            }
136    
137            message.setMessage(body.toString());
138    
139            // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
140            alterMessageWhenNonProductionInstance(message, null);
141            
142            try {
143                mailService.sendMessage(message);
144            } catch (InvalidAddressException e) {
145                LOG.error("sendErrorEmail() Invalid email address.  Message not sent", e);
146            }
147        }
148        
149        /**
150         * KFSMI-6475 - Alter the subject and switch all recipients
151         * 
152         * @param message
153         * @param environmentCode
154         */
155        @SuppressWarnings("rawtypes")
156        public void alterMessageWhenNonProductionInstance( MailMessage message, String environmentCode ) {
157            if ( !kualiConfigurationService.isProductionEnvironment() ) {
158                if ( environmentCode == null ) {
159                    environmentCode = kualiConfigurationService.getPropertyString(KFSConstants.ENVIRONMENT_KEY);
160                }
161                // Add the environment code to the subject
162                message.setSubject(environmentCode + ": " + message.getSubject());
163                // insert the original recipients into the beginning of the message 
164                StringBuffer recipients = new StringBuffer();
165                recipients.append("To : ").append(message.getToAddresses().toString()).append('\n');
166                recipients.append("Cc : ").append(message.getCcAddresses().toString()).append('\n');
167                recipients.append("Bcc: ").append(message.getBccAddresses().toString()).append('\n');
168                recipients.append('\n');
169                message.setMessage( recipients.toString() + message.getMessage() );
170                // Clear out the recipients
171                message.setToAddresses(new HashSet());
172                message.setCcAddresses(Collections.emptySet());
173                message.setBccAddresses(Collections.emptySet());
174                // Set all to the batch mailing list
175                message.addToAddress(mailService.getBatchMailingList());
176            }        
177        }
178    
179        /**
180         * @see org.kuali.kfs.pdp.service.PdpEmailService#sendLoadEmail(org.kuali.kfs.pdp.businessobject.PaymentFileLoad,
181         *      java.util.List)
182         */
183        public void sendLoadEmail(PaymentFileLoad paymentFile, List<String> warnings) {
184            LOG.debug("sendLoadEmail() starting");
185    
186            // check email configuration
187            if (!isPaymentEmailEnabled()) {
188                return;
189            }
190    
191            MailMessage message = new MailMessage();
192    
193            message.setFromAddress(mailService.getBatchMailingList());
194            message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_SUCCESS_EMAIL_SUBJECT_PARAMETER_NAME));
195    
196            List<String> ccAddresses = parameterService.getParameterValues(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC);
197            message.getCcAddresses().addAll(ccAddresses);
198            message.getBccAddresses().addAll(ccAddresses);
199    
200            CustomerProfile customer = customerProfileService.get(paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit());
201            String toAddresses = StringUtils.deleteWhitespace(customer.getProcessingEmailAddr());
202            List<String> toAddressList = Arrays.asList(toAddresses.split(","));
203    
204            message.getToAddresses().addAll(toAddressList);
205    
206            StringBuffer body = new StringBuffer();
207            body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_LOADED) + "\n\n");
208            addPaymentFieldsToBody(body, paymentFile.getBatchId().intValue(), paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount());
209    
210            body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_WARNING_MESSAGES) + "\n");
211            for (String warning : warnings) {
212                body.append(warning + "\n\n");
213            }
214    
215            message.setMessage(body.toString());
216    
217            // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
218            alterMessageWhenNonProductionInstance(message, null);
219            
220            try {
221                mailService.sendMessage(message);
222            }
223            catch (InvalidAddressException e) {
224                LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
225            }
226    
227            if (paymentFile.isFileThreshold()) {
228                sendThresholdEmail(true, paymentFile, customer);
229            }
230    
231            if (paymentFile.isDetailThreshold()) {
232                sendThresholdEmail(false, paymentFile, customer);
233            }
234        }
235    
236        /**
237         * Sends email for a payment that was over the customer file threshold or the detail threshold
238         * 
239         * @param fileThreshold indicates whether the file threshold (true) was violated or the detail threshold (false)
240         * @param paymentFile parsed payment file object
241         * @param customer payment customer
242         */
243        protected void sendThresholdEmail(boolean fileThreshold, PaymentFileLoad paymentFile, CustomerProfile customer) {
244            MailMessage message = new MailMessage();
245    
246            message.setFromAddress(mailService.getBatchMailingList());
247            message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_THRESHOLD_EMAIL_SUBJECT_PARAMETER_NAME));
248    
249            StringBuffer body = new StringBuffer();
250    
251            body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_LOADED) + "\n\n");
252            addPaymentFieldsToBody(body, paymentFile.getBatchId().intValue(), paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount());
253    
254            if (fileThreshold) {
255                String toAddresses = StringUtils.deleteWhitespace(customer.getFileThresholdEmailAddress());
256                List<String> toAddressList = Arrays.asList(toAddresses.split(","));
257    
258                message.getToAddresses().addAll(toAddressList);
259                body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_THRESHOLD, paymentFile.getPaymentTotalAmount(), customer.getFileThresholdAmount()));
260            }
261            else {
262                String toAddresses = StringUtils.deleteWhitespace(customer.getPaymentThresholdEmailAddress());
263                List<String> toAddressList = Arrays.asList(toAddresses.split(","));
264    
265                message.getToAddresses().addAll(toAddressList);
266    
267                body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_DETAIL_THRESHOLD, customer.getPaymentThresholdAmount()) + "\n\n");
268                for (PaymentDetail paymentDetail : paymentFile.getThresholdPaymentDetails()) {
269                    paymentDetail.refresh();
270                    body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_THRESHOLD, paymentDetail.getPaymentGroup().getPayeeName(), paymentDetail.getNetPaymentAmount()) + "\n");
271                }
272            }
273            
274            List<String> ccAddresses = parameterService.getParameterValues(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC);
275            message.getCcAddresses().addAll(ccAddresses);
276            message.getBccAddresses().addAll(ccAddresses);
277    
278            message.setMessage(body.toString());
279    
280            // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
281            alterMessageWhenNonProductionInstance(message, null);
282            
283            try {
284                mailService.sendMessage(message);
285            }
286            catch (InvalidAddressException e) {
287                LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
288            }
289        }
290    
291        /**
292         * @see org.kuali.kfs.pdp.service.PdpEmailService#sendTaxEmail(org.kuali.kfs.pdp.businessobject.PaymentFileLoad)
293         */
294        public void sendTaxEmail(PaymentFileLoad paymentFile) {
295            LOG.debug("sendTaxEmail() starting");
296    
297            MailMessage message = new MailMessage();
298    
299            message.setFromAddress(mailService.getBatchMailingList());
300            message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_TAX_EMAIL_SUBJECT_PARAMETER_NAME));
301    
302            StringBuffer body = new StringBuffer();
303    
304            String taxEmail = parameterService.getParameterValue(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_GROUP_EMAIL_ADDRESS);
305            if (StringUtils.isBlank(taxEmail)) {
306                LOG.error("No Tax E-mail Application Setting found to send notification e-mail");
307                return;
308            }
309            else {
310                message.addToAddress(taxEmail);
311            }
312            List<String> ccAddresses = parameterService.getParameterValues(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC);
313            message.getCcAddresses().addAll(ccAddresses);
314            message.getBccAddresses().addAll(ccAddresses);
315    
316            body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_TAX_LOADED) + "\n\n");
317            addPaymentFieldsToBody(body, paymentFile.getBatchId().intValue(), paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount());
318    
319            body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_GO_TO_PDP) + "\n");
320    
321            message.setMessage(body.toString());
322    
323            // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
324            alterMessageWhenNonProductionInstance(message, null);
325            
326            try {
327                mailService.sendMessage(message);
328            }
329            catch (InvalidAddressException e) {
330                LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
331            }
332        }
333    
334        /**
335         * @see org.kuali.kfs.pdp.service.PdpEmailService#sendLoadEmail(org.kuali.kfs.pdp.businessobject.Batch)
336         */
337        public void sendLoadEmail(Batch batch) {
338            LOG.debug("sendLoadEmail() starting");
339    
340            // check email configuration
341            if (!isPaymentEmailEnabled()) {
342                return;
343            }
344    
345            MailMessage message = new MailMessage();
346    
347            message.setFromAddress(mailService.getBatchMailingList());
348            message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_SUCCESS_EMAIL_SUBJECT_PARAMETER_NAME));
349    
350            StringBuffer body = new StringBuffer();
351    
352            List<String> ccAddresses = parameterService.getParameterValues(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC);
353            message.getCcAddresses().addAll(ccAddresses);
354            message.getBccAddresses().addAll(ccAddresses);
355    
356            CustomerProfile customer = batch.getCustomerProfile();
357            String toAddresses = StringUtils.deleteWhitespace(customer.getProcessingEmailAddr());
358            List<String> toAddressList = Arrays.asList(toAddresses.split(","));
359    
360            message.getToAddresses().addAll(toAddressList);
361    
362            body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_LOADED) + "\n\n");
363            addPaymentFieldsToBody(body, batch.getId().intValue(), customer.getChartCode(), customer.getUnitCode(), customer.getSubUnitCode(), batch.getCustomerFileCreateTimestamp(), batch.getPaymentCount().intValue(), batch.getPaymentTotalAmount());
364    
365            message.setMessage(body.toString());
366    
367            // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
368            alterMessageWhenNonProductionInstance(message, null);
369            
370            try {
371                mailService.sendMessage(message);
372            }
373            catch (InvalidAddressException e) {
374                LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
375            }
376        }
377    
378        /**
379         * @see org.kuali.kfs.pdp.service.PdpEmailService#sendExceedsMaxNotesWarningEmail(java.util.List, java.util.List, int, int)
380         */
381        public void sendExceedsMaxNotesWarningEmail(List<String> creditMemos, List<String> paymentRequests, int lineTotal, int maxNoteLines) {
382            LOG.debug("sendExceedsMaxNotesWarningEmail() starting");
383    
384            // check email configuration
385            if (!isPaymentEmailEnabled()) {
386                return;
387            }
388    
389            MailMessage message = new MailMessage();
390            message.setFromAddress(mailService.getBatchMailingList());
391    
392            StringBuffer body = new StringBuffer();
393    
394            String environmentCode = kualiConfigurationService.getPropertyString(KFSConstants.ENVIRONMENT_KEY);
395            message.setSubject(getMessage(PdpKeyConstants.MESSAGE_PURAP_EXTRACT_MAX_NOTES_SUBJECT));
396    
397            // Get recipient email address
398            String toAddresses = parameterService.getParameterValue(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.PDP_ERROR_EXCEEDS_NOTE_LIMIT_EMAIL);
399            List<String> toAddressList = Arrays.asList(toAddresses.split(","));
400            message.getToAddresses().addAll(toAddressList);
401    
402            List<String> ccAddresses = parameterService.getParameterValues(LoadPaymentsStep.class, PdpParameterConstants.SOFT_EDIT_CC);
403            message.getCcAddresses().addAll(ccAddresses);
404    
405            
406            message.getBccAddresses().addAll(ccAddresses);
407            
408            body.append(getMessage(PdpKeyConstants.MESSAGE_PURAP_EXTRACT_MAX_NOTES_MESSAGE, StringUtils.join(creditMemos, ","), StringUtils.join(paymentRequests, ","), lineTotal, maxNoteLines));
409            message.setMessage(body.toString());
410    
411            // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
412            alterMessageWhenNonProductionInstance(message, null);
413            
414            try {
415                mailService.sendMessage(message);
416            }
417            catch (InvalidAddressException e) {
418                LOG.error("sendExceedsMaxNotesWarningEmail() Invalid email address. Message not sent", e);
419            }
420        }
421    
422        /**
423         * @see org.kuali.kfs.pdp.service.PdpEmailService#sendAchSummaryEmail(java.util.Map, java.util.Map, java.util.Date)
424         */
425        public void sendAchSummaryEmail(Map<String, Integer> unitCounts, Map<String, KualiDecimal> unitTotals, Date disbursementDate) {
426            LOG.debug("sendAchSummaryEmail() starting");
427    
428            MailMessage message = new MailMessage();
429    
430            List<String> toAddressList = parameterService.getParameterValues(ExtractAchPaymentsStep.class, PdpParameterConstants.ACH_SUMMARY_TO_EMAIL_ADDRESS_PARMAETER_NAME);
431            message.getToAddresses().addAll(toAddressList);
432            message.getCcAddresses().addAll(toAddressList);
433            message.getBccAddresses().addAll(toAddressList);
434    
435            message.setFromAddress(mailService.getBatchMailingList());
436    
437            String subject = parameterService.getParameterValue(ExtractAchPaymentsStep.class, PdpParameterConstants.ACH_SUMMARY_EMAIL_SUBJECT_PARAMETER_NAME);
438            message.setSubject(subject);
439    
440            StringBuffer body = new StringBuffer();
441            body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_SUMMARY_EMAIL_DISB_DATE, disbursementDate) + "\n");
442    
443            Integer totalCount = 0;
444            KualiDecimal totalAmount = KualiDecimal.ZERO;
445            for (String unit : unitCounts.keySet()) {
446                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");
447    
448                totalCount = totalCount + unitCounts.get(unit);
449                totalAmount = totalAmount.add(unitTotals.get(unit));
450            }
451    
452            body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_SUMMARY_EMAIL_EXTRACT_TOTALS, StringUtils.leftPad(totalCount.toString(), 10), StringUtils.leftPad(totalAmount.toString(), 20)) + "\n");
453            body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_SUMMARY_EMAIL_COMPLETE));
454    
455            message.setMessage(body.toString());
456    
457            // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
458            alterMessageWhenNonProductionInstance(message, null);
459            
460            try {
461                mailService.sendMessage(message);
462            }
463            catch (InvalidAddressException e) {
464                LOG.error("sendAchSummaryEmail() Invalid email address. Message not sent", e);
465            }
466        }
467    
468        /**
469         * @see org.kuali.kfs.pdp.service.PdpEmailService#sendAchAdviceEmail(org.kuali.kfs.pdp.businessobject.PaymentGroup,
470         *      org.kuali.kfs.pdp.businessobject.CustomerProfile, org.kuali.kfs.pdp.businessobject.PaymentDetail)
471         */
472        public void sendAchAdviceEmail(PaymentGroup paymentGroup, PaymentDetail paymentDetail, CustomerProfile customer) {
473            LOG.debug("sendAchAdviceEmail() starting");
474    
475            MailMessage message = new MailMessage();
476    
477            message.addToAddress(paymentGroup.getAdviceEmailAddress());
478            message.addCcAddress(paymentGroup.getAdviceEmailAddress());
479            message.addBccAddress(paymentGroup.getAdviceEmailAddress());
480            message.setFromAddress(customer.getAdviceReturnEmailAddr());
481            message.setSubject(customer.getAdviceSubjectLine());
482    
483            LOG.debug("sending email to " + paymentGroup.getAdviceEmailAddress() + " for disb # " + paymentGroup.getDisbursementNbr());
484    
485            StringBuffer body = new StringBuffer();
486            body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_EMAIL_TOFROM, paymentGroup.getPayeeName(), customer.getAchPaymentDescription()));
487    
488            // formatter for payment amounts
489            Formatter formatter = new CurrencyFormatter();
490    
491            // get bank name to which the payment is being transferred
492            String bankName = "";
493    
494            ACHBank achBank = achBankService.getByPrimaryId(paymentGroup.getAchBankRoutingNbr());
495            if (achBank == null) {
496                LOG.error("Bank cound not be found for routing number " + paymentGroup.getAchBankRoutingNbr());
497            }
498            else {
499                bankName = achBank.getBankName();
500            }
501    
502            body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_EMAIL_BANKAMOUNT, bankName, formatter.formatForPresentation(paymentDetail.getNetPaymentAmount())));
503    
504            // print detail amounts
505            int labelPad = 25;
506    
507            String newPaymentAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_NET_AMOUNT);
508            body.append(StringUtils.rightPad(newPaymentAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getNetPaymentAmount()) + "\n");
509    
510            if (paymentDetail.getOrigInvoiceAmount().isNonZero()) {
511                String origInvoiceAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_ORIGINAL_INVOICE_AMOUNT);
512                body.append(StringUtils.rightPad(origInvoiceAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getOrigInvoiceAmount()) + "\n");
513            }
514    
515            if (paymentDetail.getInvTotDiscountAmount().isNonZero()) {
516                String invTotDiscountAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_DISCOUNT_AMOUNT);
517                body.append(StringUtils.rightPad(invTotDiscountAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotDiscountAmount()) + "\n");
518            }
519    
520            if (paymentDetail.getInvTotShipAmount().isNonZero()) {
521                String invTotShippingAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_SHIPPING_AMOUNT);
522                body.append(StringUtils.rightPad(invTotShippingAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotShipAmount()) + "\n");
523            }
524    
525            if (paymentDetail.getInvTotOtherDebitAmount().isNonZero()) {
526                String invTotOtherDebitAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_OTHER_DEBIT_AMOUNT);
527                body.append(StringUtils.rightPad(invTotOtherDebitAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotOtherDebitAmount()) + "\n");
528            }
529    
530            if (paymentDetail.getInvTotOtherCreditAmount().isNonZero()) {
531                String invTotOtherCreditAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_OTHER_CREDIT_AMOUNT);
532                body.append(StringUtils.rightPad(invTotOtherCreditAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotOtherCreditAmount()) + "\n");
533            }
534    
535            body.append("\n" + customer.getAdviceHeaderText() + "\n");
536    
537            if (StringUtils.isNotBlank(paymentDetail.getPurchaseOrderNbr())) {
538                String purchaseOrderNbrLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_PURCHASE_ORDER_NUMBER);
539                body.append(StringUtils.rightPad(purchaseOrderNbrLabel, labelPad) + paymentDetail.getPurchaseOrderNbr() + "\n");
540            }
541    
542            if (StringUtils.isNotBlank(paymentDetail.getInvoiceNbr())) {
543                String invoiceNbrLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_NUMBER);
544                body.append(StringUtils.rightPad(invoiceNbrLabel, labelPad) + paymentDetail.getInvoiceNbr() + "\n");
545            }
546    
547            if (StringUtils.isNotBlank(paymentDetail.getCustPaymentDocNbr())) {
548                String custPaymentDocNbrLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_CUSTOMER_DOC_NUMBER);
549                body.append(StringUtils.rightPad(custPaymentDocNbrLabel, labelPad) + paymentDetail.getCustPaymentDocNbr() + "\n");
550            }
551    
552            if (StringUtils.isNotBlank(paymentGroup.getCustomerInstitutionNumber())) {
553                String customerInstituitionNbrLabel = dataDictionaryService.getAttributeLabel(PaymentGroup.class, PdpPropertyConstants.CUSTOMER_INSTITUTION_NUMBER);
554                body.append(StringUtils.rightPad(customerInstituitionNbrLabel, labelPad) + paymentGroup.getCustomerInstitutionNumber() + "\n");
555            }
556    
557            body.append("\n");
558    
559            // print payment notes
560            for (PaymentNoteText paymentNoteText : paymentDetail.getNotes()) {
561                body.append(paymentNoteText.getCustomerNoteText() + "\n");
562            }
563    
564            if (paymentDetail.getNotes().isEmpty()) {
565                body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_EMAIL_NONOTES));
566            }
567    
568            message.setMessage(body.toString());
569    
570            // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
571            alterMessageWhenNonProductionInstance(message, null);
572            
573            try {
574                mailService.sendMessage(message);
575            }
576            catch (InvalidAddressException e) {
577                LOG.error("sendAchAdviceEmail() Invalid email address. Sending message to " + customer.getAdviceReturnEmailAddr(), e);
578    
579                // send notification to advice return address with payment details
580                message.addToAddress(customer.getAdviceReturnEmailAddr());
581                
582                message.setFromAddress(mailService.getBatchMailingList());
583                message.setSubject(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_INVALID_EMAIL_ADDRESS));
584    
585                LOG.debug("bouncing email to " + customer.getAdviceReturnEmailAddr() + " for disb # " + paymentGroup.getDisbursementNbr());
586                // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
587                alterMessageWhenNonProductionInstance(message, null);
588                
589                try {
590                    mailService.sendMessage(message);
591                }
592                catch (InvalidAddressException e1) {
593                    LOG.error("Could not send email to advice return email address on customer profile: " + customer.getAdviceReturnEmailAddr(), e1);
594                    throw new RuntimeException("Could not send email to advice return email address on customer profile: " + customer.getAdviceReturnEmailAddr());
595                }
596            }
597        }
598        
599        /**
600         * 
601         * @see org.kuali.kfs.pdp.service.PdpEmailService#sendCancelEmail(org.kuali.kfs.pdp.businessobject.PaymentGroup, java.lang.String, org.kuali.rice.kim.bo.Person)
602         */
603        public void sendCancelEmail(PaymentGroup paymentGroup, String note, Person user) {
604            LOG.debug("sendCancelEmail() starting");
605    
606            MailMessage message = new MailMessage();
607            
608            String environmentCode = kualiConfigurationService.getPropertyString(KFSConstants.ENVIRONMENT_KEY);
609            
610            message.setSubject("PDP --- Cancelled Payment by Tax");
611    
612            CustomerProfile cp = paymentGroup.getBatch().getCustomerProfile();
613            String toAddresses = cp.getAdviceReturnEmailAddr();
614            String toAddressList[] = toAddresses.split(",");
615    
616            if (toAddressList.length > 0) {
617                for (int i = 0; i < toAddressList.length; i++) {
618                    if (toAddressList[i] != null) {
619                        message.addToAddress(toAddressList[i].trim());
620                        message.addBccAddress(toAddressList[i].trim());
621                    }
622                }
623            }
624            // message.addToAddress(cp.getAdviceReturnEmailAddr());
625    
626            String ccAddresses = parameterService.getParameterValue(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_CANCEL_EMAIL_LIST);
627            String ccAddressList[] = ccAddresses.split(",");
628    
629            if (ccAddressList.length > 0) {
630                for (int i = 0; i < ccAddressList.length; i++) {
631                    if (ccAddressList[i] != null) {
632                        message.addCcAddress(ccAddressList[i].trim());
633                    }
634                }
635            }
636    
637            String fromAddressList[] = { mailService.getBatchMailingList() };
638    
639            if (fromAddressList.length > 0) {
640                for (int i = 0; i < fromAddressList.length; i++) {
641                    if (fromAddressList[i] != null) {
642                        message.setFromAddress(fromAddressList[i].trim());
643                    }
644                }
645            }
646    
647            StringBuffer body = new StringBuffer();
648    
649            String messageKey = kualiConfigurationService.getPropertyString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_1);
650            body.append(MessageFormat.format(messageKey, new Object[] { null }) + " \n\n");
651            
652            body.append(note + "\n\n");
653            String taxEmail = parameterService.getParameterValue(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_GROUP_EMAIL_ADDRESS);
654            String taxContactDepartment = parameterService.getParameterValue(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_CANCEL_CONTACT);
655            if (StringUtils.isBlank(taxEmail)) {
656                messageKey = kualiConfigurationService.getPropertyString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_2);
657                body.append(MessageFormat.format(messageKey, new Object[] { taxContactDepartment }) + " \n\n");
658            }
659            else {
660                messageKey = kualiConfigurationService.getPropertyString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_3);
661                body.append(MessageFormat.format(messageKey, new Object[] { taxContactDepartment, taxEmail }) + " \n\n");
662            }
663    
664            messageKey = kualiConfigurationService.getPropertyString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_4);
665                body.append(MessageFormat.format(messageKey, new Object[] { null }) + " \n\n");
666            
667            for (PaymentDetail pd : paymentGroup.getPaymentDetails()) {
668    
669                String payeeLabel = dataDictionaryService.getAttributeLabel(PaymentGroup.class, PdpPropertyConstants.PaymentGroup.PAYMENT_GROUP_PAYEE_NAME);
670                String netPaymentAccountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_NET_AMOUNT);
671                String sourceDocumentNumberLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_DISBURSEMENT_CUST_PAYMENT_DOC_NBR);
672                String invoiceNumberLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_NUMBER);
673                String purchaseOrderNumberLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_PURCHASE_ORDER_NUMBER);
674                String paymentDetailIdLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_ID);
675                
676                body.append(payeeLabel + ": " + paymentGroup.getPayeeName() + " \n");
677                body.append(netPaymentAccountLabel + ": " + pd.getNetPaymentAmount() + " \n");
678                body.append(sourceDocumentNumberLabel + ": " + pd.getCustPaymentDocNbr() + " \n");
679                body.append(invoiceNumberLabel + ": " + pd.getInvoiceNbr() + " \n");
680                body.append(purchaseOrderNumberLabel + ": " + pd.getPurchaseOrderNbr() + " \n");
681                body.append(paymentDetailIdLabel + ": " + pd.getId() + "\n");
682                
683            }
684    
685            body.append(MessageFormat.format(messageKey, new Object[] { null }) + " \n\n");
686            
687            String batchIdLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.BATCH_ID);
688            String chartMessageLabel = dataDictionaryService.getAttributeLabel(CustomerProfile.class, PdpPropertyConstants.CustomerProfile.CUSTOMER_PROFILE_CHART_CODE);
689            String organizationLabel = dataDictionaryService.getAttributeLabel(CustomerProfile.class, PdpPropertyConstants.CustomerProfile.CUSTOMER_PROFILE_UNIT_CODE);
690            String subUnitLabel = dataDictionaryService.getAttributeLabel(CustomerProfile.class, PdpPropertyConstants.CustomerProfile.CUSTOMER_PROFILE_SUB_UNIT_CODE);
691            String creationDateLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.FILE_CREATION_TIME);
692            String paymentCountLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.PAYMENT_COUNT);
693            String paymentTotalLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.PAYMENT_TOTAL_AMOUNT);
694            
695            body.append(batchIdLabel + ": " + paymentGroup.getBatch().getId() + " \n");
696            body.append(chartMessageLabel + ": " + cp.getChartCode() + " \n");
697            body.append(organizationLabel + ": " + cp.getUnitCode() + " \n");
698            body.append(subUnitLabel + ": " + cp.getSubUnitCode() + " \n");
699            body.append(creationDateLabel + ": " + paymentGroup.getBatch().getCustomerFileCreateTimestamp() + " \n\n");
700            body.append(paymentCountLabel + ": " + paymentGroup.getBatch().getPaymentCount() + " \n\n");
701            body.append(paymentTotalLabel + ": " + paymentGroup.getBatch().getPaymentTotalAmount() + " \n\n");
702    
703            message.setMessage(body.toString());
704    
705            // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
706            alterMessageWhenNonProductionInstance(message, null);
707            
708            try {
709                mailService.sendMessage(message);
710            }
711            catch (InvalidAddressException e) {
712                LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
713            }
714        }
715        
716        /**
717         * Writes out payment file field labels and values to <code>StringBuffer</code>
718         * 
719         * @param body <code>StringBuffer</code>
720         */
721        protected void addPaymentFieldsToBody(StringBuffer body, Integer batchId, String chart, String unit, String subUnit, Date createDate, int paymentCount, KualiDecimal paymentTotal) {
722            String batchIdLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.BATCH_ID);
723            body.append(batchIdLabel + ": " + batchId + "\n");
724    
725            String chartLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, KFSPropertyConstants.CHART);
726            body.append(chartLabel + ": " + chart + "\n");
727    
728            String orgLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.UNIT);
729            body.append(orgLabel + ": " + unit + "\n");
730    
731            String subUnitLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.SUB_UNIT);
732            body.append(subUnitLabel + ": " + subUnit + "\n");
733    
734            String createDateLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.CREATION_DATE);
735            body.append(createDateLabel + ": " + createDate + "\n");
736    
737            String paymentCountLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.PAYMENT_COUNT);
738            body.append("\n" + paymentCountLabel + ": " + paymentCount + "\n");
739    
740            String paymentTotalLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.PAYMENT_TOTAL_AMOUNT);
741            body.append(paymentTotalLabel + ": " + paymentTotal + "\n");
742        }
743    
744        /**
745         * Reads system parameter indicating whether to status emails should be sent
746         * 
747         * @return true if email should be sent, false otherwise
748         */
749        public boolean isPaymentEmailEnabled() {
750            boolean noEmail = parameterService.getIndicatorParameter(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.NO_PAYMENT_FILE_EMAIL);
751            if (noEmail) {
752                LOG.debug("sendLoadEmail() sending payment file email is disabled");
753                return false;
754            }
755    
756            return true;
757        }
758    
759        /**
760         * Retrieves the email subject text from system parameter then checks environment code and prepends to message if not
761         * production.
762         * 
763         * @param subjectParmaterName name of parameter giving the subject text
764         * @return subject text
765         */
766        protected String getEmailSubject(String subjectParmaterName) {
767            String subject = parameterService.getParameterValue(LoadPaymentsStep.class, subjectParmaterName);
768    
769            return subject;
770        }
771    
772        /**
773         * Helper method to retrieve a message from resources and substitute place holder values
774         * 
775         * @param messageKey key of message in resource file
776         * @param messageParameters parameter for message
777         * @return <code>String</code> Message with substituted values
778         */
779        protected String getMessage(String messageKey, Object... messageParameters) {
780            String message = kualiConfigurationService.getPropertyString(messageKey);
781            return MessageFormat.format(message, messageParameters);
782        }
783    
784        /**
785         * Sets the customerProfileService attribute value.
786         * 
787         * @param customerProfileService The customerProfileService to set.
788         */
789        public void setCustomerProfileService(CustomerProfileService customerProfileService) {
790            this.customerProfileService = customerProfileService;
791        }
792    
793        /**
794         * Sets the kualiConfigurationService attribute value.
795         * 
796         * @param kualiConfigurationService The kualiConfigurationService to set.
797         */
798        public void setKualiConfigurationService(KualiConfigurationService kualiConfigurationService) {
799            this.kualiConfigurationService = kualiConfigurationService;
800        }
801    
802        /**
803         * Sets the mailService attribute value.
804         * 
805         * @param mailService The mailService to set.
806         */
807        public void setMailService(MailService mailService) {
808            this.mailService = mailService;
809        }
810    
811        /**
812         * Sets the parameterService attribute value.
813         * 
814         * @param parameterService The parameterService to set.
815         */
816        public void setParameterService(ParameterService parameterService) {
817            this.parameterService = parameterService;
818        }
819    
820        /**
821         * Sets the dataDictionaryService attribute value.
822         * 
823         * @param dataDictionaryService The dataDictionaryService to set.
824         */
825        public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
826            this.dataDictionaryService = dataDictionaryService;
827        }
828    
829        /**
830         * Sets the achBankService attribute value.
831         * 
832         * @param achBankService The achBankService to set.
833         */
834        public void setAchBankService(AchBankService achBankService) {
835            this.achBankService = achBankService;
836        }
837    
838    }