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