1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.module.purap.document.service.impl;
17
18 import org.apache.commons.collections.CollectionUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.commons.lang.text.StrBuilder;
21 import org.kuali.ole.module.purap.*;
22 import org.kuali.ole.module.purap.PurapConstants.ItemTypeCodes;
23 import org.kuali.ole.module.purap.PurapConstants.PREQDocumentsStrings;
24 import org.kuali.ole.module.purap.PurapConstants.PaymentRequestStatuses;
25 import org.kuali.ole.module.purap.PurapParameterConstants.NRATaxParameters;
26 import org.kuali.ole.module.purap.businessobject.*;
27 import org.kuali.ole.module.purap.document.AccountsPayableDocument;
28 import org.kuali.ole.module.purap.document.PaymentRequestDocument;
29 import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
30 import org.kuali.ole.module.purap.document.VendorCreditMemoDocument;
31 import org.kuali.ole.module.purap.document.dataaccess.PaymentRequestDao;
32 import org.kuali.ole.module.purap.document.service.*;
33 import org.kuali.ole.module.purap.document.validation.event.AttributedContinuePurapEvent;
34 import org.kuali.ole.module.purap.exception.PurError;
35 import org.kuali.ole.module.purap.service.PurapAccountingService;
36 import org.kuali.ole.module.purap.service.PurapGeneralLedgerService;
37 import org.kuali.ole.module.purap.util.ExpiredOrClosedAccountEntry;
38 import org.kuali.ole.module.purap.util.PurApItemUtils;
39 import org.kuali.ole.module.purap.util.VendorGroupingHelper;
40 import org.kuali.ole.select.OleSelectConstant;
41 import org.kuali.ole.sys.OLEConstants;
42 import org.kuali.ole.sys.OLEPropertyConstants;
43 import org.kuali.ole.sys.businessobject.AccountingLine;
44 import org.kuali.ole.sys.businessobject.Bank;
45 import org.kuali.ole.sys.businessobject.SourceAccountingLine;
46 import org.kuali.ole.sys.context.SpringContext;
47 import org.kuali.ole.sys.service.BankService;
48 import org.kuali.ole.sys.service.FinancialSystemWorkflowHelperService;
49 import org.kuali.ole.sys.service.UniversityDateService;
50 import org.kuali.ole.sys.service.impl.OleParameterConstants;
51 import org.kuali.ole.vnd.VendorConstants;
52 import org.kuali.ole.vnd.businessobject.PaymentTermType;
53 import org.kuali.ole.vnd.businessobject.VendorAddress;
54 import org.kuali.ole.vnd.businessobject.VendorDetail;
55 import org.kuali.ole.vnd.document.service.VendorService;
56 import org.kuali.rice.core.api.config.property.ConfigurationService;
57 import org.kuali.rice.core.api.datetime.DateTimeService;
58 import org.kuali.rice.core.api.util.type.KualiDecimal;
59 import org.kuali.rice.coreservice.framework.parameter.ParameterService;
60 import org.kuali.rice.kew.api.KewApiServiceLocator;
61 import org.kuali.rice.kew.api.WorkflowDocument;
62 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
63 import org.kuali.rice.kew.api.document.search.DocumentSearchResult;
64 import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
65 import org.kuali.rice.kew.api.exception.WorkflowException;
66 import org.kuali.rice.kim.api.identity.Person;
67 import org.kuali.rice.kns.service.DataDictionaryService;
68 import org.kuali.rice.krad.bo.DocumentHeader;
69 import org.kuali.rice.krad.bo.Note;
70 import org.kuali.rice.krad.exception.ValidationException;
71 import org.kuali.rice.krad.service.BusinessObjectService;
72 import org.kuali.rice.krad.service.DocumentService;
73 import org.kuali.rice.krad.service.KualiRuleService;
74 import org.kuali.rice.krad.service.NoteService;
75 import org.kuali.rice.krad.util.GlobalVariables;
76 import org.kuali.rice.krad.util.KRADPropertyConstants;
77 import org.kuali.rice.krad.util.ObjectUtils;
78 import org.kuali.rice.krad.workflow.service.WorkflowDocumentService;
79 import org.springframework.transaction.annotation.Transactional;
80
81 import java.math.BigDecimal;
82 import java.sql.Date;
83 import java.sql.Timestamp;
84 import java.util.*;
85
86
87
88
89 @Transactional
90 public class PaymentRequestServiceImpl implements PaymentRequestService {
91 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentRequestServiceImpl.class);
92
93 protected DateTimeService dateTimeService;
94 protected DocumentService documentService;
95 protected NoteService noteService;
96 protected PurapService purapService;
97 protected PaymentRequestDao paymentRequestDao;
98 protected ParameterService parameterService;
99 protected ConfigurationService configurationService;
100 protected NegativePaymentRequestApprovalLimitService negativePaymentRequestApprovalLimitService;
101 protected PurapAccountingService purapAccountingService;
102 protected BusinessObjectService businessObjectService;
103 protected PurApWorkflowIntegrationService purapWorkflowIntegrationService;
104 protected WorkflowDocumentService workflowDocumentService;
105 protected AccountsPayableService accountsPayableService;
106 protected VendorService vendorService;
107 protected DataDictionaryService dataDictionaryService;
108 protected UniversityDateService universityDateService;
109 protected BankService bankService;
110 protected PurchaseOrderService purchaseOrderService;
111 protected FinancialSystemWorkflowHelperService financialSystemWorkflowHelperService;
112 protected KualiRuleService kualiRuleService;
113 protected boolean currencyTypeIndicator = true;
114 private static transient OlePurapService olePurapService;
115
116 public static OlePurapService getOlePurapService() {
117 if (olePurapService == null) {
118 olePurapService = SpringContext.getBean(OlePurapService.class);
119 }
120 return olePurapService;
121 }
122
123
124
125
126
127
128 @Override
129 @Deprecated
130 public Collection<PaymentRequestDocument> getPaymentRequestsToExtractByCM(String campusCode, VendorCreditMemoDocument cmd) {
131 LOG.debug("getPaymentRequestsByCM() started");
132 Date currentSqlDateMidnight = dateTimeService.getCurrentSqlDateMidnight();
133 List<PaymentRequestDocument> paymentRequestIterator = paymentRequestDao.getPaymentRequestsToExtract(campusCode, null, null, cmd.getVendorHeaderGeneratedIdentifier(), cmd.getVendorDetailAssignedIdentifier(), currentSqlDateMidnight);
134
135 return filterPaymentRequestByAppDocStatus(paymentRequestIterator,
136 PurapConstants.PaymentRequestStatuses.APPDOC_AUTO_APPROVED,
137 PurapConstants.PaymentRequestStatuses.APPDOC_DEPARTMENT_APPROVED);
138 }
139
140
141
142
143
144
145 @Override
146 public Collection<PaymentRequestDocument> getPaymentRequestsToExtractByVendor(String campusCode, VendorGroupingHelper vendor, Date onOrBeforePaymentRequestPayDate) {
147 LOG.debug("getPaymentRequestsByVendor() started");
148 Collection<PaymentRequestDocument> paymentRequestDocuments = paymentRequestDao.getPaymentRequestsToExtractForVendor(campusCode, vendor, onOrBeforePaymentRequestPayDate);
149
150 return filterPaymentRequestByAppDocStatus(paymentRequestDocuments,
151 PurapConstants.PaymentRequestStatuses.APPDOC_AUTO_APPROVED,
152 PurapConstants.PaymentRequestStatuses.APPDOC_DEPARTMENT_APPROVED);
153 }
154
155
156
157
158 @Override
159 public Collection<PaymentRequestDocument> getPaymentRequestsToExtract(Date onOrBeforePaymentRequestPayDate) {
160 LOG.debug("getPaymentRequestsToExtract() started");
161
162 Collection<PaymentRequestDocument> paymentRequestIterator = paymentRequestDao.getPaymentRequestsToExtract(false, null, onOrBeforePaymentRequestPayDate);
163 return filterPaymentRequestByAppDocStatus(paymentRequestIterator,
164 PaymentRequestStatuses.STATUSES_ALLOWED_FOR_EXTRACTION);
165 }
166
167
168
169
170
171 @Override
172 public Collection<PaymentRequestDocument> getPaymentRequestsToExtractSpecialPayments(String chartCode, Date onOrBeforePaymentRequestPayDate) {
173 LOG.debug("getPaymentRequestsToExtractSpecialPayments() started");
174
175 Collection<PaymentRequestDocument> paymentRequestIterator = paymentRequestDao.getPaymentRequestsToExtract(true, chartCode, onOrBeforePaymentRequestPayDate);
176 return filterPaymentRequestByAppDocStatus(paymentRequestIterator,
177 PaymentRequestStatuses.STATUSES_ALLOWED_FOR_EXTRACTION);
178 }
179
180
181
182
183 @Override
184 public Collection<PaymentRequestDocument> getImmediatePaymentRequestsToExtract(String chartCode) {
185 LOG.debug("getImmediatePaymentRequestsToExtract() started");
186
187 Collection<PaymentRequestDocument> paymentRequestIterator = paymentRequestDao.getImmediatePaymentRequestsToExtract(chartCode);
188 return filterPaymentRequestByAppDocStatus(paymentRequestIterator,
189 PaymentRequestStatuses.STATUSES_ALLOWED_FOR_EXTRACTION);
190 }
191
192
193
194
195
196 @Override
197 public Collection<PaymentRequestDocument> getPaymentRequestToExtractByChart(String chartCode, Date onOrBeforePaymentRequestPayDate) {
198 LOG.debug("getPaymentRequestToExtractByChart() started");
199
200 Collection<PaymentRequestDocument> paymentRequestIterator = paymentRequestDao.getPaymentRequestsToExtract(false, chartCode, onOrBeforePaymentRequestPayDate);
201 return filterPaymentRequestByAppDocStatus(paymentRequestIterator,
202 PaymentRequestStatuses.STATUSES_ALLOWED_FOR_EXTRACTION);
203 }
204
205
206
207
208 @Override
209 public boolean autoApprovePaymentRequests() {
210 if (LOG.isInfoEnabled()) {
211 LOG.info("Starting autoApprovePaymentRequests.");
212 }
213 boolean hadErrorAtLeastOneError = true;
214
215 Date todayAtMidnight = dateTimeService.getCurrentSqlDateMidnight();
216
217 List<String> docNumbers = paymentRequestDao.getEligibleForAutoApproval(todayAtMidnight);
218 docNumbers = filterPaymentRequestByAppDocStatus(docNumbers, PurapConstants.PaymentRequestStatuses.PREQ_STATUSES_FOR_AUTO_APPROVE);
219 if (LOG.isInfoEnabled()) {
220 LOG.info(" -- Initial filtering complete, returned " + new Integer(docNumbers.size()).toString() + " docs.");
221 }
222
223 List<PaymentRequestDocument> docs = new ArrayList<PaymentRequestDocument>();
224 for (String docNumber : docNumbers) {
225 PaymentRequestDocument preq = getPaymentRequestByDocumentNumber(docNumber);
226 if (ObjectUtils.isNotNull(preq)) {
227 docs.add(preq);
228 }
229 }
230 if (LOG.isInfoEnabled()) {
231 LOG.info(" -- Initial filtering complete, returned " + new Integer((docs == null ? 0 : docs.size())).toString() + " docs.");
232 }
233 if (docs != null) {
234 String samt = parameterService.getParameterValueAsString(PaymentRequestDocument.class, PurapParameterConstants.PURAP_DEFAULT_NEGATIVE_PAYMENT_REQUEST_APPROVAL_LIMIT);
235 KualiDecimal defaultMinimumLimit = new KualiDecimal(samt);
236 if (LOG.isInfoEnabled()) {
237 LOG.info(" -- Using default limit value of " + defaultMinimumLimit.toString() + ".");
238 }
239 for (PaymentRequestDocument paymentRequestDocument : docs) {
240 hadErrorAtLeastOneError |= !autoApprovePaymentRequest(paymentRequestDocument, defaultMinimumLimit);
241 }
242 }
243 return hadErrorAtLeastOneError;
244 }
245
246
247
248
249
250
251
252
253 @Override
254 public boolean autoApprovePaymentRequest(String docNumber, KualiDecimal defaultMinimumLimit) {
255 PaymentRequestDocument paymentRequestDocument = null;
256 try {
257 paymentRequestDocument = (PaymentRequestDocument) documentService.getByDocumentHeaderId(docNumber);
258 if (paymentRequestDocument.isHoldIndicator() || paymentRequestDocument.isPaymentRequestedCancelIndicator() || !Arrays.asList(PurapConstants.PaymentRequestStatuses.PREQ_STATUSES_FOR_AUTO_APPROVE).contains(paymentRequestDocument.getApplicationDocumentStatus())) {
259
260
261
262
263
264
265
266
267
268 LOG.warn("Payment Request Document " + paymentRequestDocument.getDocumentNumber() + " could not be auto-approved because it has either been placed on hold, " + " requested cancel, or does not have one of the PREQ statuses for auto-approve.");
269 return true;
270 }
271 if (autoApprovePaymentRequest(paymentRequestDocument, defaultMinimumLimit)) {
272 if (LOG.isInfoEnabled()) {
273 LOG.info("Auto-approval for payment request successful. Doc number: " + docNumber);
274 }
275 return true;
276 } else {
277 LOG.error("Payment Request Document " + docNumber + " could not be auto-approved.");
278 return false;
279 }
280 } catch (WorkflowException we) {
281 LOG.error("Exception encountered when retrieving document number " + docNumber + ".", we);
282
283 throw new RuntimeException("Exception encountered when retrieving document number " + docNumber + ".", we);
284 }
285 }
286
287
288
289
290
291
292
293
294 @Override
295 public boolean autoApprovePaymentRequest(PaymentRequestDocument doc, KualiDecimal defaultMinimumLimit) {
296 if (isEligibleForAutoApproval(doc, defaultMinimumLimit)) {
297 try {
298
299
300
301
302
303
304
305
306
307
308 try {
309 ObjectUtils.materializeUpdateableCollections(doc);
310 for (PaymentRequestItem item : (List<PaymentRequestItem>) doc.getItems()) {
311 ObjectUtils.materializeUpdateableCollections(item);
312 }
313 } catch (Exception ex) {
314 throw new RuntimeException(ex);
315 }
316 doc = (PaymentRequestDocument) ObjectUtils.deepCopy(doc);
317
318 doc.updateAndSaveAppDocStatus(PaymentRequestStatuses.APPDOC_AUTO_APPROVED);
319
320 documentService.blanketApproveDocument(doc, "auto-approving: Total is below threshold.", null);
321 } catch (WorkflowException we) {
322 LOG.error("Exception encountered when approving document number " + doc.getDocumentNumber() + ".", we);
323
324 throw new RuntimeException("Exception encountered when approving document number " + doc.getDocumentNumber() + ".", we);
325 }
326 }
327 return true;
328 }
329
330 public boolean autoApprovePaymentRequest(PaymentRequestDocument doc) {
331 try {
332
333
334
335
336
337
338
339
340
341
342 try {
343 ObjectUtils.materializeUpdateableCollections(doc);
344 for (PaymentRequestItem item : (List<PaymentRequestItem>) doc.getItems()) {
345 ObjectUtils.materializeUpdateableCollections(item);
346 }
347 } catch (Exception ex) {
348 throw new RuntimeException(ex);
349 }
350 doc = (PaymentRequestDocument) ObjectUtils.deepCopy(doc);
351
352 doc.updateAndSaveAppDocStatus(PaymentRequestStatuses.APPDOC_AUTO_APPROVED);
353
354 documentService.blanketApproveDocument(doc, "auto-approving: Total is below threshold.", null);
355 } catch (WorkflowException we) {
356 LOG.error("Exception encountered when approving document number " + doc.getDocumentNumber() + ".", we);
357
358 throw new RuntimeException("Exception encountered when approving document number " + doc.getDocumentNumber() + ".", we);
359 }
360 return true;
361 }
362
363
364
365
366
367
368
369
370
371
372
373 protected boolean isEligibleForAutoApproval(PaymentRequestDocument document, KualiDecimal defaultMinimumLimit) {
374
375 if (document.getVendorDetail().getCurrencyType()!=null){
376 if(document.getVendorDetail().getCurrencyType().getCurrencyType().equalsIgnoreCase(OleSelectConstant.CURRENCY_TYPE_NAME)){
377 currencyTypeIndicator=true;
378 }
379 else{
380 currencyTypeIndicator=false;
381 }
382 }
383 if (!currencyTypeIndicator) {
384 if (LOG.isInfoEnabled()) {
385 LOG.info(" -- PayReq [" + document.getDocumentNumber() + "] skipped due to a Foreign Vendor.");
386 }
387 return false;
388 }
389
390
391 if (purapWorkflowIntegrationService.willDocumentStopAtGivenFutureRouteNode(document, PaymentRequestStatuses.NODE_VENDOR_TAX_REVIEW)) {
392 if (LOG.isInfoEnabled()) {
393 LOG.info(" -- PayReq [" + document.getDocumentNumber() + "] skipped due to requiring Tax Review.");
394 }
395 return false;
396 }
397
398
399 if (document.isPaymentRequestPositiveApprovalIndicator()) {
400 if (LOG.isInfoEnabled()) {
401 LOG.info(" -- PayReq [" + document.getDocumentNumber()
402 + "] skipped due to a Positive Approval Required Indicator set to Yes.");
403 }
404 return false;
405 }
406
407
408
409
410 KualiDecimal minimumAmount = null;
411
412
413
414
415 for (SourceAccountingLine line : purapAccountingService.generateSummary((List<PurApItem>)document.getItems())) {
416
417 Map<String, Object> autoApproveMap = new HashMap<String, Object>();
418 autoApproveMap.put("chartOfAccountsCode", line.getChartOfAccountsCode());
419 autoApproveMap.put("accountNumber", line.getAccountNumber());
420 autoApproveMap.put("active", true);
421 AutoApproveExclude autoApproveExclude = businessObjectService.findByPrimaryKey(AutoApproveExclude.class, autoApproveMap);
422 if (autoApproveExclude != null) {
423 if (LOG.isInfoEnabled()) {
424 LOG.info(" -- PayReq [" + document.getDocumentNumber() + "] skipped due to source accounting line "
425 + line.getSequenceNumber() + " using Chart/Account [" + line.getChartOfAccountsCode() + "-"
426 + line.getAccountNumber() + "], which is excluded in the Auto Approve Exclusions table.");
427 }
428 return false;
429 }
430
431 minimumAmount = getMinimumLimitAmount(negativePaymentRequestApprovalLimitService.findByChart(line.getChartOfAccountsCode()), minimumAmount);
432 minimumAmount = getMinimumLimitAmount(negativePaymentRequestApprovalLimitService.findByChartAndAccount(line.getChartOfAccountsCode(), line.getAccountNumber()), minimumAmount);
433 minimumAmount = getMinimumLimitAmount(negativePaymentRequestApprovalLimitService.findByChartAndOrganization(line.getChartOfAccountsCode(), line.getOrganizationReferenceId()), minimumAmount);
434 }
435
436
437 if (document.isReceivingDocumentRequiredIndicator()) {
438 if (LOG.isInfoEnabled()) {
439 LOG.info(" -- PayReq ["
440 + document.getDocumentNumber()
441 + "] auto-approved (ignored dollar limit) due to Receiving Document Required Indicator set to Yes.");
442 }
443 return true;
444 }
445
446
447 if (ObjectUtils.isNull(minimumAmount) || defaultMinimumLimit.compareTo(minimumAmount) < 0) {
448 minimumAmount = defaultMinimumLimit;
449 }
450
451
452 if (document.getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount().isLessThan(minimumAmount)) {
453 if (LOG.isInfoEnabled()) {
454 LOG.info(" -- PayReq ["
455 + document.getDocumentNumber()
456 + "] auto-approved due to document Total ["
457 + document.getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount()
458 + "] being less than "
459 + (minimumAmount == defaultMinimumLimit ? "Default Auto-Approval Limit "
460 : "Configured Auto-Approval Limit ") + "of "
461 + (minimumAmount == null ? "null" : minimumAmount.toString()) + ".");
462 }
463 return true;
464 }
465
466 if (LOG.isInfoEnabled()) {
467 LOG.info(" -- PayReq ["
468 + document.getDocumentNumber()
469 + "] skipped due to document Total ["
470 + document.getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount()
471 + "] being greater than "
472 + (minimumAmount == defaultMinimumLimit ? "Default Auto-Approval Limit "
473 : "Configured Auto-Approval Limit ") + "of "
474 + (minimumAmount == null ? "null" : minimumAmount.toString()) + ".");
475 }
476
477 return false;
478 }
479
480
481
482
483
484
485
486
487
488
489 protected KualiDecimal getMinimumLimitAmount(Collection<NegativePaymentRequestApprovalLimit> limits, KualiDecimal minimumAmount) {
490 for (NegativePaymentRequestApprovalLimit limit : limits) {
491 KualiDecimal amount = limit.getNegativePaymentRequestApprovalLimitAmount();
492 if (null == minimumAmount) {
493 minimumAmount = amount;
494 } else if (minimumAmount.isGreaterThan(amount)) {
495 minimumAmount = amount;
496 }
497 }
498 return minimumAmount;
499 }
500
501
502
503
504
505
506
507
508
509 @Override
510 public List getPaymentRequestsByVendorNumber(Integer vendorHeaderGeneratedId, Integer vendorDetailAssignedId) {
511 LOG.debug("getActivePaymentRequestsByVendorNumber() started");
512 return paymentRequestDao.getActivePaymentRequestsByVendorNumber(vendorHeaderGeneratedId, vendorDetailAssignedId);
513 }
514
515
516
517
518
519
520
521
522
523 @Override
524 public List getPaymentRequestsByVendorNumberInvoiceNumber(Integer vendorHeaderGeneratedId, Integer vendorDetailAssignedId, String invoiceNumber) {
525 LOG.debug("getActivePaymentRequestsByVendorNumberInvoiceNumber() started");
526 return paymentRequestDao.getActivePaymentRequestsByVendorNumberInvoiceNumber(vendorHeaderGeneratedId, vendorDetailAssignedId, invoiceNumber);
527 }
528
529
530
531
532 @Override
533 public HashMap<String, String> paymentRequestDuplicateMessages(PaymentRequestDocument document) {
534 HashMap<String, String> msgs;
535 msgs = new HashMap<String, String>();
536
537 Integer purchaseOrderId = document.getPurchaseOrderIdentifier();
538
539 if (ObjectUtils.isNotNull(document.getInvoiceDate())) {
540 if (purapService.isDateAYearBeforeToday(document.getInvoiceDate())) {
541 msgs.put(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_INVOICE_DATE_A_YEAR_OR_MORE_PAST));
542 }
543 }
544 PurchaseOrderDocument po = document.getPurchaseOrderDocument();
545
546 if (po != null) {
547 Integer vendorDetailAssignedId = po.getVendorDetailAssignedIdentifier();
548 Integer vendorHeaderGeneratedId = po.getVendorHeaderGeneratedIdentifier();
549
550 List<PaymentRequestDocument> preqs = new ArrayList();
551
552 List<PaymentRequestDocument> preqsDuplicates = getPaymentRequestsByVendorNumber(vendorHeaderGeneratedId, vendorDetailAssignedId);
553 for (PaymentRequestDocument duplicatePREQ : preqsDuplicates) {
554 if (duplicatePREQ!=null && duplicatePREQ.getInvoiceNumber()!=null &&
555 document!=null && document.getInvoiceNumber()!=null &&
556 duplicatePREQ.getInvoiceNumber().toUpperCase().equals(document.getInvoiceNumber().toUpperCase())) {
557
558 preqs.add(duplicatePREQ);
559 }
560 }
561
562 if (preqs.size() > 0) {
563 boolean addedMessage = false;
564 boolean foundCanceledPostApprove = false;
565 boolean foundCanceledPreApprove = false;
566 for (PaymentRequestDocument testPREQ : preqs) {
567 if (StringUtils.equals(testPREQ.getApplicationDocumentStatus(), PaymentRequestStatuses.APPDOC_CANCELLED_POST_AP_APPROVE)) {
568 foundCanceledPostApprove |= true;
569 } else if (StringUtils.equals(testPREQ.getApplicationDocumentStatus(), PaymentRequestStatuses.APPDOC_CANCELLED_IN_PROCESS)) {
570 foundCanceledPreApprove |= true;
571 } else {
572 msgs.put(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_INVOICE));
573 addedMessage = true;
574 break;
575 }
576 }
577
578 if (!addedMessage) {
579 if (foundCanceledPostApprove && foundCanceledPreApprove) {
580 msgs.put(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_INVOICE_CANCELLEDORVOIDED));
581 } else if (foundCanceledPreApprove) {
582 msgs.put(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_INVOICE_VOIDED));
583 } else if (foundCanceledPostApprove) {
584
585 msgs.put(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_INVOICE_CANCELLED));
586 }
587 }
588 }
589
590
591 preqs = getPaymentRequestsByPOIdInvoiceAmountInvoiceDate(purchaseOrderId, document.getVendorInvoiceAmount(), document.getInvoiceDate());
592 if (preqs.size() > 0) {
593 boolean addedMessage = false;
594 boolean foundCanceledPostApprove = false;
595 boolean foundCanceledPreApprove = false;
596 msgs.put(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_INVOICE_DATE_AMOUNT));
597 for (PaymentRequestDocument testPREQ : preqs) {
598 if (StringUtils.equalsIgnoreCase(testPREQ.getApplicationDocumentStatus(), PaymentRequestStatuses.APPDOC_CANCELLED_POST_AP_APPROVE)) {
599 foundCanceledPostApprove |= true;
600 } else if (StringUtils.equalsIgnoreCase(testPREQ.getApplicationDocumentStatus(), PaymentRequestStatuses.APPDOC_CANCELLED_IN_PROCESS)) {
601 foundCanceledPreApprove |= true;
602 } else {
603 msgs.put(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_INVOICE_DATE_AMOUNT));
604 addedMessage = true;
605 break;
606 }
607 }
608
609
610 if (!addedMessage) {
611 if (foundCanceledPostApprove && foundCanceledPreApprove) {
612 msgs.put(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_INVOICE_DATE_AMOUNT_CANCELLEDORVOIDED));
613 } else if (foundCanceledPreApprove) {
614 msgs.put(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_INVOICE_DATE_AMOUNT_VOIDED));
615 addedMessage = true;
616 } else if (foundCanceledPostApprove) {
617 msgs.put(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_INVOICE_DATE_AMOUNT_CANCELLED));
618 addedMessage = true;
619 }
620
621 }
622 }
623 }
624 return msgs;
625 }
626
627
628
629
630 @Override
631 public PaymentRequestDocument getPaymentRequestByDocumentNumber(String documentNumber) {
632 LOG.debug("getPaymentRequestByDocumentNumber() started");
633
634 if (ObjectUtils.isNotNull(documentNumber)) {
635 try {
636 PaymentRequestDocument doc = (PaymentRequestDocument) documentService.getByDocumentHeaderId(documentNumber);
637 return doc;
638 } catch (WorkflowException e) {
639 String errorMessage = "Error getting payment request document from document service";
640 LOG.error("getPaymentRequestByDocumentNumber() " + errorMessage, e);
641 throw new RuntimeException(errorMessage, e);
642 }
643 }
644 return null;
645 }
646
647
648
649
650 @Override
651 public PaymentRequestDocument getPaymentRequestById(Integer poDocId) {
652 return getPaymentRequestByDocumentNumber(paymentRequestDao.getDocumentNumberByPaymentRequestId(poDocId));
653 }
654
655
656
657
658 @Override
659 public List<PaymentRequestDocument> getPaymentRequestsByPurchaseOrderId(Integer poDocId) {
660 List<PaymentRequestDocument> preqs = new ArrayList<PaymentRequestDocument>();
661 List<String> docNumbers = paymentRequestDao.getDocumentNumbersByPurchaseOrderId(poDocId);
662 for (String docNumber : docNumbers) {
663 PaymentRequestDocument preq = getPaymentRequestByDocumentNumber(docNumber);
664 if (ObjectUtils.isNotNull(preq)) {
665 preqs.add(preq);
666 }
667 }
668 return preqs;
669 }
670
671
672
673
674
675 @Override
676 public List<PaymentRequestDocument> getPaymentRequestsByPOIdInvoiceAmountInvoiceDate(Integer poId, KualiDecimal invoiceAmount, Date invoiceDate) {
677 LOG.debug("getPaymentRequestsByPOIdInvoiceAmountInvoiceDate() started");
678 return paymentRequestDao.getActivePaymentRequestsByPOIdInvoiceAmountInvoiceDate(poId, invoiceAmount, invoiceDate);
679 }
680
681
682
683
684 @Override
685 public boolean isInvoiceDateAfterToday(Date invoiceDate) {
686
687 Calendar now = Calendar.getInstance();
688 now.set(Calendar.HOUR, 11);
689 now.set(Calendar.MINUTE, 59);
690 now.set(Calendar.SECOND, 59);
691 now.set(Calendar.MILLISECOND, 59);
692 Timestamp nowTime = new Timestamp(now.getTimeInMillis());
693 Calendar invoiceDateC = Calendar.getInstance();
694 invoiceDateC.setTime(invoiceDate);
695
696 invoiceDateC.set(Calendar.HOUR, 0);
697 invoiceDateC.set(Calendar.MINUTE, 0);
698 invoiceDateC.set(Calendar.SECOND, 0);
699 invoiceDateC.set(Calendar.MILLISECOND, 0);
700 Timestamp invoiceDateTime = new Timestamp(invoiceDateC.getTimeInMillis());
701 return ((invoiceDateTime.compareTo(nowTime)) > 0);
702 }
703
704
705
706
707
708 @Override
709 public java.sql.Date calculatePayDate(Date invoiceDate, PaymentTermType terms) {
710 LOG.debug("calculatePayDate() started");
711
712 Calendar invoicedDateCalendar = dateTimeService.getCalendar(invoiceDate);
713 Calendar processedDateCalendar = dateTimeService.getCurrentCalendar();
714
715
716 String defaultDays = parameterService.getParameterValueAsString(PaymentRequestDocument.class, PurapParameterConstants.PURAP_PREQ_PAY_DATE_DEFAULT_NUMBER_OF_DAYS);
717 processedDateCalendar.add(Calendar.DAY_OF_MONTH, Integer.parseInt(defaultDays));
718
719 if (ObjectUtils.isNull(terms) || StringUtils.isEmpty(terms.getVendorPaymentTermsCode())) {
720 invoicedDateCalendar.add(Calendar.DAY_OF_MONTH, PurapConstants.PREQ_PAY_DATE_EMPTY_TERMS_DEFAULT_DAYS);
721 return returnLaterDate(invoicedDateCalendar, processedDateCalendar);
722 }
723
724 Integer discountDueNumber = terms.getVendorDiscountDueNumber();
725 Integer netDueNumber = terms.getVendorNetDueNumber();
726 if (ObjectUtils.isNotNull(discountDueNumber)) {
727 String discountDueTypeDescription = terms.getVendorDiscountDueTypeDescription();
728 paymentTermsDateCalculation(discountDueTypeDescription, invoicedDateCalendar, discountDueNumber);
729 } else if (ObjectUtils.isNotNull(netDueNumber)) {
730 String netDueTypeDescription = terms.getVendorNetDueTypeDescription();
731 paymentTermsDateCalculation(netDueTypeDescription, invoicedDateCalendar, netDueNumber);
732 } else {
733 throw new RuntimeException("Neither discount or net number were specified for this payment terms type");
734 }
735
736
737 return returnLaterDate(invoicedDateCalendar, processedDateCalendar);
738 }
739
740
741
742
743
744
745
746
747 protected java.sql.Date returnLaterDate(Calendar invoicedDateCalendar, Calendar processedDateCalendar) {
748 if (invoicedDateCalendar.after(processedDateCalendar)) {
749 return new java.sql.Date(invoicedDateCalendar.getTimeInMillis());
750 } else {
751 return new java.sql.Date(processedDateCalendar.getTimeInMillis());
752 }
753 }
754
755
756
757
758
759
760
761
762 protected void paymentTermsDateCalculation(String dueTypeDescription, Calendar invoicedDateCalendar, Integer dueNumber) {
763
764 if (StringUtils.equals(dueTypeDescription, PurapConstants.PREQ_PAY_DATE_DATE)) {
765
766 invoicedDateCalendar.add(Calendar.MONTH, 1);
767 invoicedDateCalendar.set(Calendar.DAY_OF_MONTH, dueNumber.intValue());
768 } else if (StringUtils.equals(PurapConstants.PREQ_PAY_DATE_DAYS, dueTypeDescription)) {
769
770 invoicedDateCalendar.add(Calendar.DAY_OF_MONTH, dueNumber.intValue());
771 } else {
772
773 throw new RuntimeException("missing payment terms description or not properly enterred on payment term maintenance doc");
774 }
775 }
776
777
778
779
780
781 @Override
782 public void calculatePaymentRequest(PaymentRequestDocument paymentRequest, boolean updateDiscount) {
783 LOG.debug("calculatePaymentRequest() started");
784
785
786 if (ObjectUtils.isNull(paymentRequest.getPaymentRequestPayDate())) {
787 paymentRequest.setPaymentRequestPayDate(calculatePayDate(paymentRequest.getInvoiceDate(), paymentRequest.getVendorPaymentTerms()));
788 }
789
790 distributeAccounting(paymentRequest);
791
792 purapService.calculateTax(paymentRequest);
793
794
795 purapService.prorateForTradeInAndFullOrderDiscount(paymentRequest);
796
797
798 if (updateDiscount) {
799 calculateDiscount(paymentRequest);
800 }
801
802 distributeAccounting(paymentRequest);
803 }
804
805
806
807
808
809
810
811 protected void calculateDiscount(PaymentRequestDocument paymentRequestDocument) {
812 PaymentRequestItem discountItem = findDiscountItem(paymentRequestDocument);
813
814 PaymentTermType pt = paymentRequestDocument.getVendorPaymentTerms();
815 if ((pt != null) && (pt.getVendorPaymentTermsPercent() != null) && (BigDecimal.ZERO.compareTo(pt.getVendorPaymentTermsPercent()) != 0)) {
816 if (discountItem == null) {
817
818
819
820 purapService.addBelowLineItems(paymentRequestDocument);
821
822
823 removeIneligibleAdditionalCharges(paymentRequestDocument);
824
825 discountItem = findDiscountItem(paymentRequestDocument);
826 }
827
828
829 PaymentRequestItem fullOrderItem = findFullOrderDiscountItem(paymentRequestDocument);
830 KualiDecimal fullOrderAmount = KualiDecimal.ZERO;
831 KualiDecimal fullOrderTaxAmount = KualiDecimal.ZERO;
832
833 if (fullOrderItem != null) {
834 fullOrderAmount = (ObjectUtils.isNotNull(fullOrderItem.getExtendedPrice())) ? fullOrderItem.getExtendedPrice() : KualiDecimal.ZERO;
835 fullOrderTaxAmount = (ObjectUtils.isNotNull(fullOrderItem.getItemTaxAmount())) ? fullOrderItem.getItemTaxAmount() : KualiDecimal.ZERO;
836 }
837 KualiDecimal totalCost = paymentRequestDocument.getTotalPreTaxDollarAmountAboveLineItems().add(fullOrderAmount);
838 PurApItem tradeInItem = paymentRequestDocument.getTradeInItem();
839 if (ObjectUtils.isNotNull(tradeInItem)) {
840 totalCost = totalCost.subtract(tradeInItem.getTotalAmount());
841 }
842 BigDecimal discountAmount = pt.getVendorPaymentTermsPercent().multiply(totalCost.bigDecimalValue()).multiply(new BigDecimal(PurapConstants.PREQ_DISCOUNT_MULT));
843
844
845 discountItem.setItemUnitPrice(discountAmount.setScale(2, KualiDecimal.ROUND_BEHAVIOR));
846 discountItem.setExtendedPrice(new KualiDecimal(discountAmount));
847
848
849 boolean salesTaxInd = parameterService.getParameterValueAsBoolean(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_SALES_TAX_IND);
850 boolean useTaxIndicator = paymentRequestDocument.isUseTaxIndicator();
851
852 if (salesTaxInd == true && useTaxIndicator == false) {
853 KualiDecimal totalTax = paymentRequestDocument.getTotalTaxAmountAboveLineItems().add(fullOrderTaxAmount);
854 BigDecimal discountTaxAmount = null;
855 if (totalCost.isNonZero()) {
856 discountTaxAmount = discountAmount.divide(totalCost.bigDecimalValue()).multiply(totalTax.bigDecimalValue());
857 } else {
858 discountTaxAmount = BigDecimal.ZERO;
859 }
860
861 discountItem.setItemTaxAmount(new KualiDecimal(discountTaxAmount.setScale(KualiDecimal.SCALE, KualiDecimal.ROUND_BEHAVIOR)));
862 }
863
864
865 discountItem.setPurapDocument(paymentRequestDocument);
866 } else {
867 if (discountItem != null) {
868 paymentRequestDocument.getItems().remove(discountItem);
869 }
870 }
871
872 }
873
874
875 @Override
876 public void clearTax(PaymentRequestDocument document) {
877
878 removeTaxItems(document);
879
880 document.setTaxClassificationCode(null);
881 document.setTaxFederalPercent(null);
882 document.setTaxStatePercent(null);
883 document.setTaxCountryCode(null);
884 document.setTaxNQIId(null);
885
886 document.setTaxForeignSourceIndicator(false);
887 document.setTaxExemptTreatyIndicator(false);
888 document.setTaxOtherExemptIndicator(false);
889 document.setTaxGrossUpIndicator(false);
890 document.setTaxUSAIDPerDiemIndicator(false);
891 document.setTaxSpecialW4Amount(null);
892
893 }
894
895
896
897
898 @Override
899 public void calculateTaxArea(PaymentRequestDocument preq) {
900 LOG.debug("calculateTaxArea() started");
901
902
903 removeTaxItems(preq);
904
905
906 if (StringUtils.equalsIgnoreCase(preq.getTaxClassificationCode(), "N")) {
907 return;
908 }
909
910
911
912 BigDecimal taxableAmount = preq.getGrandPreTaxTotal().bigDecimalValue();
913
914
915
916 if (preq.getTaxGrossUpIndicator() && preq.getTaxStatePercent().compareTo(new BigDecimal(0)) != 0) {
917 PurApItem stateGrossItem = addTaxItem(preq, ItemTypeCodes.ITEM_TYPE_STATE_GROSS_CODE, taxableAmount);
918 }
919
920
921 if (preq.getTaxStatePercent().compareTo(new BigDecimal(0)) != 0) {
922 PurApItem stateTaxItem = addTaxItem(preq, ItemTypeCodes.ITEM_TYPE_STATE_TAX_CODE, taxableAmount);
923 }
924
925
926
927 if (preq.getTaxGrossUpIndicator() && preq.getTaxFederalPercent().compareTo(new BigDecimal(0)) != 0) {
928 PurApItem federalGrossItem = addTaxItem(preq, ItemTypeCodes.ITEM_TYPE_FEDERAL_GROSS_CODE, taxableAmount);
929 }
930
931
932 if (preq.getTaxFederalPercent().compareTo(new BigDecimal(0)) != 0) {
933 PurApItem federalTaxItem = addTaxItem(preq, ItemTypeCodes.ITEM_TYPE_FEDERAL_TAX_CODE, taxableAmount);
934 }
935
936
937
938
939 }
940
941
942
943
944
945
946 protected void removeTaxItems(PaymentRequestDocument preq) {
947 List<PurApItem> items = preq.getItems();
948 for (int i = 0; i < items.size(); i++) {
949 PurApItem item = items.get(i);
950 String code = item.getItemTypeCode();
951 if (ItemTypeCodes.ITEM_TYPE_FEDERAL_TAX_CODE.equals(code) || ItemTypeCodes.ITEM_TYPE_STATE_TAX_CODE.equals(code) || ItemTypeCodes.ITEM_TYPE_FEDERAL_GROSS_CODE.equals(code) || ItemTypeCodes.ITEM_TYPE_STATE_GROSS_CODE.equals(code)) {
952 items.remove(i--);
953 }
954 }
955 }
956
957
958
959
960
961
962
963
964
965 protected PurApItem addTaxItem(PaymentRequestDocument preq, String itemTypeCode, BigDecimal taxableAmount) {
966 PurApItem taxItem = null;
967
968 try {
969 taxItem = (PurApItem) preq.getItemClass().newInstance();
970 } catch (IllegalAccessException e) {
971 throw new IllegalArgumentException("Unable to access itemClass", e);
972 } catch (InstantiationException e) {
973 throw new IllegalArgumentException("Unable to instantiate itemClass", e);
974 }
975
976
977 taxItem.setItemTypeCode(itemTypeCode);
978 preq.addItem(taxItem);
979
980
981 PurApAccountingLine taxLine = addTaxAccountingLine(taxItem, taxableAmount);
982
983
984 taxItem.setItemUnitPrice(taxLine.getAmount().bigDecimalValue());
985 taxItem.setExtendedPrice(taxLine.getAmount());
986
987
988 ItemType itemType = new ItemType();
989 itemType.setItemTypeCode(itemTypeCode);
990 itemType = (ItemType) businessObjectService.retrieve(itemType);
991 taxItem.setItemType(itemType);
992 taxItem.setItemDescription(itemType.getItemTypeDescription());
993
994 return taxItem;
995 }
996
997
998
999
1000
1001
1002
1003
1004 protected PurApAccountingLine addTaxAccountingLine(PurApItem taxItem, BigDecimal taxableAmount) {
1005 PaymentRequestDocument preq = taxItem.getPurapDocument();
1006 PurApAccountingLine taxLine = null;
1007
1008 try {
1009 taxLine = (PurApAccountingLine) taxItem.getAccountingLineClass().newInstance();
1010 } catch (IllegalAccessException e) {
1011 throw new IllegalArgumentException("Unable to access sourceAccountingLineClass", e);
1012 } catch (InstantiationException e) {
1013 throw new IllegalArgumentException("Unable to instantiate sourceAccountingLineClass", e);
1014 }
1015
1016
1017 boolean isFederalTax = ItemTypeCodes.ITEM_TYPE_FEDERAL_TAX_CODE.equals(taxItem.getItemTypeCode());
1018 boolean isFederalGross = ItemTypeCodes.ITEM_TYPE_FEDERAL_GROSS_CODE.equals(taxItem.getItemTypeCode());
1019 boolean isStateTax = ItemTypeCodes.ITEM_TYPE_STATE_TAX_CODE.equals(taxItem.getItemTypeCode());
1020 boolean isStateGross = ItemTypeCodes.ITEM_TYPE_STATE_GROSS_CODE.equals(taxItem.getItemTypeCode());
1021 boolean isFederal = isFederalTax || isFederalGross;
1022 boolean isGross = isFederalGross || isStateGross;
1023
1024
1025 String taxChart = null;
1026 String taxAccount = null;
1027 String taxObjectCode = null;
1028
1029 if (isGross) {
1030
1031 AccountingLine line1 = preq.getFirstAccount();
1032 taxChart = line1.getChartOfAccountsCode();
1033 taxAccount = line1.getAccountNumber();
1034 taxObjectCode = line1.getFinancialObjectCode();
1035 } else if (isFederalTax) {
1036
1037 taxChart = parameterService.getParameterValueAsString(PaymentRequestDocument.class, NRATaxParameters.FEDERAL_TAX_PARM_PREFIX + NRATaxParameters.TAX_PARM_CHART_SUFFIX);
1038 taxAccount = parameterService.getParameterValueAsString(PaymentRequestDocument.class, NRATaxParameters.FEDERAL_TAX_PARM_PREFIX + NRATaxParameters.TAX_PARM_ACCOUNT_SUFFIX);
1039 taxObjectCode = parameterService.getSubParameterValueAsString(PaymentRequestDocument.class, NRATaxParameters.FEDERAL_TAX_PARM_PREFIX + NRATaxParameters.TAX_PARM_OBJECT_BY_INCOME_CLASS_SUFFIX, preq.getTaxClassificationCode());
1040 if (StringUtils.isBlank(taxChart) || StringUtils.isBlank(taxAccount) || StringUtils.isBlank(taxObjectCode)) {
1041 LOG.error("Unable to retrieve federal tax parameters.");
1042 throw new RuntimeException("Unable to retrieve federal tax parameters.");
1043 }
1044 } else if (isStateTax) {
1045
1046 taxChart = parameterService.getParameterValueAsString(PaymentRequestDocument.class, NRATaxParameters.STATE_TAX_PARM_PREFIX + NRATaxParameters.TAX_PARM_CHART_SUFFIX);
1047 taxAccount = parameterService.getParameterValueAsString(PaymentRequestDocument.class, NRATaxParameters.STATE_TAX_PARM_PREFIX + NRATaxParameters.TAX_PARM_ACCOUNT_SUFFIX);
1048 taxObjectCode = parameterService.getSubParameterValueAsString(PaymentRequestDocument.class, NRATaxParameters.STATE_TAX_PARM_PREFIX + NRATaxParameters.TAX_PARM_OBJECT_BY_INCOME_CLASS_SUFFIX, preq.getTaxClassificationCode());
1049 if (StringUtils.isBlank(taxChart) || StringUtils.isBlank(taxAccount) || StringUtils.isBlank(taxObjectCode)) {
1050 LOG.error("Unable to retrieve state tax parameters.");
1051 throw new RuntimeException("Unable to retrieve state tax parameters.");
1052 }
1053 }
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063 BigDecimal taxPercentFederal = preq.getTaxFederalPercent();
1064 BigDecimal taxPercentState = preq.getTaxStatePercent();
1065 BigDecimal taxPercent = isFederal ? taxPercentFederal : taxPercentState;
1066
1067
1068 BigDecimal taxDivider = new BigDecimal(100);
1069 if (preq.getTaxGrossUpIndicator()) {
1070 taxDivider = taxDivider.subtract(taxPercentFederal.add(taxPercentState));
1071 }
1072
1073
1074 BigDecimal taxAmount = taxableAmount.multiply(taxPercent);
1075 taxAmount = taxAmount.divide(taxDivider, 5, BigDecimal.ROUND_HALF_UP);
1076
1077
1078 if (!isGross) {
1079 taxAmount = taxAmount.negate();
1080 }
1081
1082
1083 taxLine.setDocumentNumber(preq.getDocumentNumber());
1084 taxLine.setSequenceNumber(preq.getNextSourceLineNumber());
1085 taxLine.setChartOfAccountsCode(taxChart);
1086 taxLine.setAccountNumber(taxAccount);
1087 taxLine.setFinancialObjectCode(taxObjectCode);
1088 taxLine.setAmount(new KualiDecimal(taxAmount));
1089
1090
1091 taxLine.setItemIdentifier(taxItem.getItemIdentifier());
1092 taxLine.setPurapItem(taxItem);
1093 taxItem.getSourceAccountingLines().add(taxLine);
1094
1095 return taxLine;
1096 }
1097
1098
1099
1100
1101
1102
1103
1104 protected PaymentRequestItem findDiscountItem(PaymentRequestDocument paymentRequestDocument) {
1105 PaymentRequestItem discountItem = null;
1106 for (PaymentRequestItem preqItem : (List<PaymentRequestItem>) paymentRequestDocument.getItems()) {
1107 if (StringUtils.equals(preqItem.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE)) {
1108 discountItem = preqItem;
1109 break;
1110 }
1111 }
1112 return discountItem;
1113 }
1114
1115
1116
1117
1118
1119
1120
1121 protected PaymentRequestItem findFullOrderDiscountItem(PaymentRequestDocument paymentRequestDocument) {
1122 PaymentRequestItem discountItem = null;
1123 for (PaymentRequestItem preqItem : (List<PaymentRequestItem>) paymentRequestDocument.getItems()) {
1124 if (StringUtils.equals(preqItem.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) {
1125 discountItem = preqItem;
1126 break;
1127 }
1128 }
1129 return discountItem;
1130 }
1131
1132
1133
1134
1135
1136
1137 protected void distributeAccounting(PaymentRequestDocument paymentRequestDocument) {
1138
1139 purapAccountingService.updateAccountAmounts(paymentRequestDocument);
1140
1141 String accountDistributionMethod = paymentRequestDocument.getAccountDistributionMethod();
1142
1143 for (PaymentRequestItem item : (List<PaymentRequestItem>) paymentRequestDocument.getItems()) {
1144 KualiDecimal totalAmount = KualiDecimal.ZERO;
1145 List<PurApAccountingLine> distributedAccounts = null;
1146 List<SourceAccountingLine> summaryAccounts = null;
1147 Set excludedItemTypeCodes = new HashSet();
1148 excludedItemTypeCodes.add(PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE);
1149
1150
1151 if (item.getItemType().isLineItemIndicator()) {
1152 continue;
1153 }
1154
1155 if ((item.getSourceAccountingLines().isEmpty()) && (ObjectUtils.isNotNull(item.getExtendedPrice())) && (KualiDecimal.ZERO.compareTo(item.getExtendedPrice()) != 0)) {
1156 if ((StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE, item.getItemType().getItemTypeCode())) && (paymentRequestDocument.getGrandTotal() != null) && ((KualiDecimal.ZERO.compareTo(paymentRequestDocument.getGrandTotal()) != 0))) {
1157
1158
1159
1160
1161
1162 totalAmount = paymentRequestDocument.getLineItemTotal();
1163
1164
1165 Set includedItemTypeCodes = new HashSet();
1166 includedItemTypeCodes.add(PurapConstants.ItemTypeCodes.ITEM_TYPE_ITEM_CODE);
1167 includedItemTypeCodes.add(PurapConstants.ItemTypeCodes.ITEM_TYPE_SERVICE_CODE);
1168
1169 summaryAccounts = purapAccountingService.generateSummaryIncludeItemTypesAndNoZeroTotals(paymentRequestDocument.getItems(), includedItemTypeCodes);
1170
1171
1172
1173 if (summaryAccounts != null) {
1174 distributedAccounts = purapAccountingService.generateAccountDistributionForProration(summaryAccounts, totalAmount, PurapConstants.PRORATION_SCALE, PaymentRequestAccount.class);
1175 }
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190 } else {
1191 PurchaseOrderItem poi = item.getPurchaseOrderItem();
1192 if ((poi != null) && (poi.getSourceAccountingLines() != null) && (!(poi.getSourceAccountingLines().isEmpty())) && (poi.getExtendedPrice() != null) && ((KualiDecimal.ZERO.compareTo(poi.getExtendedPrice())) != 0)) {
1193
1194
1195 item.generateAccountListFromPoItemAccounts(poi.getSourceAccountingLines());
1196 } else {
1197 totalAmount = paymentRequestDocument.getPurchaseOrderDocument().getTotalDollarAmountAboveLineItems();
1198 purapAccountingService.updateAccountAmounts(paymentRequestDocument.getPurchaseOrderDocument());
1199 summaryAccounts = purapAccountingService.generateSummary(PurApItemUtils.getAboveTheLineOnly(paymentRequestDocument.getPurchaseOrderDocument().getItems()));
1200 distributedAccounts = purapAccountingService.generateAccountDistributionForProration(summaryAccounts, totalAmount, new Integer("6"), PaymentRequestAccount.class);
1201 }
1202 }
1203 if (CollectionUtils.isNotEmpty(distributedAccounts) && CollectionUtils.isEmpty(item.getSourceAccountingLines())) {
1204 item.setSourceAccountingLines(distributedAccounts);
1205 }
1206 }
1207
1208 purapAccountingService.updateItemAccountAmounts(item);
1209 }
1210
1211
1212
1213 purapAccountingService.updateAccountAmounts(paymentRequestDocument);
1214 }
1215
1216
1217
1218
1219
1220 @Override
1221 public PaymentRequestDocument addHoldOnPaymentRequest(PaymentRequestDocument document, String note) throws Exception {
1222
1223 Note noteObj = documentService.createNoteFromDocument(document, note);
1224 document.addNote(noteObj);
1225 noteService.save(noteObj);
1226
1227
1228
1229 document.setHoldIndicator(true);
1230 document.setLastActionPerformedByPersonId(GlobalVariables.getUserSession().getPerson().getPrincipalId());
1231 purapService.saveDocumentNoValidation(document);
1232
1233 return document;
1234 }
1235
1236
1237
1238
1239 @Override
1240 public PaymentRequestDocument removeHoldOnPaymentRequest(PaymentRequestDocument document, String note) throws Exception {
1241
1242 Note noteObj = documentService.createNoteFromDocument(document, note);
1243 document.addNote(noteObj);
1244 noteService.save(noteObj);
1245
1246
1247
1248 document.setHoldIndicator(false);
1249 document.setLastActionPerformedByPersonId(null);
1250 purapService.saveDocumentNoValidation(document);
1251
1252 return document;
1253 }
1254
1255
1256
1257
1258
1259 @Override
1260 public void requestCancelOnPaymentRequest(PaymentRequestDocument document, String note) throws Exception {
1261
1262 Note noteObj = documentService.createNoteFromDocument(document, note);
1263 document.addNote(noteObj);
1264 noteService.save(noteObj);
1265
1266
1267 document.setPaymentRequestedCancelIndicator(true);
1268 document.setLastActionPerformedByPersonId(GlobalVariables.getUserSession().getPerson().getPrincipalId());
1269 document.setAccountsPayableRequestCancelIdentifier(GlobalVariables.getUserSession().getPerson().getPrincipalId());
1270 purapService.saveDocumentNoValidation(document);
1271 }
1272
1273
1274
1275
1276 @Override
1277 public void removeRequestCancelOnPaymentRequest(PaymentRequestDocument document, String note) throws Exception {
1278
1279 Note noteObj = documentService.createNoteFromDocument(document, note);
1280 document.addNote(noteObj);
1281 noteService.save(noteObj);
1282
1283 clearRequestCancelFields(document);
1284
1285 purapService.saveDocumentNoValidation(document);
1286
1287 }
1288
1289
1290
1291
1292
1293
1294 protected void clearRequestCancelFields(PaymentRequestDocument document) {
1295 document.setPaymentRequestedCancelIndicator(false);
1296 document.setLastActionPerformedByPersonId(null);
1297 document.setAccountsPayableRequestCancelIdentifier(null);
1298 }
1299
1300
1301
1302
1303 @Override
1304 public boolean isExtracted(PaymentRequestDocument document) {
1305 return (ObjectUtils.isNull(document.getExtractedTimestamp()) ? false : true);
1306 }
1307
1308 protected boolean isBeingAdHocRouted(PaymentRequestDocument document) {
1309 return financialSystemWorkflowHelperService.isAdhocApprovalRequestedForPrincipal(document.getDocumentHeader().getWorkflowDocument(), GlobalVariables.getUserSession().getPrincipalId());
1310 }
1311
1312
1313
1314
1315
1316 @Override
1317 public void cancelExtractedPaymentRequest(PaymentRequestDocument paymentRequest, String note) {
1318 LOG.debug("cancelExtractedPaymentRequest() started");
1319 if (PaymentRequestStatuses.CANCELLED_STATUSES.contains(paymentRequest.getApplicationDocumentStatus())) {
1320 LOG.debug("cancelExtractedPaymentRequest() ended");
1321 return;
1322 }
1323
1324 try {
1325 Note cancelNote = documentService.createNoteFromDocument(paymentRequest, note);
1326 paymentRequest.addNote(cancelNote);
1327 noteService.save(cancelNote);
1328 } catch (Exception e) {
1329 throw new RuntimeException(PurapConstants.REQ_UNABLE_TO_CREATE_NOTE, e);
1330 }
1331
1332
1333 paymentRequest.setReopenPurchaseOrderIndicator(false);
1334
1335 getAccountsPayableService().cancelAccountsPayableDocument(paymentRequest, "");
1336
1337
1338 if (LOG.isDebugEnabled()) {
1339 LOG.debug("cancelExtractedPaymentRequest() PREQ " + paymentRequest.getPurapDocumentIdentifier() + " Cancelled Without Workflow");
1340 LOG.debug("cancelExtractedPaymentRequest() ended");
1341 }
1342 }
1343
1344
1345
1346
1347
1348 @Override
1349 public void resetExtractedPaymentRequest(PaymentRequestDocument paymentRequest, String note) {
1350 LOG.debug("resetExtractedPaymentRequest() started");
1351 if (PaymentRequestStatuses.CANCELLED_STATUSES.contains(paymentRequest.getApplicationDocumentStatus())) {
1352 LOG.debug("resetExtractedPaymentRequest() ended");
1353 return;
1354 }
1355 paymentRequest.setExtractedTimestamp(null);
1356 paymentRequest.setPaymentPaidTimestamp(null);
1357 String noteText = "This Payment Request is being reset for extraction by PDP " + note;
1358 try {
1359 Note resetNote = documentService.createNoteFromDocument(paymentRequest, noteText);
1360 paymentRequest.addNote(resetNote);
1361 noteService.save(resetNote);
1362 } catch (Exception e) {
1363 throw new RuntimeException(PurapConstants.REQ_UNABLE_TO_CREATE_NOTE + " " + e);
1364 }
1365 purapService.saveDocumentNoValidation(paymentRequest);
1366 if (LOG.isDebugEnabled()) {
1367 LOG.debug("resetExtractedPaymentRequest() PREQ " + paymentRequest.getPurapDocumentIdentifier() + " Reset from Extracted status");
1368 }
1369 }
1370
1371
1372
1373
1374 @Override
1375 public void populatePaymentRequest(PaymentRequestDocument paymentRequestDocument) {
1376
1377 PurchaseOrderDocument purchaseOrderDocument = paymentRequestDocument.getPurchaseOrderDocument();
1378
1379
1380 HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList = getAccountsPayableService().getExpiredOrClosedAccountList(paymentRequestDocument);
1381 if (paymentRequestDocument.getInvoiceIdentifier() == null) {
1382 paymentRequestDocument.populatePaymentRequestFromPurchaseOrder(purchaseOrderDocument, expiredOrClosedAccountList);
1383 }
1384
1385
1386 paymentRequestDocument.getDocumentHeader().setDocumentDescription(createPreqDocumentDescription(paymentRequestDocument.getPurchaseOrderIdentifier(), paymentRequestDocument.getVendorName()));
1387
1388
1389
1390 getAccountsPayableService().generateExpiredOrClosedAccountNote(paymentRequestDocument, expiredOrClosedAccountList);
1391
1392
1393 if (!expiredOrClosedAccountList.isEmpty()) {
1394 paymentRequestDocument.setContinuationAccountIndicator(true);
1395 }
1396
1397
1398 calculateDiscount(paymentRequestDocument);
1399
1400 distributeAccounting(paymentRequestDocument);
1401
1402
1403 Bank defaultBank = bankService.getDefaultBankByDocType(paymentRequestDocument.getClass());
1404 if (defaultBank != null) {
1405 paymentRequestDocument.setBankCode(defaultBank.getBankCode());
1406 paymentRequestDocument.setBank(defaultBank);
1407 }
1408 }
1409
1410
1411
1412
1413
1414 @Override
1415 public String createPreqDocumentDescription(Integer purchaseOrderIdentifier, String vendorName) {
1416 LOG.debug("Inside createPreqDocumentDescription()");
1417 String description = getOlePurapService().getParameter(OLEConstants.PREQ_DESC);
1418 Map<String,String> descMap = new HashMap<>();
1419 descMap.put(OLEConstants.PO_DOC_ID,purchaseOrderIdentifier.toString());
1420 descMap.put(OLEConstants.VENDOR_NAME,StringUtils.trimToEmpty(vendorName));
1421 description = getOlePurapService().setDocumentDescription(description,descMap);
1422 int noteTextMaxLength = dataDictionaryService.getAttributeMaxLength(DocumentHeader.class, KRADPropertyConstants.DOCUMENT_DESCRIPTION).intValue();
1423 if (noteTextMaxLength >= description.length()) {
1424 return description;
1425 } else {
1426 return description.substring(0, noteTextMaxLength);
1427 }
1428 }
1429
1430
1431
1432
1433 @Override
1434 public void populateAndSavePaymentRequest(PaymentRequestDocument preq) throws WorkflowException {
1435 try {
1436 preq.updateAndSaveAppDocStatus(PurapConstants.PaymentRequestStatuses.APPDOC_IN_PROCESS);
1437 documentService.saveDocument(preq, AttributedContinuePurapEvent.class);
1438 LOG.info("Payment request saved successfully" + preq.getDocumentNumber());
1439 } catch (ValidationException ve) {
1440 preq.updateAndSaveAppDocStatus(PurapConstants.PaymentRequestStatuses.APPDOC_INITIATE);
1441 } catch (WorkflowException we) {
1442 preq.updateAndSaveAppDocStatus(PurapConstants.PaymentRequestStatuses.APPDOC_INITIATE);
1443
1444 String errorMsg = "Error saving document # " + preq.getDocumentHeader().getDocumentNumber() + " " + we.getMessage();
1445 LOG.error(errorMsg, we);
1446 throw new RuntimeException(errorMsg, we);
1447 }
1448 }
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459 @Override
1460 public boolean shouldPurchaseOrderBeReversed(AccountsPayableDocument apDoc) {
1461 PurchaseOrderDocument po = apDoc.getPurchaseOrderDocument();
1462 if (ObjectUtils.isNull(po)) {
1463 throw new RuntimeException("po should never be null on PREQ");
1464 }
1465
1466 if (purapService.isFullDocumentEntryCompleted(apDoc) && StringUtils.equalsIgnoreCase(PurapConstants.PurchaseOrderStatuses.APPDOC_CLOSED, po.getApplicationDocumentStatus())) {
1467 return true;
1468 }
1469 return false;
1470 }
1471
1472
1473
1474
1475 @Override
1476 public Person getPersonForCancel(AccountsPayableDocument apDoc) {
1477 PaymentRequestDocument preqDoc = (PaymentRequestDocument) apDoc;
1478 Person user = null;
1479 if (preqDoc.isPaymentRequestedCancelIndicator()) {
1480 user = preqDoc.getLastActionPerformedByUser();
1481 }
1482 return user;
1483 }
1484
1485
1486
1487
1488 @Override
1489 public void takePurchaseOrderCancelAction(AccountsPayableDocument apDoc) {
1490 PaymentRequestDocument preqDocument = (PaymentRequestDocument) apDoc;
1491 if (preqDocument.isReopenPurchaseOrderIndicator()) {
1492 String docType = PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_REOPEN_DOCUMENT;
1493 purchaseOrderService.createAndRoutePotentialChangeDocument(preqDocument.getPurchaseOrderDocument().getDocumentNumber(), docType, "reopened by Credit Memo " + apDoc.getPurapDocumentIdentifier() + "cancel", new ArrayList(), PurapConstants.PurchaseOrderStatuses.APPDOC_PENDING_REOPEN);
1494 }
1495 }
1496
1497
1498
1499
1500
1501 @Override
1502 public String updateStatusByNode(String currentNodeName, AccountsPayableDocument apDoc) {
1503 return updateStatusByNode(currentNodeName, (PaymentRequestDocument) apDoc);
1504 }
1505
1506
1507
1508
1509
1510
1511
1512
1513 protected String updateStatusByNode(String currentNodeName, PaymentRequestDocument preqDoc) {
1514
1515 clearRequestCancelFields(preqDoc);
1516
1517
1518
1519 String cancelledStatus = "";
1520 if (StringUtils.isEmpty(currentNodeName)) {
1521
1522 cancelledStatus = PurapConstants.PaymentRequestStatuses.APPDOC_CANCELLED_POST_AP_APPROVE;
1523 } else {
1524 cancelledStatus = PurapConstants.PaymentRequestStatuses.getPaymentRequestAppDocDisapproveStatuses().get(currentNodeName);
1525 }
1526
1527 if (StringUtils.isNotBlank(cancelledStatus)) {
1528
1529
1530
1531
1532
1533
1534 purapService.saveDocumentNoValidation(preqDoc);
1535 } else {
1536 logAndThrowRuntimeException("No status found to set for document being disapproved in node '" + currentNodeName + "'");
1537 }
1538 return cancelledStatus;
1539 }
1540
1541
1542
1543
1544
1545 @Override
1546 public void markPaid(PaymentRequestDocument pr, Date processDate) {
1547 LOG.debug("markPaid() started");
1548
1549 pr.setPaymentPaidTimestamp(new Timestamp(processDate.getTime()));
1550 purapService.saveDocumentNoValidation(pr);
1551 }
1552
1553
1554
1555
1556 @Override
1557 public boolean hasDiscountItem(PaymentRequestDocument preq) {
1558 return ObjectUtils.isNotNull(findDiscountItem(preq));
1559 }
1560
1561
1562
1563
1564
1565 @Override
1566 public boolean poItemEligibleForAp(AccountsPayableDocument apDoc, PurchaseOrderItem poi) {
1567 if (ObjectUtils.isNull(poi)) {
1568 throw new RuntimeException("item null in purchaseOrderItemEligibleForPayment ... this should never happen");
1569 }
1570
1571 if (!poi.isItemActiveIndicator()) {
1572 return false;
1573 }
1574
1575 ItemType poiType = poi.getItemType();
1576 if (ObjectUtils.isNull(poiType)) {
1577 return false;
1578 }
1579
1580 if (poiType.isQuantityBasedGeneralLedgerIndicator()) {
1581 if (poi.getItemQuantity().isGreaterThan(poi.getItemInvoicedTotalQuantity())) {
1582 return true;
1583 }
1584 return false;
1585 } else {
1586
1587
1588
1589 if (poi.getItemOutstandingEncumberedAmount() != null) {
1590 return true;
1591 }
1592 return false;
1593 }
1594 }
1595
1596 @Override
1597 public void removeIneligibleAdditionalCharges(PaymentRequestDocument document) {
1598
1599 List<PaymentRequestItem> itemsToRemove = new ArrayList<PaymentRequestItem>();
1600
1601 for (PaymentRequestItem item : (List<PaymentRequestItem>) document.getItems()) {
1602
1603
1604 if (ObjectUtils.isNull(item.getPurchaseOrderItemUnitPrice()) && (ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE.equals(item.getItemTypeCode()) || ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE.equals(item.getItemTypeCode()))) {
1605 itemsToRemove.add(item);
1606 continue;
1607 }
1608
1609
1610 if (StringUtils.equals(item.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE)) {
1611 PaymentTermType pt = document.getVendorPaymentTerms();
1612 if ((pt != null) && (pt.getVendorPaymentTermsPercent() != null) && (BigDecimal.ZERO.compareTo(pt.getVendorPaymentTermsPercent()) != 0)) {
1613
1614 } else {
1615
1616 itemsToRemove.add(item);
1617 }
1618 continue;
1619 }
1620
1621 }
1622
1623
1624 for (PaymentRequestItem item : itemsToRemove) {
1625 document.getItems().remove(item);
1626 }
1627 }
1628
1629 @Override
1630 public void changeVendor(PaymentRequestDocument preq, Integer headerId, Integer detailId) {
1631
1632 VendorDetail primaryVendor = vendorService.getVendorDetail(preq.getOriginalVendorHeaderGeneratedIdentifier(), preq.getOriginalVendorDetailAssignedIdentifier());
1633
1634 if (primaryVendor == null) {
1635 LOG.error("useAlternateVendor() primaryVendorDetail from database for header id " + headerId + " and detail id " + detailId + "is null");
1636 throw new PurError("AlternateVendor: VendorDetail from database for header id " + headerId + " and detail id " + detailId + "is null");
1637 }
1638
1639
1640 VendorDetail vd = vendorService.getVendorDetail(headerId, detailId);
1641 if (vd == null) {
1642 LOG.error("changeVendor() VendorDetail from database for header id " + headerId + " and detail id " + detailId + "is null");
1643 throw new PurError("changeVendor: VendorDetail from database for header id " + headerId + " and detail id " + detailId + "is null");
1644 }
1645 preq.setVendorDetail(vd);
1646 preq.setVendorName(vd.getVendorName());
1647 preq.setVendorNumber(vd.getVendorNumber());
1648 preq.setVendorHeaderGeneratedIdentifier(vd.getVendorHeaderGeneratedIdentifier());
1649 preq.setVendorDetailAssignedIdentifier(vd.getVendorDetailAssignedIdentifier());
1650 preq.setVendorPaymentTermsCode(vd.getVendorPaymentTermsCode());
1651 preq.setVendorShippingPaymentTermsCode(vd.getVendorShippingPaymentTermsCode());
1652 preq.setVendorShippingTitleCode(vd.getVendorShippingTitleCode());
1653 preq.refreshReferenceObject("vendorPaymentTerms");
1654 preq.refreshReferenceObject("vendorShippingPaymentTerms");
1655
1656
1657 String deliveryCampus = preq.getPurchaseOrderDocument().getDeliveryCampusCode();
1658 VendorAddress va = vendorService.getVendorDefaultAddress(headerId, detailId, VendorConstants.AddressTypes.REMIT, deliveryCampus);
1659 if (va == null) {
1660 va = vendorService.getVendorDefaultAddress(headerId, detailId, VendorConstants.AddressTypes.PURCHASE_ORDER, deliveryCampus);
1661 }
1662 if (va == null) {
1663 LOG.error("changeVendor() VendorAddress from database for header id " + headerId + " and detail id " + detailId + "is null");
1664 throw new PurError("changeVendor VendorAddress from database for header id " + headerId + " and detail id " + detailId + "is null");
1665 }
1666
1667 if (preq != null) {
1668 setVendorAddress(va, preq);
1669 } else {
1670 LOG.error("changeVendor(): Null link back to the Purchase Order.");
1671 throw new PurError("Null link back to the Purchase Order.");
1672 }
1673
1674
1675 preq.getDocumentHeader().setDocumentDescription(createPreqDocumentDescription(preq.getPurchaseOrderIdentifier(), preq.getVendorName()));
1676 }
1677
1678
1679
1680
1681
1682
1683
1684
1685 protected void setVendorAddress(VendorAddress va, PaymentRequestDocument preq) {
1686
1687 if (va != null) {
1688 preq.setVendorAddressGeneratedIdentifier(va.getVendorAddressGeneratedIdentifier());
1689 preq.setVendorAddressInternationalProvinceName(va.getVendorAddressInternationalProvinceName());
1690 preq.setVendorLine1Address(va.getVendorLine1Address());
1691 preq.setVendorLine2Address(va.getVendorLine2Address());
1692 preq.setVendorCityName(va.getVendorCityName());
1693 preq.setVendorStateCode(va.getVendorStateCode());
1694 preq.setVendorPostalCode(va.getVendorZipCode());
1695 preq.setVendorCountryCode(va.getVendorCountryCode());
1696 }
1697
1698 }
1699
1700
1701
1702
1703
1704
1705 protected void logAndThrowRuntimeException(String errorMessage) {
1706 this.logAndThrowRuntimeException(errorMessage, null);
1707 }
1708
1709
1710
1711
1712
1713
1714
1715 protected void logAndThrowRuntimeException(String errorMessage, Exception e) {
1716 if (ObjectUtils.isNotNull(e)) {
1717 LOG.error(errorMessage, e);
1718 throw new RuntimeException(errorMessage, e);
1719 } else {
1720 LOG.error(errorMessage);
1721 throw new RuntimeException(errorMessage);
1722 }
1723 }
1724
1725
1726
1727
1728
1729
1730 @Override
1731 public void generateGLEntriesCreateAccountsPayableDocument(AccountsPayableDocument apDocument) {
1732 PaymentRequestDocument paymentRequest = (PaymentRequestDocument) apDocument;
1733
1734 SpringContext.getBean(PurapGeneralLedgerService.class).generateEntriesCreatePaymentRequest(paymentRequest);
1735 }
1736
1737
1738
1739
1740 @Override
1741 public boolean hasActivePaymentRequestsForPurchaseOrder(Integer purchaseOrderIdentifier) {
1742
1743 boolean hasActivePreqs = false;
1744 List<String> docNumbers = null;
1745 WorkflowDocument workflowDocument = null;
1746
1747 docNumbers = paymentRequestDao.getActivePaymentRequestDocumentNumbersForPurchaseOrder(purchaseOrderIdentifier);
1748 docNumbers = filterPaymentRequestByAppDocStatus(docNumbers, PaymentRequestStatuses.STATUSES_POTENTIALLY_ACTIVE);
1749
1750 for (String docNumber : docNumbers) {
1751 try {
1752 workflowDocument = workflowDocumentService.loadWorkflowDocument(docNumber, GlobalVariables.getUserSession().getPerson());
1753 } catch (WorkflowException we) {
1754 throw new RuntimeException(we);
1755 }
1756
1757 if (!(workflowDocument.isCanceled() || workflowDocument.isException())) {
1758 hasActivePreqs = true;
1759 break;
1760 }
1761 }
1762 return hasActivePreqs;
1763 }
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776 protected List<String> filterPaymentRequestByAppDocStatus(List<String> lookupDocNumbers, String... appDocStatus) {
1777 boolean valid = false;
1778
1779 final String DOC_NUM_DELIM = "|";
1780 StrBuilder routerHeaderIdBuilder = new StrBuilder().appendWithSeparators(lookupDocNumbers, DOC_NUM_DELIM);
1781
1782 List<String> paymentRequestDocNumbers = new ArrayList<String>();
1783
1784 DocumentSearchCriteria.Builder documentSearchCriteriaDTO = DocumentSearchCriteria.Builder.create();
1785 documentSearchCriteriaDTO.setDocumentId(routerHeaderIdBuilder.toString());
1786 documentSearchCriteriaDTO.setDocumentTypeName(PurapConstants.PurapDocTypeCodes.PAYMENT_REQUEST_DOCUMENT);
1787 documentSearchCriteriaDTO.setApplicationDocumentStatuses(Arrays.asList(appDocStatus));
1788
1789 DocumentSearchResults reqDocumentsList = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(
1790 "", documentSearchCriteriaDTO.build());
1791
1792 for (DocumentSearchResult reqDocument : reqDocumentsList.getSearchResults()) {
1793
1794 if (Arrays.asList(appDocStatus).contains(reqDocument.getDocument().getApplicationDocumentStatus())) {
1795
1796 paymentRequestDocNumbers.add(reqDocument.getDocument().getDocumentId());
1797 }
1798
1799 }
1800
1801 return paymentRequestDocNumbers;
1802 }
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815 protected Collection<PaymentRequestDocument> filterPaymentRequestByAppDocStatus(Collection<PaymentRequestDocument> paymentRequestDocuments, String... appDocStatus) {
1816 List<String> paymentRequestDocNumbers = new ArrayList<String>();
1817 for (PaymentRequestDocument paymentRequest : paymentRequestDocuments) {
1818 paymentRequestDocNumbers.add(paymentRequest.getDocumentNumber());
1819 }
1820
1821 List<String> filteredPaymentRequestDocNumbers = filterPaymentRequestByAppDocStatus(paymentRequestDocNumbers, appDocStatus);
1822
1823 Collection<PaymentRequestDocument> filteredPaymentRequestDocuments = new ArrayList<PaymentRequestDocument>();
1824
1825 for (PaymentRequestDocument paymentRequest : paymentRequestDocuments) {
1826 if (filteredPaymentRequestDocNumbers.contains(paymentRequest.getDocumentNumber())) {
1827 filteredPaymentRequestDocuments.add(paymentRequest);
1828 }
1829 }
1830 return filteredPaymentRequestDocuments;
1831 }
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844 protected Iterator<PaymentRequestDocument> filterPaymentRequestByAppDocStatus(Iterator<PaymentRequestDocument> paymentRequestIterator, String... appDocStatus) {
1845 Collection<PaymentRequestDocument> paymentRequestDocuments = new ArrayList<PaymentRequestDocument>();
1846 for (; paymentRequestIterator.hasNext(); ) {
1847 paymentRequestDocuments.add(paymentRequestIterator.next());
1848 }
1849
1850 return filterPaymentRequestByAppDocStatus(paymentRequestDocuments, appDocStatus).iterator();
1851 }
1852
1853
1854
1855
1856 @Override
1857 public void processPaymentRequestInReceivingStatus() {
1858 List<String> docNumbers = paymentRequestDao.getPaymentRequestInReceivingStatus();
1859 docNumbers = filterPaymentRequestByAppDocStatus(docNumbers, PurapConstants.PaymentRequestStatuses.APPDOC_AWAITING_RECEIVING_REVIEW);
1860
1861 List<PaymentRequestDocument> preqsAwaitingReceiving = new ArrayList<PaymentRequestDocument>();
1862 for (String docNumber : docNumbers) {
1863 PaymentRequestDocument preq = getPaymentRequestByDocumentNumber(docNumber);
1864 if (ObjectUtils.isNotNull(preq)) {
1865 preqsAwaitingReceiving.add(preq);
1866 }
1867 }
1868 if (ObjectUtils.isNotNull(preqsAwaitingReceiving)) {
1869 for (PaymentRequestDocument preqDoc : preqsAwaitingReceiving) {
1870 if (preqDoc.isReceivingRequirementMet()) {
1871 try {
1872 documentService.approveDocument(preqDoc, "Approved by Receiving Required PREQ job", null);
1873 } catch (WorkflowException e) {
1874 LOG.error("processPaymentRequestInReceivingStatus() Error approving payment request document from awaiting receiving", e);
1875 throw new RuntimeException("Error approving payment request document from awaiting receiving", e);
1876 }
1877 }
1878 }
1879 }
1880 }
1881
1882
1883
1884
1885 @Override
1886 public boolean allowBackpost(PaymentRequestDocument paymentRequestDocument) {
1887 int allowBackpost = (Integer.parseInt(parameterService.getParameterValueAsString(PaymentRequestDocument.class, PurapRuleConstants.ALLOW_BACKPOST_DAYS)));
1888
1889 Calendar today = dateTimeService.getCurrentCalendar();
1890 Integer currentFY = universityDateService.getCurrentUniversityDate().getUniversityFiscalYear();
1891 java.util.Date priorClosingDateTemp = universityDateService.getLastDateOfFiscalYear(currentFY - 1);
1892 Calendar priorClosingDate = Calendar.getInstance();
1893 priorClosingDate.setTime(priorClosingDateTemp);
1894
1895
1896 Calendar allowBackpostDate = Calendar.getInstance();
1897 allowBackpostDate.setTime(priorClosingDate.getTime());
1898 allowBackpostDate.add(Calendar.DATE, allowBackpost + 1);
1899
1900 Calendar preqInvoiceDate = Calendar.getInstance();
1901 preqInvoiceDate.setTime(paymentRequestDocument.getInvoiceDate());
1902
1903
1904
1905 if ((today.compareTo(priorClosingDate) > 0) && (today.compareTo(allowBackpostDate) <= 0) && (preqInvoiceDate.compareTo(priorClosingDate) <= 0)) {
1906 LOG.debug("allowBackpost() within range to allow backpost; posting entry to period 12 of previous FY");
1907 return true;
1908 }
1909
1910 LOG.debug("allowBackpost() not within range to allow backpost; posting entry to current FY");
1911 return false;
1912 }
1913
1914 @Override
1915 public boolean isPurchaseOrderValidForPaymentRequestDocumentCreation(PaymentRequestDocument paymentRequestDocument, PurchaseOrderDocument po) {
1916 Integer POID = paymentRequestDocument.getPurchaseOrderIdentifier();
1917 boolean valid = true;
1918
1919 PurchaseOrderDocument purchaseOrderDocument = paymentRequestDocument.getPurchaseOrderDocument();
1920 if (ObjectUtils.isNull(purchaseOrderDocument)) {
1921 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, PurapKeyConstants.ERROR_PURCHASE_ORDER_NOT_EXIST);
1922 valid &= false;
1923 } else if (purchaseOrderDocument.isPendingActionIndicator()) {
1924 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, PurapKeyConstants.ERROR_PURCHASE_PENDING_ACTION);
1925 valid &= false;
1926 } else if (!StringUtils.equals(purchaseOrderDocument.getApplicationDocumentStatus(), PurapConstants.PurchaseOrderStatuses.APPDOC_OPEN)) {
1927 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, PurapKeyConstants.ERROR_PURCHASE_ORDER_NOT_OPEN);
1928 valid &= false;
1929
1930 } else {
1931
1932
1933 }
1934
1935 return valid;
1936 }
1937
1938 @Override
1939 public boolean encumberedItemExistsForInvoicing(PurchaseOrderDocument document) {
1940 boolean zeroDollar = true;
1941 GlobalVariables.getMessageMap().clearErrorPath();
1942 GlobalVariables.getMessageMap().addToErrorPath(OLEPropertyConstants.DOCUMENT);
1943 for (PurchaseOrderItem poi : (List<PurchaseOrderItem>) document.getItems()) {
1944
1945 if (poi.getItemType().isLineItemIndicator() && poi.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1946 KualiDecimal encumberedQuantity = poi.getItemOutstandingEncumberedQuantity() == null ? KualiDecimal.ZERO : poi.getItemOutstandingEncumberedQuantity();
1947 if (encumberedQuantity.compareTo(KualiDecimal.ZERO) == 1) {
1948 zeroDollar = false;
1949 break;
1950 }
1951 }
1952
1953 else if (poi.getItemType().isAmountBasedGeneralLedgerIndicator() || poi.getItemType().isAdditionalChargeIndicator()) {
1954 KualiDecimal encumberedAmount = poi.getItemOutstandingEncumberedAmount() == null ? KualiDecimal.ZERO : poi.getItemOutstandingEncumberedAmount();
1955 if (encumberedAmount.compareTo(KualiDecimal.ZERO) == 1) {
1956 zeroDollar = false;
1957 break;
1958 }
1959 }
1960 }
1961
1962 return !zeroDollar;
1963 }
1964
1965 public void setDateTimeService(DateTimeService dateTimeService) {
1966 this.dateTimeService = dateTimeService;
1967 }
1968
1969 public void setParameterService(ParameterService parameterService) {
1970 this.parameterService = parameterService;
1971 }
1972
1973 public void setConfigurationService(ConfigurationService configurationService) {
1974 this.configurationService = configurationService;
1975 }
1976
1977 public void setDocumentService(DocumentService documentService) {
1978 this.documentService = documentService;
1979 }
1980
1981 public void setNoteService(NoteService noteService) {
1982 this.noteService = noteService;
1983 }
1984
1985 public void setPurapService(PurapService purapService) {
1986 this.purapService = purapService;
1987 }
1988
1989 public void setPaymentRequestDao(PaymentRequestDao paymentRequestDao) {
1990 this.paymentRequestDao = paymentRequestDao;
1991 }
1992
1993 public void setNegativePaymentRequestApprovalLimitService(NegativePaymentRequestApprovalLimitService negativePaymentRequestApprovalLimitService) {
1994 this.negativePaymentRequestApprovalLimitService = negativePaymentRequestApprovalLimitService;
1995 }
1996
1997 public void setPurapAccountingService(PurapAccountingService purapAccountingService) {
1998 this.purapAccountingService = purapAccountingService;
1999 }
2000
2001 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
2002 this.businessObjectService = businessObjectService;
2003 }
2004
2005 public void setPurapWorkflowIntegrationService(PurApWorkflowIntegrationService purapWorkflowIntegrationService) {
2006 this.purapWorkflowIntegrationService = purapWorkflowIntegrationService;
2007 }
2008
2009 public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) {
2010 this.workflowDocumentService = workflowDocumentService;
2011 }
2012
2013 public void setAccountsPayableService(AccountsPayableService accountsPayableService) {
2014 this.accountsPayableService = accountsPayableService;
2015 }
2016
2017 public void setVendorService(VendorService vendorService) {
2018 this.vendorService = vendorService;
2019 }
2020
2021 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
2022 this.dataDictionaryService = dataDictionaryService;
2023 }
2024
2025 public void setUniversityDateService(UniversityDateService universityDateService) {
2026 this.universityDateService = universityDateService;
2027 }
2028
2029
2030 public void setBankService(BankService bankService) {
2031 this.bankService = bankService;
2032 }
2033
2034
2035 public void setPurchaseOrderService(PurchaseOrderService purchaseOrderService) {
2036 this.purchaseOrderService = purchaseOrderService;
2037 }
2038
2039 public void setFinancialSystemWorkflowHelperService(FinancialSystemWorkflowHelperService financialSystemWorkflowHelperService) {
2040 this.financialSystemWorkflowHelperService = financialSystemWorkflowHelperService;
2041 }
2042
2043
2044 public void setKualiRuleService(KualiRuleService kualiRuleService) {
2045 this.kualiRuleService = kualiRuleService;
2046 }
2047
2048
2049
2050
2051
2052
2053
2054 public AccountsPayableService getAccountsPayableService() {
2055 return SpringContext.getBean(AccountsPayableService.class);
2056 }
2057 }