1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.gl.batch.service.impl;
17
18 import java.text.MessageFormat;
19 import java.util.ArrayList;
20 import java.util.Formattable;
21 import java.util.Formatter;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.apache.commons.lang.StringUtils;
30 import org.kuali.ole.gl.batch.CollectorBatch;
31 import org.kuali.ole.gl.batch.CollectorStep;
32 import org.kuali.ole.gl.batch.service.CollectorReportService;
33 import org.kuali.ole.gl.businessobject.DemergerReportData;
34 import org.kuali.ole.gl.businessobject.OriginEntryFull;
35 import org.kuali.ole.gl.businessobject.Transaction;
36 import org.kuali.ole.gl.report.CollectorReportData;
37 import org.kuali.ole.gl.report.LedgerSummaryReport;
38 import org.kuali.ole.gl.report.PreScrubberReport;
39 import org.kuali.ole.gl.report.Summary;
40 import org.kuali.ole.gl.service.PreScrubberService;
41 import org.kuali.ole.gl.service.ScrubberReportData;
42 import org.kuali.ole.sys.OLEConstants;
43 import org.kuali.ole.sys.OLEConstants.SystemGroupParameterNames;
44 import org.kuali.ole.sys.OLEKeyConstants;
45 import org.kuali.ole.sys.Message;
46 import org.kuali.ole.sys.service.ReportWriterService;
47 import org.kuali.rice.core.api.config.property.ConfigurationService;
48 import org.kuali.rice.core.api.datetime.DateTimeService;
49 import org.kuali.rice.core.api.mail.MailMessage;
50 import org.kuali.rice.core.api.util.type.KualiDecimal;
51 import org.kuali.rice.core.web.format.CurrencyFormatter;
52 import org.kuali.rice.coreservice.framework.parameter.ParameterService;
53 import org.kuali.rice.krad.service.MailService;
54 import org.kuali.rice.krad.util.ErrorMessage;
55 import org.kuali.rice.krad.util.MessageMap;
56
57
58
59
60 public class CollectorReportServiceImpl implements CollectorReportService {
61 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CollectorReportServiceImpl.class);
62
63 protected DateTimeService dateTimeService;
64 protected ParameterService parameterService;
65 protected ConfigurationService configurationService;
66 protected MailService mailService;
67 protected PreScrubberService preScrubberService;
68 protected ReportWriterService collectorReportWriterService;
69
70
71
72
73
74
75
76 @Override
77 public void sendEmails(CollectorReportData collectorReportData) {
78
79 Iterator<CollectorBatch> batchIter = collectorReportData.getAddedBatches();
80 while (batchIter.hasNext()) {
81 CollectorBatch batch = batchIter.next();
82 sendValidationEmail(batch, collectorReportData);
83 sendDemergerEmail(batch, collectorReportData);
84 }
85
86 sendEmailSendFailureNotice(collectorReportData);
87 }
88
89
90
91
92
93
94
95 @Override
96 public void generateCollectorRunReports(CollectorReportData collectorReportData) {
97 appendCollectorHeaderInformation(collectorReportData);
98 appendPreScrubberReport(collectorReportData);
99 appendScrubberReport(collectorReportData);
100 appendDemergerReport(collectorReportData);
101 appendDeletedOriginEntryAndDetailReport(collectorReportData);
102 appendDetailChangedAccountReport(collectorReportData);
103 appendLedgerReport(collectorReportData);
104 }
105
106
107
108
109
110
111 protected void appendCollectorHeaderInformation(CollectorReportData collectorReportData) {
112 Iterator<CollectorBatch> batchIter = collectorReportData.getAddedBatches();
113 OriginEntryTotals aggregateOriginEntryTotals = new OriginEntryTotals();
114 int aggregateTotalRecordsCountFromTrailer = 0;
115 int aggregateNumInputDetails = 0;
116 int aggregateNumSavedDetails = 0;
117
118 if (!collectorReportData.getAllUnparsableFileNames().isEmpty()) {
119 collectorReportWriterService.writeFormattedMessageLine("The following files could not be parsed:\n\n");
120 for (String unparsableFileName : collectorReportData.getAllUnparsableFileNames()) {
121 List<String> batchErrors = translateErrorsFromMessageMap(collectorReportData.getMessageMapForFileName(unparsableFileName));
122 collectorReportWriterService.writeFormattedMessageLine(" " + unparsableFileName + "\n");
123 for (String errorMessage : batchErrors) {
124 collectorReportWriterService.writeFormattedMessageLine(" - ERROR MESSAGE: " + errorMessage);
125 }
126 }
127 }
128
129 while (batchIter.hasNext()) {
130 CollectorBatch batch = batchIter.next();
131 StringBuilder buf = new StringBuilder();
132
133 OriginEntryTotals batchOriginEntryTotals = batch.getOriginEntryTotals();
134 appendHeaderInformation(buf, batch, collectorReportData);
135 appendTotalsInformation(buf, batch);
136
137 List<String> errorMessages = translateErrorsFromMessageMap(batch.getMessageMap());
138
139 aggregateTotalRecordsCountFromTrailer += batch.getTotalRecords();
140
141
142 if (collectorReportData.isBatchValid(batch)) {
143
144 if (batchOriginEntryTotals != null) {
145 aggregateOriginEntryTotals.incorporateTotals(batchOriginEntryTotals);
146 }
147
148 Integer batchNumInputDetails = collectorReportData.getNumInputDetails(batch);
149 if (batchNumInputDetails != null) {
150 aggregateNumInputDetails += batchNumInputDetails;
151 }
152
153 Integer batchNumSavedDetails = collectorReportData.getNumSavedDetails(batch);
154 if (batchNumSavedDetails != null) {
155 aggregateNumSavedDetails += batchNumSavedDetails;
156 }
157 }
158
159 collectorReportWriterService.writeFormattedMessageLine("Header *********************************************************************");
160 collectorReportWriterService.writeMultipleFormattedMessageLines(buf.toString());
161
162 String validationErrors = getValidationStatus(errorMessages, false, 15);
163 if (StringUtils.isNotBlank(validationErrors)) {
164 collectorReportWriterService.writeMultipleFormattedMessageLines(validationErrors);
165 }
166 }
167
168 collectorReportWriterService.writeNewLines(2);
169 collectorReportWriterService.writeFormattedMessageLine("***** Totals for Creation of GLE Data *****");
170 collectorReportWriterService.writeFormattedMessageLine(" Total Records Read %09d", aggregateTotalRecordsCountFromTrailer);
171 collectorReportWriterService.writeFormattedMessageLine(" Total Groups Read %09d", collectorReportData.getNumPersistedBatches());
172 collectorReportWriterService.writeFormattedMessageLine(" Total Groups Bypassed %09d", collectorReportData.getNumNotPersistedBatches());
173 int totalRecordsBypassed = collectorReportData.getNumNotPersistedOriginEntryRecords() + collectorReportData.getNumNotPersistedCollectorDetailRecords();
174 collectorReportWriterService.writeFormattedMessageLine(" Total Records Bypassed %09d", totalRecordsBypassed);
175 collectorReportWriterService.writeFormattedMessageLine(" Total WWW Records Out %09d", aggregateNumInputDetails);
176 int aggregateOriginEntryCountFromParsedData = aggregateOriginEntryTotals.getNumCreditEntries() + aggregateOriginEntryTotals.getNumDebitEntries() + aggregateOriginEntryTotals.getNumOtherEntries();
177 collectorReportWriterService.writeFormattedMessageLine(" Total GLE Records Out %09d", aggregateOriginEntryCountFromParsedData);
178 collectorReportWriterService.writeFormattedMessageLine(" Total GLE Debits %19s", new KualiDecimalFormatter(aggregateOriginEntryTotals.getDebitAmount()));
179 collectorReportWriterService.writeFormattedMessageLine(" Debit Count %09d", aggregateOriginEntryTotals.getNumDebitEntries());
180 collectorReportWriterService.writeFormattedMessageLine(" Total GLE Credits %19s", new KualiDecimalFormatter(aggregateOriginEntryTotals.getCreditAmount()));
181 collectorReportWriterService.writeFormattedMessageLine(" Debit Count %09d", aggregateOriginEntryTotals.getNumCreditEntries());
182 collectorReportWriterService.writeFormattedMessageLine(" Total GLE Not C or D %19s", new KualiDecimalFormatter(aggregateOriginEntryTotals.getOtherAmount()));
183 collectorReportWriterService.writeFormattedMessageLine(" Not C or D Count %09d", aggregateOriginEntryTotals.getNumOtherEntries());
184 collectorReportWriterService.writeNewLines(1);
185 collectorReportWriterService.writeFormattedMessageLine("Inserted %d detail records into gl_id_bill_t", aggregateNumSavedDetails);
186 }
187
188
189
190
191
192
193
194 protected void appendHeaderInformation(StringBuilder buf, CollectorBatch batch, CollectorReportData collectorReportData) {
195
196 String emailBatchStatus = collectorReportData.getEmailSendingStatus().get(batch.getBatchName());
197
198 buf.append("\n Chart: ").append(batch.getChartOfAccountsCode()).append("\n");
199 buf.append(" Org: ").append(batch.getOrganizationCode()).append("\n");
200 buf.append(" Campus: ").append(batch.getCampusCode()).append("\n");
201 buf.append(" Department: ").append(batch.getDepartmentName()).append("\n");
202 buf.append(" Mailing Address: ").append(batch.getMailingAddress()).append("\n");
203 buf.append(" Contact: ").append(batch.getPersonUserID()).append("\n");
204 buf.append(" Email: ").append(batch.getEmailAddress());
205 if (StringUtils.isNotEmpty(emailBatchStatus)){
206 String displayStatus = StringUtils.containsIgnoreCase(emailBatchStatus, "ERROR")? "**Email Failure" : "**Email Success";
207 buf.append(" ( " + displayStatus + " )").append("\n");
208 }else{
209 buf.append("\n");
210 }
211 buf.append(" Transmission Date: ").append(batch.getTransmissionDate()).append("\n\n");
212 }
213
214
215
216
217
218
219
220
221 protected void appendTotalsInformation(StringBuilder buf, CollectorBatch batch) {
222 OriginEntryTotals totals = batch.getOriginEntryTotals();
223 if (totals == null) {
224 buf.append(" Totals are unavailable for this batch.\n");
225 }
226 else {
227
228 appendAmountCountLine(buf, "Group Credits = ", Integer.toString(totals.getNumCreditEntries()), totals.getCreditAmount());
229 appendAmountCountLine(buf, "Group Debits = ", Integer.toString(totals.getNumDebitEntries()), totals.getDebitAmount());
230 appendAmountCountLine(buf, "Group Not C/D = ", Integer.toString(totals.getNumOtherEntries()), totals.getOtherAmount());
231 appendAmountCountLine(buf, "Valid Group Count = ", batch.getTotalRecords().toString(), batch.getTotalAmount());
232 }
233 }
234
235
236
237
238
239
240
241
242
243 protected void appendAmountCountLine(StringBuilder buf, String countTitle, String count, KualiDecimal amount) {
244 appendPaddingString(buf, ' ', countTitle.length(), 35);
245 buf.append(countTitle);
246
247 appendPaddingString(buf, '0', count.length(), 5);
248 buf.append(count);
249
250 if (amount == null) {
251 buf.append(StringUtils.leftPad("N/A", 21));
252 }
253 else {
254 Map<String, String> settings = new HashMap<String, String>();
255 settings.put(CurrencyFormatter.SHOW_SYMBOL, Boolean.TRUE.toString());
256 org.kuali.rice.core.web.format.Formatter f = org.kuali.rice.core.web.format.Formatter.getFormatter(KualiDecimal.class, settings);
257 String amountString = (String) f.format(amount);
258 appendPaddingString(buf, ' ', amountString.length(), 21);
259 buf.append(amountString);
260 }
261
262 buf.append("\n");
263
264 }
265
266
267
268
269
270
271
272
273
274
275 protected StringBuilder appendPaddingString(StringBuilder buf, char padCharacter, int valueLength, int desiredLength) {
276 for (int i = valueLength; i < desiredLength; i++) {
277 buf.append(padCharacter);
278 }
279 return buf;
280 }
281
282 protected void appendPreScrubberReport(CollectorReportData collectorReportData) {
283 if (preScrubberService.deriveChartOfAccountsCodeIfSpaces()) {
284 collectorReportWriterService.pageBreak();
285 collectorReportWriterService.writeSubTitle("Collector Pre-Scrubber Report");
286 new PreScrubberReport().generateReport(collectorReportData.getPreScrubberReportData(), collectorReportWriterService);
287 }
288 }
289
290
291
292
293
294
295 protected void appendScrubberReport(CollectorReportData collectorReportData) {
296 Iterator<CollectorBatch> batchIter = collectorReportData.getAddedBatches();
297 ScrubberReportData aggregateScrubberReportData = new ScrubberReportData();
298 Map<Transaction, List<Message>> aggregateScrubberErrors = new LinkedHashMap<Transaction, List<Message>>();
299
300 collectorReportWriterService.pageBreak();
301
302 while (batchIter.hasNext()) {
303 CollectorBatch batch = batchIter.next();
304
305 ScrubberReportData batchScrubberReportData = collectorReportData.getScrubberReportData(batch);
306 if (batchScrubberReportData != null) {
307
308 aggregateScrubberReportData.incorporateReportData(batchScrubberReportData);
309 }
310
311 Map<Transaction, List<Message>> batchScrubberReportErrors = collectorReportData.getBatchOriginEntryScrubberErrors(batch);
312 if (batchScrubberReportErrors != null) {
313
314 aggregateScrubberErrors.putAll(batchScrubberReportErrors);
315 }
316 }
317
318 List<Transaction> transactions = new ArrayList<Transaction>(aggregateScrubberErrors.keySet());
319 for (Transaction errorTrans : aggregateScrubberErrors.keySet()) {
320 List<Message> errors = aggregateScrubberErrors.get(errorTrans);
321 collectorReportWriterService.writeError(errorTrans, errors);
322 }
323 collectorReportWriterService.writeStatisticLine("UNSCRUBBED RECORDS READ %,9d", aggregateScrubberReportData.getNumberOfUnscrubbedRecordsRead());
324 collectorReportWriterService.writeStatisticLine("SCRUBBED RECORDS WRITTEN %,9d", aggregateScrubberReportData.getNumberOfScrubbedRecordsWritten());
325 collectorReportWriterService.writeStatisticLine("ERROR RECORDS WRITTEN %,9d", aggregateScrubberReportData.getNumberOfErrorRecordsWritten());
326 collectorReportWriterService.writeStatisticLine("TOTAL OUTPUT RECORDS WRITTEN %,9d", aggregateScrubberReportData.getTotalNumberOfRecordsWritten());
327 collectorReportWriterService.writeStatisticLine("EXPIRED ACCOUNTS FOUND %,9d", aggregateScrubberReportData.getNumberOfExpiredAccountsFound());
328 }
329
330
331
332
333
334
335
336 protected void appendDemergerReport(CollectorReportData collectorReportData) {
337 Iterator<CollectorBatch> batchIter = collectorReportData.getAddedBatches();
338 DemergerReportData aggregateDemergerReportData = new DemergerReportData();
339 ScrubberReportData aggregateScrubberReportData = new ScrubberReportData();
340
341 while (batchIter.hasNext()) {
342 CollectorBatch batch = batchIter.next();
343 DemergerReportData batchDemergerReportData = collectorReportData.getDemergerReportData(batch);
344 if (batchDemergerReportData != null) {
345 aggregateDemergerReportData.incorporateReportData(batchDemergerReportData);
346 }
347 }
348
349 collectorReportWriterService.pageBreak();
350 collectorReportWriterService.writeStatisticLine("ERROR RECORDS READ %,9d", aggregateDemergerReportData.getErrorTransactionsRead());
351 collectorReportWriterService.writeStatisticLine("VALID RECORDS READ %,9d", aggregateDemergerReportData.getValidTransactionsRead());
352 collectorReportWriterService.writeStatisticLine("ERROR RECORDS REMOVED FROM PROCESSING %,9d", aggregateDemergerReportData.getErrorTransactionsSaved());
353 collectorReportWriterService.writeStatisticLine("VALID RECORDS ENTERED INTO ORIGIN ENTRY %,9d", aggregateDemergerReportData.getValidTransactionsSaved());
354 }
355
356
357
358
359
360
361
362 protected void appendDeletedOriginEntryAndDetailReport(CollectorReportData collectorReportData) {
363
364 Iterator<CollectorBatch> batchIter = collectorReportData.getAddedBatches();
365 int aggregateNumDetailsDeleted = 0;
366
367 StringBuilder buf = new StringBuilder();
368
369 collectorReportWriterService.pageBreak();
370 collectorReportWriterService.writeFormattedMessageLine("ID-Billing detail data matched with GLE errors to remove documents with errors");
371 while (batchIter.hasNext()) {
372 CollectorBatch batch = batchIter.next();
373
374 Integer batchNumDetailsDeleted = collectorReportData.getNumDetailDeleted(batch);
375 if (batchNumDetailsDeleted != null) {
376 aggregateNumDetailsDeleted += batchNumDetailsDeleted.intValue();
377 }
378 }
379 collectorReportWriterService.writeFormattedMessageLine("Total-Recs-Bypassed %d", aggregateNumDetailsDeleted);
380
381 batchIter = collectorReportData.getAddedBatches();
382 int aggregateTransactionCount = 0;
383 KualiDecimal aggregateDebitAmount = KualiDecimal.ZERO;
384 while (batchIter.hasNext()) {
385 CollectorBatch batch = batchIter.next();
386
387 Map<DocumentGroupData, OriginEntryTotals> inputEntryTotals = collectorReportData.getTotalsOnInputOriginEntriesAssociatedWithErrorGroup(batch);
388 if (inputEntryTotals != null) {
389 for (Map.Entry<DocumentGroupData, OriginEntryTotals> errorDocumentGroupEntry : inputEntryTotals.entrySet()) {
390
391
392
393
394 collectorReportWriterService.writeFormattedMessageLine("Message sent to %-40s for Document %s", batch.getEmailAddress(), errorDocumentGroupEntry.getKey().getDocumentNumber());
395 int documentTransactionCount = errorDocumentGroupEntry.getValue().getNumCreditEntries() + errorDocumentGroupEntry.getValue().getNumDebitEntries() + errorDocumentGroupEntry.getValue().getNumOtherEntries();
396 aggregateTransactionCount += documentTransactionCount;
397 aggregateDebitAmount = aggregateDebitAmount.add(errorDocumentGroupEntry.getValue().getDebitAmount());
398 collectorReportWriterService.writeFormattedMessageLine("Total Transactions %d for Total Debit Amount %s", documentTransactionCount, new KualiDecimalFormatter(errorDocumentGroupEntry.getValue().getDebitAmount()));
399 }
400 }
401 }
402 collectorReportWriterService.writeFormattedMessageLine("Total Error Records %d", aggregateTransactionCount);
403 collectorReportWriterService.writeFormattedMessageLine("Total Debit Dollars %s", new KualiDecimalFormatter(aggregateDebitAmount));
404 }
405
406
407
408
409
410
411
412 protected void appendDetailChangedAccountReport(CollectorReportData collectorReportData) {
413 StringBuilder buf = new StringBuilder();
414
415 collectorReportWriterService.writeNewLines(3);
416 collectorReportWriterService.writeFormattedMessageLine("ID-Billing Detail Records with Account Numbers Changed Due to Change of Corresponding GLE Data");
417 Iterator<CollectorBatch> batchIter = collectorReportData.getAddedBatches();
418 int aggregateNumDetailAccountValuesChanged = 0;
419 while (batchIter.hasNext()) {
420 CollectorBatch batch = batchIter.next();
421
422 Integer batchNumDetailAccountValuesChanged = collectorReportData.getNumDetailAccountValuesChanged(batch);
423 if (batchNumDetailAccountValuesChanged != null) {
424 aggregateNumDetailAccountValuesChanged += batchNumDetailAccountValuesChanged;
425 }
426 }
427 collectorReportWriterService.writeFormattedMessageLine("Tot-Recs-Changed %d", aggregateNumDetailAccountValuesChanged);
428 }
429
430
431
432
433
434
435 public void setDateTimeService(DateTimeService dateTimeService) {
436 this.dateTimeService = dateTimeService;
437 }
438
439
440
441
442
443
444
445
446 protected List<Summary> buildDemergerReportSummary(ScrubberReportData scrubberReportData, DemergerReportData demergerReport) {
447 List<Summary> reportSummary = new ArrayList<Summary>();
448 reportSummary.add(new Summary(1, "ERROR RECORDS READ", new Integer(scrubberReportData.getNumberOfErrorRecordsWritten())));
449 reportSummary.add(new Summary(2, "VALID RECORDS READ", new Integer(scrubberReportData.getNumberOfScrubbedRecordsWritten())));
450 reportSummary.add(new Summary(3, "ERROR RECORDS REMOVED FROM PROCESSING", new Integer(demergerReport.getErrorTransactionsSaved())));
451 reportSummary.add(new Summary(4, "VALID RECORDS ENTERED INTO ORIGIN ENTRY", new Integer(demergerReport.getValidTransactionsSaved())));
452
453 return reportSummary;
454 }
455
456
457
458
459
460
461
462 protected void appendLedgerReport(CollectorReportData collectorReportData) {
463 collectorReportWriterService.pageBreak();
464 collectorReportWriterService.writeSubTitle("GENERAL LEDGER INPUT TRANSACTIONS FROM COLLECTOR");
465 collectorReportWriterService.writeNewLines(1);
466
467 LedgerSummaryReport ledgerSummaryReport = collectorReportData.getLedgerSummaryReport();
468 ledgerSummaryReport.writeReport(collectorReportWriterService);
469 }
470
471
472
473
474
475
476 protected List<String> translateErrorsFromMessageMap(MessageMap messageMap) {
477 List<String> collectorErrors = new ArrayList<String>();
478
479 for (Iterator<String> iter = messageMap.getPropertiesWithErrors().iterator(); iter.hasNext();) {
480 String errorKey = iter.next();
481
482 for (Iterator<ErrorMessage> iter2 = messageMap.getMessages(errorKey).iterator(); iter2.hasNext();) {
483 ErrorMessage errorMessage = (ErrorMessage) iter2.next();
484 String messageText = configurationService.getPropertyValueAsString(errorMessage.getErrorKey());
485 collectorErrors.add(MessageFormat.format(messageText, (Object[]) errorMessage.getMessageParameters()));
486 }
487 }
488
489 return collectorErrors;
490 }
491
492
493
494
495
496
497 protected void sendValidationEmail(CollectorBatch batch, CollectorReportData collectorReportData) {
498 if (StringUtils.isBlank(batch.getEmailAddress())) {
499 LOG.error("Email not sent because email is blank, batch name " + batch.getBatchName());
500 return;
501 }
502 MessageMap messageMap = batch.getMessageMap();
503 List<String> errorMessages = translateErrorsFromMessageMap(messageMap);
504
505 LOG.debug("sendValidationEmail() starting");
506 MailMessage message = new MailMessage();
507
508 String returnAddress = parameterService.getParameterValueAsString(OLEConstants.ParameterNamespaces.GL, "Batch", OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
509 if(StringUtils.isEmpty(returnAddress)) {
510 returnAddress = mailService.getBatchMailingList();
511 }
512 message.setFromAddress(returnAddress);
513
514 String subject = parameterService.getParameterValueAsString(CollectorStep.class, SystemGroupParameterNames.COLLECTOR_VALIDATOR_EMAIL_SUBJECT_PARAMETER_NAME);
515
516 if (errorMessages.size() >0){
517 subject = parameterService.getParameterValueAsString(CollectorStep.class, SystemGroupParameterNames.COLLECTOR_VALIDATOR_ERROR_EMAIL_SUBJECT_PARAMETER_NAME);
518 }
519 message.setSubject(subject);
520
521 String body = createValidationMessageBody(errorMessages, batch, collectorReportData);
522 message.setMessage(body);
523 message.addToAddress(batch.getEmailAddress());
524
525 try {
526 mailService.sendMessage(message);
527
528 String notificationMessage = configurationService.getPropertyValueAsString(OLEKeyConstants.Collector.NOTIFICATION_EMAIL_SENT);
529 String formattedMessage = MessageFormat.format(notificationMessage, new Object[] { batch.getEmailAddress() });
530 collectorReportData.setEmailSendingStatusForParsedBatch(batch, formattedMessage);
531 }
532 catch (Exception e) {
533 LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
534 String errorMessage = configurationService.getPropertyValueAsString(OLEKeyConstants.Collector.EMAIL_SEND_ERROR);
535 String formattedMessage = MessageFormat.format(errorMessage, new Object[] { batch.getEmailAddress() });
536 collectorReportData.setEmailSendingStatusForParsedBatch(batch, formattedMessage);
537 }
538 }
539
540
541
542
543
544
545
546 protected void sendDemergerEmail(CollectorBatch batch, CollectorReportData collectorReportData) {
547 if (StringUtils.isBlank(batch.getEmailAddress())) {
548 LOG.error("Email not sent because email is blank, batch name " + batch.getBatchName());
549 return;
550 }
551 LOG.debug("sendDemergerEmail() starting");
552 String body = createDemergerMessageBody(batch, collectorReportData);
553 if (body == null) {
554
555 return;
556 }
557 MailMessage message = new MailMessage();
558
559 String returnAddress = parameterService.getParameterValueAsString(OLEConstants.ParameterNamespaces.GL, "Batch", OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
560 if(StringUtils.isEmpty(returnAddress)) {
561 returnAddress = mailService.getBatchMailingList();
562 }
563 message.setFromAddress(returnAddress);
564
565 String subject = parameterService.getParameterValueAsString(CollectorStep.class, SystemGroupParameterNames.COLLECTOR_DEMERGER_EMAIL_SUBJECT_PARAMETER_NAME);
566 String productionEnvironmentCode = configurationService.getPropertyValueAsString(OLEConstants.PROD_ENVIRONMENT_CODE_KEY);
567 String environmentCode = configurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
568 if (!StringUtils.equals(productionEnvironmentCode, environmentCode)) {
569 subject = environmentCode + ": " + subject;
570 }
571 message.setSubject(subject);
572
573 message.setMessage(body);
574 message.addToAddress(batch.getEmailAddress());
575
576 try {
577 mailService.sendMessage(message);
578
579 String notificationMessage = configurationService.getPropertyValueAsString(OLEKeyConstants.Collector.NOTIFICATION_EMAIL_SENT);
580 String formattedMessage = MessageFormat.format(notificationMessage, new Object[] { batch.getEmailAddress() });
581 collectorReportData.setEmailSendingStatusForParsedBatch(batch, formattedMessage);
582 }
583 catch (Exception e) {
584 LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
585 String errorMessage = configurationService.getPropertyValueAsString(OLEKeyConstants.Collector.EMAIL_SEND_ERROR);
586 String formattedMessage = MessageFormat.format(errorMessage, new Object[] { batch.getEmailAddress() });
587 collectorReportData.setEmailSendingStatusForParsedBatch(batch, formattedMessage);
588 }
589 }
590
591
592
593
594
595
596 protected void sendEmailSendFailureNotice(CollectorReportData collectorReportData) {
597 MailMessage message = new MailMessage();
598
599 String returnAddress = parameterService.getParameterValueAsString(OLEConstants.ParameterNamespaces.GL, "Batch", OLEConstants.FROM_EMAIL_ADDRESS_PARM_NM);
600 if(StringUtils.isEmpty(returnAddress)) {
601 returnAddress = mailService.getBatchMailingList();
602 }
603 message.setFromAddress(returnAddress);
604
605 String subject = configurationService.getPropertyValueAsString(OLEKeyConstants.ERROR_COLLECTOR_EMAILSEND_NOTIFICATION_SUBJECT);
606 String productionEnvironmentCode = configurationService.getPropertyValueAsString(OLEConstants.PROD_ENVIRONMENT_CODE_KEY);
607 String environmentCode = configurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
608 if (!StringUtils.equals(productionEnvironmentCode, environmentCode)) {
609 subject = environmentCode + ": " + subject;
610 }
611 message.setSubject(subject);
612
613 boolean hasEmailSendErrors = false;
614
615 String body = configurationService.getPropertyValueAsString(OLEKeyConstants.ERROR_COLLECTOR_EMAILSEND_NOTIFICATION_BODY);
616 for (String batchId : collectorReportData.getEmailSendingStatus().keySet()) {
617 String emailStatus = collectorReportData.getEmailSendingStatus().get(batchId);
618 if (StringUtils.containsIgnoreCase(emailStatus, "error")) {
619 body += "Batch: " + batchId + " - " + emailStatus + "\n";
620 hasEmailSendErrors = true;
621 }
622 }
623 message.setMessage(body);
624
625 message.addToAddress(mailService.getBatchMailingList());
626
627 try {
628 if (hasEmailSendErrors) {
629 mailService.sendMessage(message);
630 LOG.info("Email failure notice has been sent to : " + message.getToAddresses() );
631 }
632 }
633 catch (Exception e) {
634 LOG.error("sendErrorEmail() Invalid email address. Message not sent", e);
635 }
636 }
637
638
639
640
641
642
643
644
645
646 protected String createValidationMessageBody(List<String> errorMessages, CollectorBatch batch, CollectorReportData collectorReportData) {
647 StringBuilder body = new StringBuilder();
648
649 MessageMap fileMessageMap = batch.getMessageMap();
650
651 body.append("Header Information:\n\n");
652 if (!fileMessageMap.containsMessageKey(OLEKeyConstants.ERROR_BATCH_UPLOAD_PARSING_XML)) {
653 appendHeaderInformation(body, batch, collectorReportData);
654 appendTotalsInformation(body, batch);
655 appendValidationStatus(body, errorMessages, true, 0);
656 }
657
658 return body.toString();
659 }
660
661
662
663
664
665
666
667
668
669 protected String getValidationStatus(List<String> errorMessages, boolean notifyIfSuccessful, int numLeftPaddingSpaces) {
670 StringBuilder buf = new StringBuilder();
671 appendValidationStatus(buf, errorMessages, notifyIfSuccessful, numLeftPaddingSpaces);
672 return buf.toString();
673 }
674
675
676
677
678
679
680
681
682
683 protected void appendValidationStatus(StringBuilder buf, List<String> errorMessages, boolean notifyIfSuccessful, int numLeftPaddingSpaces) {
684 String padding = StringUtils.leftPad("", numLeftPaddingSpaces, ' ');
685
686 if (notifyIfSuccessful || !errorMessages.isEmpty()) {
687 buf.append("\n").append(padding).append("Reported Errors:\n");
688 }
689
690
691 if (errorMessages.isEmpty() && notifyIfSuccessful) {
692 buf.append(padding).append("----- NO ERRORS TO REPORT -----\nThis file will be processed by the accounting cycle.\n");
693 }
694 else if (!errorMessages.isEmpty()) {
695 for (String currentMessage : errorMessages) {
696 buf.append(padding).append(currentMessage + "\n");
697 }
698 buf.append("\n").append(padding).append("----- THIS FILE WAS NOT PROCESSED AND WILL NEED TO BE CORRECTED AND RESUBMITTED -----\n");
699 }
700 }
701
702
703
704
705
706
707
708
709 protected String createDemergerMessageBody(CollectorBatch batch, CollectorReportData collectorReportData) {
710 StringBuilder buf = new StringBuilder();
711 appendHeaderInformation(buf, batch, collectorReportData);
712
713 Map<Transaction, List<Message>> batchOriginEntryScrubberErrors = collectorReportData.getBatchOriginEntryScrubberErrors(batch);
714
715
716
717 Map<DocumentGroupData, OriginEntryTotals> errorGroupDocumentTotals = collectorReportData.getTotalsOnInputOriginEntriesAssociatedWithErrorGroup(batch);
718 Set<DocumentGroupData> errorDocumentGroups = null;
719 if (errorGroupDocumentTotals == null) {
720 return null;
721 }
722 errorDocumentGroups = errorGroupDocumentTotals.keySet();
723 if (errorDocumentGroups.isEmpty()) {
724 return null;
725 }
726 else {
727 for (DocumentGroupData errorDocumentGroup : errorDocumentGroups) {
728 buf.append("Document ").append(errorDocumentGroup.getDocumentNumber()).append(" Rejected Due to Editing Errors.\n");
729 for (Transaction transaction : batchOriginEntryScrubberErrors.keySet()) {
730 if (errorDocumentGroup.matchesTransaction(transaction)) {
731 if (transaction instanceof OriginEntryFull) {
732 OriginEntryFull entry = (OriginEntryFull) transaction;
733 buf.append(" Origin Entry: ").append(entry.getLine()).append("\n");
734 for (Message message : batchOriginEntryScrubberErrors.get(transaction)) {
735 buf.append(" ").append(message.getMessage()).append("\n");
736 }
737 }
738 }
739 }
740 }
741 }
742
743 return buf.toString();
744 }
745
746 public void setMailService(MailService mailService) {
747 this.mailService = mailService;
748 }
749
750 public void setConfigurationService(ConfigurationService configurationService) {
751 this.configurationService = configurationService;
752 }
753
754 public void setParameterService(ParameterService parameterService) {
755 this.parameterService = parameterService;
756 }
757
758
759
760
761
762 public void setCollectorReportWriterService(ReportWriterService collectorReportWriterService) {
763 this.collectorReportWriterService = collectorReportWriterService;
764 }
765
766 public void setPreScrubberService(PreScrubberService preScrubberService) {
767 this.preScrubberService = preScrubberService;
768 }
769
770 protected static class KualiDecimalFormatter implements Formattable {
771 private KualiDecimal number;
772
773 public KualiDecimalFormatter(KualiDecimal numberToFormat) {
774 this.number = numberToFormat;
775 }
776
777 @Override
778 public void formatTo(Formatter formatter, int flags, int width, int precision) {
779 Map<String, String> settings = new HashMap<String, String>();
780 settings.put(CurrencyFormatter.SHOW_SYMBOL, Boolean.TRUE.toString());
781 org.kuali.rice.core.web.format.Formatter cf = org.kuali.rice.core.web.format.Formatter.getFormatter(KualiDecimal.class, settings);
782 formatter.format((String) cf.format(number));
783 }
784 }
785 }