View Javadoc
1   /*
2    * Copyright 2008 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.pdp.service.impl;
17  
18  import java.text.MessageFormat;
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.Date;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Map;
27  
28  import org.apache.commons.lang.StringUtils;
29  import org.kuali.ole.fp.document.DisbursementVoucherConstants;
30  import org.kuali.ole.fp.document.DisbursementVoucherDocument;
31  import org.kuali.ole.pdp.PdpKeyConstants;
32  import org.kuali.ole.pdp.PdpParameterConstants;
33  import org.kuali.ole.pdp.PdpPropertyConstants;
34  import org.kuali.ole.pdp.batch.ExtractAchPaymentsStep;
35  import org.kuali.ole.pdp.batch.LoadPaymentsStep;
36  import org.kuali.ole.pdp.batch.SendAchAdviceNotificationsStep;
37  import org.kuali.ole.pdp.businessobject.ACHBank;
38  import org.kuali.ole.pdp.businessobject.Batch;
39  import org.kuali.ole.pdp.businessobject.CustomerProfile;
40  import org.kuali.ole.pdp.businessobject.PaymentDetail;
41  import org.kuali.ole.pdp.businessobject.PaymentFileLoad;
42  import org.kuali.ole.pdp.businessobject.PaymentGroup;
43  import org.kuali.ole.pdp.businessobject.PaymentNoteText;
44  import org.kuali.ole.pdp.service.AchBankService;
45  import org.kuali.ole.pdp.service.CustomerProfileService;
46  import org.kuali.ole.pdp.service.PdpEmailService;
47  import org.kuali.ole.sys.OLEConstants;
48  import org.kuali.ole.sys.OLEKeyConstants;
49  import org.kuali.ole.sys.OLEPropertyConstants;
50  import org.kuali.ole.sys.service.impl.OleParameterConstants;
51  import org.kuali.rice.core.api.config.property.ConfigContext;
52  import org.kuali.rice.core.api.config.property.ConfigurationService;
53  import org.kuali.rice.core.api.mail.MailMessage;
54  import org.kuali.rice.core.api.util.type.KualiDecimal;
55  import org.kuali.rice.core.web.format.CurrencyFormatter;
56  import org.kuali.rice.core.web.format.Formatter;
57  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
58  import org.kuali.rice.kim.api.identity.Person;
59  import org.kuali.rice.kns.service.DataDictionaryService;
60  import org.kuali.rice.krad.service.MailService;
61  import org.kuali.rice.krad.util.ErrorMessage;
62  import org.kuali.rice.krad.util.MessageMap;
63  
64  /**
65   * @see org.kuali.ole.pdp.service.PdpEmailService
66   */
67  public class PdpEmailServiceImpl implements PdpEmailService {
68      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PdpEmailServiceImpl.class);
69  
70      protected CustomerProfileService customerProfileService;
71      protected ConfigurationService kualiConfigurationService;
72      protected MailService mailService;
73      protected ParameterService parameterService;
74      protected DataDictionaryService dataDictionaryService;
75      protected AchBankService achBankService;
76  
77      /**
78       * @see org.kuali.ole.pdp.service.PdpEmailService#sendErrorEmail(org.kuali.ole.pdp.businessobject.PaymentFileLoad,
79       *      org.kuali.rice.kns.util.ErrorMap)
80       */
81      @Override
82      public void sendErrorEmail(PaymentFileLoad paymentFile, MessageMap errors) {
83          LOG.debug("sendErrorEmail() starting");
84  
85          // check email configuration
86          if (!isPaymentEmailEnabled()) {
87              return;
88          }
89  
90          MailMessage message = new MailMessage();
91  
92          String returnAddress = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_BATCH.class, OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
93          if(StringUtils.isEmpty(returnAddress)) {
94              returnAddress = mailService.getBatchMailingList();
95          }
96          message.setFromAddress(returnAddress);
97          message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_FAILURE_EMAIL_SUBJECT_PARAMETER_NAME));
98  
99          StringBuilder body = new StringBuilder();
100         List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC) );
101 
102         if (paymentFile == null) {
103             if (ccAddresses.isEmpty()) {
104                 LOG.error("sendErrorEmail() No HARD_EDIT_CC addresses.  No email sent");
105                 return;
106             }
107 
108             message.getToAddresses().addAll(ccAddresses);
109 
110             body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_BAD_FILE_PARSE) + "\n\n");
111         }
112         else {
113             CustomerProfile customer = customerProfileService.get(paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit());
114             if (customer == null) {
115                 LOG.error("sendErrorEmail() Invalid Customer.  Sending email to CC addresses");
116 
117                 if (ccAddresses.isEmpty()) {
118                     LOG.error("sendErrorEmail() No HARD_EDIT_CC addresses.  No email sent");
119                     return;
120                 }
121 
122                 message.getToAddresses().addAll(ccAddresses);
123 
124                 body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_INVALID_CUSTOMER) + "\n\n");
125             }
126             else {
127                 String toAddresses = StringUtils.deleteWhitespace(customer.getProcessingEmailAddr());
128                 List<String> toAddressList = Arrays.asList(toAddresses.split(","));
129 
130                 message.getToAddresses().addAll(toAddressList);
131                 message.getCcAddresses().addAll(ccAddresses);
132                 //TODO: for some reason the mail service does not work unless the bcc list has addresss. This is a temporary workaround
133                 message.getBccAddresses().addAll(ccAddresses);
134             }
135         }
136 
137         if (paymentFile != null) {
138             body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_NOT_LOADED) + "\n\n");
139             addPaymentFieldsToBody(body, null, paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount());
140         }
141 
142         body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_ERROR_MESSAGES) + "\n");
143         List<ErrorMessage> errorMessages = errors.getMessages(OLEConstants.GLOBAL_ERRORS);
144         for (ErrorMessage errorMessage : errorMessages) {
145             body.append(getMessage(errorMessage.getErrorKey(), (Object[]) errorMessage.getMessageParameters()) + "\n\n");
146         }
147 
148         message.setMessage(body.toString());
149 
150         // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
151         alterMessageWhenNonProductionInstance(message, null);
152         
153         try {
154             mailService.sendMessage(message);
155         } catch (Exception e) {
156             LOG.error("sendErrorEmail() Invalid email address.  Message not sent", e);
157         }
158     }
159     
160     /**
161      * KFSMI-6475 - Alter the subject and switch all recipients
162      * 
163      * @param message
164      * @param environmentCode
165      */
166     @SuppressWarnings("rawtypes")
167     public void alterMessageWhenNonProductionInstance( MailMessage message, String environmentCode ) {
168         if (! ConfigContext.getCurrentContextConfig().isProductionEnvironment()) {
169             // insert the original recipients into the beginning of the message 
170             StringBuilder recipients = new StringBuilder();
171             recipients.append("Intended To : ").append(message.getToAddresses().toString()).append('\n');
172             recipients.append("Intended Cc : ").append(message.getCcAddresses().toString()).append('\n');
173             recipients.append("Intended Bcc: ").append(message.getBccAddresses().toString()).append('\n');
174             recipients.append('\n');
175             message.setMessage( recipients.toString() + message.getMessage() );
176             // Clear out the recipients
177             message.setToAddresses(new HashSet());
178             message.setCcAddresses(Collections.emptySet());
179             message.setBccAddresses(Collections.emptySet());
180             // Set all to the batch mailing list
181             message.addToAddress(mailService.getBatchMailingList());
182         }        
183     }
184 
185     /**
186      * @see org.kuali.ole.pdp.service.PdpEmailService#sendLoadEmail(org.kuali.ole.pdp.businessobject.PaymentFileLoad,
187      *      java.util.List)
188      */
189     @Override
190     public void sendLoadEmail(PaymentFileLoad paymentFile, List<String> warnings) {
191         LOG.debug("sendLoadEmail() starting");
192 
193         // check email configuration
194         if (!isPaymentEmailEnabled()) {
195             return;
196         }
197 
198         MailMessage message = new MailMessage();
199 
200         String returnAddress = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_BATCH.class, OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
201         if(StringUtils.isEmpty(returnAddress)) {
202             returnAddress = mailService.getBatchMailingList();
203         }
204         message.setFromAddress(returnAddress);
205         message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_SUCCESS_EMAIL_SUBJECT_PARAMETER_NAME));
206 
207         List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC) );
208         message.getCcAddresses().addAll(ccAddresses);
209         message.getBccAddresses().addAll(ccAddresses);
210 
211         CustomerProfile customer = customerProfileService.get(paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit());
212         String toAddresses = StringUtils.deleteWhitespace(customer.getProcessingEmailAddr());
213         List<String> toAddressList = Arrays.asList(toAddresses.split(","));
214 
215         message.getToAddresses().addAll(toAddressList);
216 
217         StringBuilder body = new StringBuilder();
218         body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_LOADED) + "\n\n");
219         addPaymentFieldsToBody(body, paymentFile.getBatchId().intValue(), paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount());
220 
221         body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_WARNING_MESSAGES) + "\n");
222         for (String warning : warnings) {
223             body.append(warning + "\n\n");
224         }
225 
226         message.setMessage(body.toString());
227 
228         // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
229         alterMessageWhenNonProductionInstance(message, null);
230         
231         try {
232             mailService.sendMessage(message);
233         }
234         catch (Exception e) {
235             LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
236         }
237 
238         if (paymentFile.isFileThreshold()) {
239             sendThresholdEmail(true, paymentFile, customer);
240         }
241 
242         if (paymentFile.isDetailThreshold()) {
243             sendThresholdEmail(false, paymentFile, customer);
244         }
245     }
246 
247     /**
248      * Sends email for a payment that was over the customer file threshold or the detail threshold
249      * 
250      * @param fileThreshold indicates whether the file threshold (true) was violated or the detail threshold (false)
251      * @param paymentFile parsed payment file object
252      * @param customer payment customer
253      */
254     protected void sendThresholdEmail(boolean fileThreshold, PaymentFileLoad paymentFile, CustomerProfile customer) {
255         MailMessage message = new MailMessage();
256 
257         String returnAddress = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_BATCH.class, OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
258         if(StringUtils.isEmpty(returnAddress)) {
259             returnAddress = mailService.getBatchMailingList();
260         }
261         message.setFromAddress(returnAddress);
262         message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_THRESHOLD_EMAIL_SUBJECT_PARAMETER_NAME));
263 
264         StringBuilder body = new StringBuilder();
265 
266         body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_LOADED) + "\n\n");
267         addPaymentFieldsToBody(body, paymentFile.getBatchId().intValue(), paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount());
268 
269         if (fileThreshold) {
270             String toAddresses = StringUtils.deleteWhitespace(customer.getFileThresholdEmailAddress());
271             List<String> toAddressList = Arrays.asList(toAddresses.split(","));
272 
273             message.getToAddresses().addAll(toAddressList);
274             body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_THRESHOLD, paymentFile.getPaymentTotalAmount(), customer.getFileThresholdAmount()));
275         }
276         else {
277             String toAddresses = StringUtils.deleteWhitespace(customer.getPaymentThresholdEmailAddress());
278             List<String> toAddressList = Arrays.asList(toAddresses.split(","));
279 
280             message.getToAddresses().addAll(toAddressList);
281 
282             body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_DETAIL_THRESHOLD, customer.getPaymentThresholdAmount()) + "\n\n");
283             for (PaymentDetail paymentDetail : paymentFile.getThresholdPaymentDetails()) {
284                 paymentDetail.refresh();
285                 body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_THRESHOLD, paymentDetail.getPaymentGroup().getPayeeName(), paymentDetail.getNetPaymentAmount()) + "\n");
286             }
287         }
288         
289         List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC) );
290         message.getCcAddresses().addAll(ccAddresses);
291         message.getBccAddresses().addAll(ccAddresses);
292 
293         message.setMessage(body.toString());
294 
295         // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
296         alterMessageWhenNonProductionInstance(message, null);
297         
298         try {
299             mailService.sendMessage(message);
300         }
301         catch (Exception e) {
302             LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
303         }
304     }
305 
306     /**
307      * @see org.kuali.ole.pdp.service.PdpEmailService#sendTaxEmail(org.kuali.ole.pdp.businessobject.PaymentFileLoad)
308      */
309     @Override
310     public void sendTaxEmail(PaymentFileLoad paymentFile) {
311         LOG.debug("sendTaxEmail() starting");
312 
313         MailMessage message = new MailMessage();
314 
315         String returnAddress = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_BATCH.class, OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
316         if(StringUtils.isEmpty(returnAddress)) {
317             returnAddress = mailService.getBatchMailingList();
318         }
319         message.setFromAddress(returnAddress);
320         message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_TAX_EMAIL_SUBJECT_PARAMETER_NAME));
321 
322         StringBuilder body = new StringBuilder();
323 
324         String taxEmail = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_GROUP_EMAIL_ADDRESS);
325         if (StringUtils.isBlank(taxEmail)) {
326             LOG.error("No Tax E-mail Application Setting found to send notification e-mail");
327             return;
328         }
329         else {
330             message.addToAddress(taxEmail);
331         }
332         List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC) );
333         message.getCcAddresses().addAll(ccAddresses);
334         message.getBccAddresses().addAll(ccAddresses);
335 
336         body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_TAX_LOADED) + "\n\n");
337         addPaymentFieldsToBody(body, paymentFile.getBatchId().intValue(), paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit(), paymentFile.getCreationDate(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount());
338 
339         body.append("\n" + getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_GO_TO_PDP) + "\n");
340 
341         message.setMessage(body.toString());
342 
343         // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
344         alterMessageWhenNonProductionInstance(message, null);
345         
346         try {
347             mailService.sendMessage(message);
348         }
349         catch (Exception e) {
350             LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
351         }
352     }
353 
354     /**
355      * @see org.kuali.ole.pdp.service.PdpEmailService#sendLoadEmail(org.kuali.ole.pdp.businessobject.Batch)
356      */
357     @Override
358     public void sendLoadEmail(Batch batch) {
359         LOG.debug("sendLoadEmail() starting");
360 
361         // check email configuration
362         if (!isPaymentEmailEnabled()) {
363             return;
364         }
365 
366         MailMessage message = new MailMessage();
367 
368         String returnAddress = parameterService.getParameterValueAsString( OleParameterConstants.PRE_DISBURSEMENT_BATCH.class, OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
369         if(StringUtils.isEmpty(returnAddress)) {
370             returnAddress = mailService.getBatchMailingList();
371         }
372         message.setFromAddress(returnAddress);
373         message.setSubject(getEmailSubject(PdpParameterConstants.PAYMENT_LOAD_SUCCESS_EMAIL_SUBJECT_PARAMETER_NAME));
374 
375         StringBuilder body = new StringBuilder();
376 
377         List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.HARD_EDIT_CC) );
378         message.getCcAddresses().addAll(ccAddresses);
379         message.getBccAddresses().addAll(ccAddresses);
380 
381         CustomerProfile customer = batch.getCustomerProfile();
382         String toAddresses = StringUtils.deleteWhitespace(customer.getProcessingEmailAddr());
383         List<String> toAddressList = Arrays.asList(toAddresses.split(","));
384 
385         message.getToAddresses().addAll(toAddressList);
386 
387         body.append(getMessage(PdpKeyConstants.MESSAGE_PAYMENT_EMAIL_FILE_LOADED) + "\n\n");
388         addPaymentFieldsToBody(body, batch.getId().intValue(), customer.getChartCode(), customer.getUnitCode(), customer.getSubUnitCode(), batch.getCustomerFileCreateTimestamp(), batch.getPaymentCount().intValue(), batch.getPaymentTotalAmount());
389 
390         message.setMessage(body.toString());
391 
392         // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
393         alterMessageWhenNonProductionInstance(message, null);
394         
395         try {
396             mailService.sendMessage(message);
397         }
398         catch (Exception e) {
399             LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
400         }
401     }
402 
403     /**
404      * @see org.kuali.ole.pdp.service.PdpEmailService#sendExceedsMaxNotesWarningEmail(java.util.List, java.util.List, int, int)
405      */
406     @Override
407     public void sendExceedsMaxNotesWarningEmail(List<String> creditMemos, List<String> paymentRequests, int lineTotal, int maxNoteLines) {
408         LOG.debug("sendExceedsMaxNotesWarningEmail() starting");
409 
410         // check email configuration
411         if (!isPaymentEmailEnabled()) {
412             return;
413         }
414 
415         MailMessage message = new MailMessage();
416         String returnAddress = parameterService.getParameterValueAsString(OLEConstants.ParameterNamespaces.PDP, "Batch", OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
417         if(StringUtils.isEmpty(returnAddress)) {
418             returnAddress = mailService.getBatchMailingList();
419         }
420         message.setFromAddress(returnAddress);
421 
422         StringBuilder body = new StringBuilder();
423 
424         String productionEnvironmentCode = kualiConfigurationService.getPropertyValueAsString(OLEConstants.PROD_ENVIRONMENT_CODE_KEY);
425         String environmentCode = kualiConfigurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
426         if (StringUtils.equals(productionEnvironmentCode, environmentCode)) {
427         message.setSubject(getMessage(PdpKeyConstants.MESSAGE_PURAP_EXTRACT_MAX_NOTES_SUBJECT));
428         }
429         else {
430             message.setSubject(getMessage(PdpKeyConstants.MESSAGE_PURAP_EXTRACT_MAX_NOTES_SUBJECT));
431         }
432 
433         // Get recipient email address
434         String toAddresses = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.PDP_ERROR_EXCEEDS_NOTE_LIMIT_EMAIL);
435         List<String> toAddressList = Arrays.asList(toAddresses.split(","));
436         message.getToAddresses().addAll(toAddressList);
437 
438         List<String> ccAddresses = new ArrayList<String>( parameterService.getParameterValuesAsString(LoadPaymentsStep.class, PdpParameterConstants.SOFT_EDIT_CC) );
439         message.getCcAddresses().addAll(ccAddresses);
440 
441         
442         message.getBccAddresses().addAll(ccAddresses);
443         
444         body.append(getMessage(PdpKeyConstants.MESSAGE_PURAP_EXTRACT_MAX_NOTES_MESSAGE, StringUtils.join(creditMemos, ","), StringUtils.join(paymentRequests, ","), lineTotal, maxNoteLines));
445         message.setMessage(body.toString());
446 
447         // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
448         alterMessageWhenNonProductionInstance(message, null);
449         
450         try {
451             mailService.sendMessage(message);
452         }
453         catch (Exception e) {
454             LOG.error("sendExceedsMaxNotesWarningEmail() Invalid email address. Message not sent", e);
455         }
456     }
457 
458     /**
459      * @see org.kuali.ole.pdp.service.PdpEmailService#sendAchSummaryEmail(java.util.Map, java.util.Map, java.util.Date)
460      */
461     @Override
462     public void sendAchSummaryEmail(Map<String, Integer> unitCounts, Map<String, KualiDecimal> unitTotals, Date disbursementDate) {
463         LOG.debug("sendAchSummaryEmail() starting");
464 
465         MailMessage message = new MailMessage();
466 
467         List<String> toAddressList = new ArrayList<String>( parameterService.getParameterValuesAsString(ExtractAchPaymentsStep.class, PdpParameterConstants.ACH_SUMMARY_TO_EMAIL_ADDRESS_PARMAETER_NAME) );
468         message.getToAddresses().addAll(toAddressList);
469         message.getCcAddresses().addAll(toAddressList);
470         message.getBccAddresses().addAll(toAddressList);
471 
472         String returnAddress = parameterService.getParameterValueAsString(OLEConstants.ParameterNamespaces.PDP, "Batch", OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
473         if(StringUtils.isEmpty(returnAddress)) {
474             returnAddress = mailService.getBatchMailingList();
475         }
476         message.setFromAddress(returnAddress);
477 
478         String subject = parameterService.getParameterValueAsString(ExtractAchPaymentsStep.class, PdpParameterConstants.ACH_SUMMARY_EMAIL_SUBJECT_PARAMETER_NAME);
479         message.setSubject(subject);
480 
481         StringBuilder body = new StringBuilder();
482         body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_SUMMARY_EMAIL_DISB_DATE, disbursementDate) + "\n");
483 
484         Integer totalCount = 0;
485         KualiDecimal totalAmount = KualiDecimal.ZERO;
486         for (String unit : unitCounts.keySet()) {
487             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");
488 
489             totalCount = totalCount + unitCounts.get(unit);
490             totalAmount = totalAmount.add(unitTotals.get(unit));
491         }
492 
493         body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_SUMMARY_EMAIL_EXTRACT_TOTALS, StringUtils.leftPad(totalCount.toString(), 10), StringUtils.leftPad(totalAmount.toString(), 20)) + "\n");
494         body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_SUMMARY_EMAIL_COMPLETE));
495 
496         message.setMessage(body.toString());
497 
498         // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
499         alterMessageWhenNonProductionInstance(message, null);
500         
501         try {
502             mailService.sendMessage(message);
503         }
504         catch (Exception e) {
505             LOG.error("sendAchSummaryEmail() Invalid email address. Message not sent", e);
506         }
507     }
508 
509     /**
510      * @see org.kuali.ole.pdp.service.PdpEmailService#sendAchAdviceEmail(org.kuali.ole.pdp.businessobject.PaymentGroup,
511      *      org.kuali.ole.pdp.businessobject.CustomerProfile, org.kuali.ole.pdp.businessobject.PaymentDetail)
512      */
513     @Override
514     public void sendAchAdviceEmail(PaymentGroup paymentGroup, PaymentDetail paymentDetail, CustomerProfile customer) {
515         LOG.debug("sendAchAdviceEmail() starting");
516 
517         MailMessage message = new MailMessage();
518         //String productionEnvironmentCode = kualiConfigurationService.getPropertyValueAsString(OLEConstants.PROD_ENVIRONMENT_CODE_KEY);
519         //String environmentCode = kualiConfigurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
520         String fromAddresses = customer.getAdviceReturnEmailAddr();
521         String toAddresses = paymentGroup.getAdviceEmailAddress();
522         Collection<String> ccAddresses = parameterService.getParameterValuesAsString(SendAchAdviceNotificationsStep.class, PdpParameterConstants.ACH_SUMMARY_CC_EMAIL_ADDRESSES_PARMAETER_NAME);
523         String batchAddresses = mailService.getBatchMailingList();
524         String subject = customer.getAdviceSubjectLine();
525  
526         message.addToAddress(toAddresses);
527         message.getCcAddresses().addAll(ccAddresses);
528         //message.addBccAddress(ccAddresses);
529         message.setFromAddress(fromAddresses);
530         message.setSubject(subject);
531 
532         /* NOTE: The following code is unnecessary and counter-productive, because alterMessageWhenNonProductionInstance called below handles non-prd env 
533          * email to/cc addresses and subject properly, while Rice MailService handles adding app and env code in front of the subject line.
534          * There's no need to add another layer to replace these addresses and subject. Replacing the real address with batchAddress will only result
535          * in wiping out the original real addresses, which would have been added to the message body by MailService, for testing purpose.         
536         if (StringUtils.equals(productionEnvironmentCode, environmentCode)) {
537             message.addToAddress(toAddresses);
538             message.addCcAddress(ccAddresses);
539             message.addBccAddress(ccAddresses);
540             message.setFromAddress(fromAddresses);
541             message.setSubject(subject);
542         }
543         else {
544             message.addToAddress(batchAddresses);
545             message.addCcAddress(batchAddresses);
546             message.addBccAddress(batchAddresses);
547             message.setFromAddress(fromAddresses);
548             message.setSubject(environmentCode + ": " + subject + ":" + toAddresses);            
549         }
550         */
551         
552         if (LOG.isDebugEnabled()) {
553             LOG.debug("sending email to " + toAddresses + " for disb # " + paymentGroup.getDisbursementNbr());
554         }
555 
556         StringBuilder body = new StringBuilder();
557         body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_EMAIL_TOFROM, paymentGroup.getPayeeName(), customer.getAchPaymentDescription()));
558 
559         // formatter for payment amounts
560         Formatter formatter = new CurrencyFormatter();
561 
562         // get bank name to which the payment is being transferred
563         String bankName = "";
564 
565         ACHBank achBank = achBankService.getByPrimaryId(paymentGroup.getAchBankRoutingNbr());
566         if (achBank == null) {
567             LOG.error("Bank cound not be found for routing number " + paymentGroup.getAchBankRoutingNbr());
568         }
569         else {
570             bankName = achBank.getBankName();
571         }
572 
573         body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_EMAIL_BANKAMOUNT, bankName, formatter.formatForPresentation(paymentDetail.getNetPaymentAmount())));
574 
575         // print detail amounts
576         int labelPad = 25;
577 
578         String newPaymentAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_NET_AMOUNT);
579         body.append(StringUtils.rightPad(newPaymentAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getNetPaymentAmount()) + "\n");
580 
581         if (paymentDetail.getOrigInvoiceAmount().isNonZero()) {
582             String origInvoiceAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_ORIGINAL_INVOICE_AMOUNT);
583             body.append(StringUtils.rightPad(origInvoiceAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getOrigInvoiceAmount()) + "\n");
584         }
585 
586         if (paymentDetail.getInvTotDiscountAmount().isNonZero()) {
587             String invTotDiscountAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_DISCOUNT_AMOUNT);
588             body.append(StringUtils.rightPad(invTotDiscountAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotDiscountAmount()) + "\n");
589         }
590 
591         if (paymentDetail.getInvTotShipAmount().isNonZero()) {
592             String invTotShippingAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_SHIPPING_AMOUNT);
593             body.append(StringUtils.rightPad(invTotShippingAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotShipAmount()) + "\n");
594         }
595 
596         if (paymentDetail.getInvTotOtherDebitAmount().isNonZero()) {
597             String invTotOtherDebitAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_OTHER_DEBIT_AMOUNT);
598             body.append(StringUtils.rightPad(invTotOtherDebitAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotOtherDebitAmount()) + "\n");
599         }
600 
601         if (paymentDetail.getInvTotOtherCreditAmount().isNonZero()) {
602             String invTotOtherCreditAmountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_TOTAL_OTHER_CREDIT_AMOUNT);
603             body.append(StringUtils.rightPad(invTotOtherCreditAmountLabel, labelPad) + formatter.formatForPresentation(paymentDetail.getInvTotOtherCreditAmount()) + "\n");
604         }
605 
606         body.append("\n" + customer.getAdviceHeaderText() + "\n");
607 
608         if (StringUtils.isNotBlank(paymentDetail.getPurchaseOrderNbr())) {
609             String purchaseOrderNbrLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_PURCHASE_ORDER_NUMBER);
610             body.append(StringUtils.rightPad(purchaseOrderNbrLabel, labelPad) + paymentDetail.getPurchaseOrderNbr() + "\n");
611         }
612 
613         if (StringUtils.isNotBlank(paymentDetail.getInvoiceNbr())) {
614             String invoiceNbrLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_NUMBER);
615             body.append(StringUtils.rightPad(invoiceNbrLabel, labelPad) + paymentDetail.getInvoiceNbr() + "\n");
616         }
617 
618         if (StringUtils.isNotBlank(paymentDetail.getCustPaymentDocNbr())) {
619             String custPaymentDocNbrLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_CUSTOMER_DOC_NUMBER);
620             body.append(StringUtils.rightPad(custPaymentDocNbrLabel, labelPad) + paymentDetail.getCustPaymentDocNbr() + "\n");
621         }
622 
623         if (StringUtils.isNotBlank(paymentDetail.getCustomerInstitutionNumber())) {
624             String customerInstituitionNbrLabel = dataDictionaryService.getAttributeLabel(PaymentGroup.class, PdpPropertyConstants.CUSTOMER_INSTITUTION_NUMBER);
625             body.append(StringUtils.rightPad(customerInstituitionNbrLabel, labelPad) + paymentDetail.getCustomerInstitutionNumber() + "\n");
626         }
627 
628         body.append("\n");
629 
630         // print payment notes
631         for (PaymentNoteText paymentNoteText : paymentDetail.getNotes()) {
632             body.append(paymentNoteText.getCustomerNoteText() + "\n");
633         }
634 
635         if (paymentDetail.getNotes().isEmpty()) {
636             body.append(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_EMAIL_NONOTES));
637         }
638 
639         message.setMessage(body.toString());
640 
641         // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
642         alterMessageWhenNonProductionInstance(message, null);
643         
644         try {
645             mailService.sendMessage(message);
646         }
647         catch (Exception e) {
648             LOG.error("sendAchAdviceEmail() Invalid email address. Sending message to " + customer.getAdviceReturnEmailAddr(), e);
649 
650             // send notification to advice return address with payment details
651             message.addToAddress(customer.getAdviceReturnEmailAddr());
652             
653             String returnAddress = parameterService.getParameterValueAsString(OLEConstants.ParameterNamespaces.PDP, "Batch", OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
654             if(StringUtils.isEmpty(returnAddress)) {
655                 returnAddress = mailService.getBatchMailingList();
656             }
657             message.setFromAddress(returnAddress);
658             message.setSubject(getMessage(PdpKeyConstants.MESSAGE_PDP_ACH_ADVICE_INVALID_EMAIL_ADDRESS));
659 
660             LOG.warn("bouncing email to " + customer.getAdviceReturnEmailAddr() + " for disb # " + paymentGroup.getDisbursementNbr());
661             // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
662             alterMessageWhenNonProductionInstance(message, null);
663             
664             try {
665                 mailService.sendMessage(message);
666             }
667             catch (Exception e1) {
668                 LOG.error("Could not send email to advice return email address on customer profile: " + customer.getAdviceReturnEmailAddr(), e1);
669                 throw new RuntimeException("Could not send email to advice return email address on customer profile: " + customer.getAdviceReturnEmailAddr());
670             }
671         }
672     }
673     
674     /**
675      * 
676      * @see org.kuali.ole.pdp.service.PdpEmailService#sendCancelEmail(org.kuali.ole.pdp.businessobject.PaymentGroup, java.lang.String, org.kuali.rice.kim.api.identity.Person)
677      */
678     @Override
679     public void sendCancelEmail(PaymentGroup paymentGroup, String note, Person user) {
680         LOG.debug("sendCancelEmail() starting");
681 
682         MailMessage message = new MailMessage();
683         
684         message.setSubject("PDP --- Cancelled Payment by Tax");
685 
686         CustomerProfile cp = paymentGroup.getBatch().getCustomerProfile();
687         String toAddresses = cp.getAdviceReturnEmailAddr();
688         String toAddressList[] = toAddresses.split(",");
689 
690         if (toAddressList.length > 0) {
691             for (int i = 0; i < toAddressList.length; i++) {
692                 if (toAddressList[i] != null) {
693                     message.addToAddress(toAddressList[i].trim());
694                     message.addBccAddress(toAddressList[i].trim());
695                 }
696             }
697         }
698         // message.addToAddress(cp.getAdviceReturnEmailAddr());
699 
700         String ccAddresses = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_CANCEL_EMAIL_LIST);
701         String ccAddressList[] = ccAddresses.split(",");
702 
703         if (ccAddressList.length > 0) {
704             for (int i = 0; i < ccAddressList.length; i++) {
705                 if (ccAddressList[i] != null) {
706                     message.addCcAddress(ccAddressList[i].trim());
707                 }
708             }
709         }
710 
711         String fromAddressList[] = { mailService.getBatchMailingList() };
712 
713         if (fromAddressList.length > 0) {
714             for (int i = 0; i < fromAddressList.length; i++) {
715                 if (fromAddressList[i] != null) {
716                     message.setFromAddress(fromAddressList[i].trim());
717                 }
718             }
719         }
720 
721         StringBuilder body = new StringBuilder();
722 
723         String messageKey = kualiConfigurationService.getPropertyValueAsString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_1);
724         body.append(MessageFormat.format(messageKey, new Object[] { null }) + " \n\n");
725         
726         body.append(note + "\n\n");
727         String taxEmail = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_GROUP_EMAIL_ADDRESS);
728         String taxContactDepartment = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.TAX_CANCEL_CONTACT);
729         if (StringUtils.isBlank(taxEmail)) {
730             messageKey = kualiConfigurationService.getPropertyValueAsString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_2);
731             body.append(MessageFormat.format(messageKey, new Object[] { taxContactDepartment }) + " \n\n");
732         }
733         else {
734             messageKey = kualiConfigurationService.getPropertyValueAsString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_3);
735             body.append(MessageFormat.format(messageKey, new Object[] { taxContactDepartment, taxEmail }) + " \n\n");
736         }
737 
738         messageKey = kualiConfigurationService.getPropertyValueAsString(PdpKeyConstants.MESSAGE_PDP_PAYMENT_MAINTENANCE_EMAIL_LINE_4);
739             body.append(MessageFormat.format(messageKey, new Object[] { null }) + " \n\n");
740         
741         for (PaymentDetail pd : paymentGroup.getPaymentDetails()) {
742 
743             String payeeLabel = dataDictionaryService.getAttributeLabel(PaymentGroup.class, PdpPropertyConstants.PaymentGroup.PAYMENT_GROUP_PAYEE_NAME);
744             String netPaymentAccountLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_NET_AMOUNT);
745             String sourceDocumentNumberLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_DISBURSEMENT_CUST_PAYMENT_DOC_NBR);
746             String invoiceNumberLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_INVOICE_NUMBER);
747             String purchaseOrderNumberLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_PURCHASE_ORDER_NUMBER);
748             String paymentDetailIdLabel = dataDictionaryService.getAttributeLabel(PaymentDetail.class, PdpPropertyConstants.PaymentDetail.PAYMENT_ID);
749             
750             body.append(payeeLabel + ": " + paymentGroup.getPayeeName() + " \n");
751             body.append(netPaymentAccountLabel + ": " + pd.getNetPaymentAmount() + " \n");
752             body.append(sourceDocumentNumberLabel + ": " + pd.getCustPaymentDocNbr() + " \n");
753             body.append(invoiceNumberLabel + ": " + pd.getInvoiceNbr() + " \n");
754             body.append(purchaseOrderNumberLabel + ": " + pd.getPurchaseOrderNbr() + " \n");
755             body.append(paymentDetailIdLabel + ": " + pd.getId() + "\n");
756             
757         }
758 
759         body.append(MessageFormat.format(messageKey, new Object[] { null }) + " \n\n");
760         
761         String batchIdLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.BATCH_ID);
762         String chartMessageLabel = dataDictionaryService.getAttributeLabel(CustomerProfile.class, PdpPropertyConstants.CustomerProfile.CUSTOMER_PROFILE_CHART_CODE);
763         String organizationLabel = dataDictionaryService.getAttributeLabel(CustomerProfile.class, PdpPropertyConstants.CustomerProfile.CUSTOMER_PROFILE_UNIT_CODE);
764         String subUnitLabel = dataDictionaryService.getAttributeLabel(CustomerProfile.class, PdpPropertyConstants.CustomerProfile.CUSTOMER_PROFILE_SUB_UNIT_CODE);
765         String creationDateLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.FILE_CREATION_TIME);
766         String paymentCountLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.PAYMENT_COUNT);
767         String paymentTotalLabel = dataDictionaryService.getAttributeLabel(Batch.class, PdpPropertyConstants.BatchConstants.PAYMENT_TOTAL_AMOUNT);
768         
769         body.append(batchIdLabel + ": " + paymentGroup.getBatch().getId() + " \n");
770         body.append(chartMessageLabel + ": " + cp.getChartCode() + " \n");
771         body.append(organizationLabel + ": " + cp.getUnitCode() + " \n");
772         body.append(subUnitLabel + ": " + cp.getSubUnitCode() + " \n");
773         body.append(creationDateLabel + ": " + paymentGroup.getBatch().getCustomerFileCreateTimestamp() + " \n\n");
774         body.append(paymentCountLabel + ": " + paymentGroup.getBatch().getPaymentCount() + " \n\n");
775         body.append(paymentTotalLabel + ": " + paymentGroup.getBatch().getPaymentTotalAmount() + " \n\n");
776 
777         message.setMessage(body.toString());
778 
779         // KFSMI-6475 - if not a production instance, replace the recipients with the testers list
780         alterMessageWhenNonProductionInstance(message, null);
781         
782         try {
783             mailService.sendMessage(message);
784         }
785         catch (Exception e) {
786             LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
787         }
788     }
789     
790     /**
791      * Writes out payment file field labels and values to <code>StringBuffer</code>
792      * 
793      * @param body <code>StringBuffer</code>
794      */
795     protected void addPaymentFieldsToBody(StringBuilder body, Integer batchId, String chart, String unit, String subUnit, Date createDate, int paymentCount, KualiDecimal paymentTotal) {
796         String batchIdLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.BATCH_ID);
797         body.append(batchIdLabel + ": " + batchId + "\n");
798 
799         String chartLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, OLEPropertyConstants.CHART);
800         body.append(chartLabel + ": " + chart + "\n");
801 
802         String orgLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.UNIT);
803         body.append(orgLabel + ": " + unit + "\n");
804 
805         String subUnitLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.SUB_UNIT);
806         body.append(subUnitLabel + ": " + subUnit + "\n");
807 
808         String createDateLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.CREATION_DATE);
809         body.append(createDateLabel + ": " + createDate + "\n");
810 
811         String paymentCountLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.PAYMENT_COUNT);
812         body.append("\n" + paymentCountLabel + ": " + paymentCount + "\n");
813 
814         String paymentTotalLabel = dataDictionaryService.getAttributeLabel(PaymentFileLoad.class, PdpPropertyConstants.PAYMENT_TOTAL_AMOUNT);
815         body.append(paymentTotalLabel + ": " + paymentTotal + "\n");
816     }
817 
818     /**
819      * Sends notification e-mail that an immediate extract Disbursement Voucher has been extracted
820      * @param disbursementVoucher the disbursement voucher which was immediately extracted
821      * @param user the current extracting user
822      */
823     @Override
824     public void sendDisbursementVoucherImmediateExtractEmail(DisbursementVoucherDocument disbursementVoucher, Person user) {
825         MailMessage message = new MailMessage();
826 
827         final String fromAddress = parameterService.getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.IMMEDIATE_EXTRACT_FROM_ADDRESS_PARM_NM);
828         final Collection<String> toAddresses = parameterService.getParameterValuesAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.IMMEDIATE_EXTRACT_TO_ADDRESSES_PARM_NM);
829         final String disbursementVoucherDocumentLabel = dataDictionaryService.getDocumentLabelByTypeName(DisbursementVoucherConstants.DOCUMENT_TYPE_CODE);
830         final String subject = getMessage(OLEKeyConstants.MESSAGE_DV_IMMEDIATE_EXTRACT_EMAIL_SUBJECT, disbursementVoucherDocumentLabel, disbursementVoucher.getCampusCode());
831         final String body = getMessage(OLEKeyConstants.MESSAGE_DV_IMMEDIATE_EXTRACT_EMAIL_BODY, disbursementVoucherDocumentLabel, disbursementVoucher.getCampusCode(), disbursementVoucher.getDocumentNumber());
832 
833         message.setFromAddress(fromAddress);
834         for (String toAddress : toAddresses) {
835             message.addToAddress(toAddress);
836         }
837         message.setSubject(subject);
838         message.setMessage(body);
839         try {
840             mailService.sendMessage(message);
841         }
842         catch (Exception e) {
843             LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
844         }
845     }
846 
847     /**
848      * Reads system parameter indicating whether to status emails should be sent
849      * 
850      * @return true if email should be sent, false otherwise
851      */
852     @Override
853     public boolean isPaymentEmailEnabled() {
854         boolean sendEmail = parameterService.getParameterValueAsBoolean(OleParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.SEND_ACH_EMAIL_NOTIFICATION);
855         if (!sendEmail) {
856             LOG.debug("sendLoadEmail() sending payment file email is disabled");
857         }
858         return sendEmail;
859     }
860 
861     /**
862      * Retrieves the email subject text from system parameter then checks environment code and prepends to message if not
863      * production.
864      * 
865      * @param subjectParmaterName name of parameter giving the subject text
866      * @return subject text
867      */
868     protected String getEmailSubject(String subjectParmaterName) {
869         String subject = parameterService.getParameterValueAsString(LoadPaymentsStep.class, subjectParmaterName);
870 
871         return subject;
872     }
873 
874     /**
875      * Helper method to retrieve a message from resources and substitute place holder values
876      * 
877      * @param messageKey key of message in resource file
878      * @param messageParameters parameter for message
879      * @return <code>String</code> Message with substituted values
880      */
881     protected String getMessage(String messageKey, Object... messageParameters) {
882         String message = kualiConfigurationService.getPropertyValueAsString(messageKey);
883         return MessageFormat.format(message, messageParameters);
884     }
885 
886     /**
887      * Sets the customerProfileService attribute value.
888      * 
889      * @param customerProfileService The customerProfileService to set.
890      */
891     public void setCustomerProfileService(CustomerProfileService customerProfileService) {
892         this.customerProfileService = customerProfileService;
893     }
894 
895     /**
896      * Sets the kualiConfigurationService attribute value.
897      * 
898      * @param kualiConfigurationService The kualiConfigurationService to set.
899      */
900     public void setConfigurationService(ConfigurationService kualiConfigurationService) {
901         this.kualiConfigurationService = kualiConfigurationService;
902     }
903 
904     /**
905      * Sets the mailService attribute value.
906      * 
907      * @param mailService The mailService to set.
908      */
909     public void setMailService(MailService mailService) {
910         this.mailService = mailService;
911     }
912 
913     /**
914      * Sets the parameterService attribute value.
915      * 
916      * @param parameterService The parameterService to set.
917      */
918     public void setParameterService(ParameterService parameterService) {
919         this.parameterService = parameterService;
920     }
921 
922     /**
923      * Sets the dataDictionaryService attribute value.
924      * 
925      * @param dataDictionaryService The dataDictionaryService to set.
926      */
927     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
928         this.dataDictionaryService = dataDictionaryService;
929     }
930 
931     /**
932      * Sets the achBankService attribute value.
933      * 
934      * @param achBankService The achBankService to set.
935      */
936     public void setAchBankService(AchBankService achBankService) {
937         this.achBankService = achBankService;
938     }
939 
940 }