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.lang.StringUtils;
19 import org.kuali.ole.module.purap.*;
20 import org.kuali.ole.module.purap.PurapConstants.PurchaseOrderStatuses;
21 import org.kuali.ole.module.purap.PurapParameterConstants.TaxParameters;
22 import org.kuali.ole.module.purap.businessobject.*;
23 import org.kuali.ole.module.purap.document.*;
24 import org.kuali.ole.module.purap.document.service.LogicContainer;
25 import org.kuali.ole.module.purap.document.service.PurapService;
26 import org.kuali.ole.module.purap.document.service.PurchaseOrderService;
27 import org.kuali.ole.module.purap.service.PurapAccountingService;
28 import org.kuali.ole.module.purap.util.PurApItemUtils;
29 import org.kuali.ole.select.businessobject.OleInvoiceItem;
30 import org.kuali.ole.select.document.OleInvoiceDocument;
31 import org.kuali.ole.sys.OLEConstants;
32 import org.kuali.ole.sys.OLEPropertyConstants;
33 import org.kuali.ole.sys.businessobject.SourceAccountingLine;
34 import org.kuali.ole.sys.businessobject.TaxDetail;
35 import org.kuali.ole.sys.context.SpringContext;
36 import org.kuali.ole.sys.document.validation.event.DocumentSystemSaveEvent;
37 import org.kuali.ole.sys.service.NonTransactional;
38 import org.kuali.ole.sys.service.TaxService;
39 import org.kuali.ole.sys.service.UniversityDateService;
40 import org.kuali.ole.sys.service.impl.OleParameterConstants;
41 import org.kuali.ole.vnd.businessobject.CommodityCode;
42 import org.kuali.ole.vnd.document.service.VendorService;
43 import org.kuali.rice.core.api.datetime.DateTimeService;
44 import org.kuali.rice.core.api.parameter.ParameterEvaluator;
45 import org.kuali.rice.core.api.parameter.ParameterEvaluatorService;
46 import org.kuali.rice.core.api.util.type.KualiDecimal;
47 import org.kuali.rice.coreservice.framework.parameter.ParameterService;
48 import org.kuali.rice.kew.api.KewApiServiceLocator;
49 import org.kuali.rice.kew.api.WorkflowDocument;
50 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeIndexingQueue;
51 import org.kuali.rice.kew.api.exception.WorkflowException;
52 import org.kuali.rice.kns.service.DataDictionaryService;
53 import org.kuali.rice.kns.util.KNSGlobalVariables;
54 import org.kuali.rice.krad.UserSession;
55 import org.kuali.rice.krad.bo.Note;
56 import org.kuali.rice.krad.document.Document;
57 import org.kuali.rice.krad.service.BusinessObjectService;
58 import org.kuali.rice.krad.service.DocumentService;
59 import org.kuali.rice.krad.service.NoteService;
60 import org.kuali.rice.krad.service.PersistenceService;
61 import org.kuali.rice.krad.util.GlobalVariables;
62 import org.kuali.rice.krad.util.KRADPropertyConstants;
63 import org.kuali.rice.krad.util.ObjectUtils;
64 import org.springframework.transaction.annotation.Transactional;
65
66 import java.math.BigDecimal;
67 import java.sql.Date;
68 import java.sql.Timestamp;
69 import java.util.*;
70
71 @NonTransactional
72 public class PurapServiceImpl implements PurapService {
73 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PurapServiceImpl.class);
74
75 private BusinessObjectService businessObjectService;
76 private DataDictionaryService dataDictionaryService;
77 private DateTimeService dateTimeService;
78 private DocumentService documentService;
79 private NoteService noteService;
80 private ParameterService parameterService;
81 private PersistenceService persistenceService;
82 private PurchaseOrderService purchaseOrderService;
83 private UniversityDateService universityDateService;
84 private VendorService vendorService;
85 private TaxService taxService;
86 private PurapAccountingService purapAccountingService;
87
88 public void setBusinessObjectService(BusinessObjectService boService) {
89 this.businessObjectService = boService;
90 }
91
92 public void setDateTimeService(DateTimeService dateTimeService) {
93 this.dateTimeService = dateTimeService;
94 }
95
96 public void setParameterService(ParameterService parameterService) {
97 this.parameterService = parameterService;
98 }
99
100 public void setDocumentService(DocumentService documentService) {
101 this.documentService = documentService;
102 }
103
104 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
105 this.dataDictionaryService = dataDictionaryService;
106 }
107
108 public void setVendorService(VendorService vendorService) {
109 this.vendorService = vendorService;
110 }
111
112 public void setPersistenceService(PersistenceService persistenceService) {
113 this.persistenceService = persistenceService;
114 }
115
116 public void setPurchaseOrderService(PurchaseOrderService purchaseOrderService) {
117 this.purchaseOrderService = purchaseOrderService;
118 }
119
120 public void setNoteService(NoteService noteService) {
121 this.noteService = noteService;
122 }
123
124 public void setUniversityDateService(UniversityDateService universityDateService) {
125 this.universityDateService = universityDateService;
126 }
127
128 public void setTaxService(TaxService taxService) {
129 this.taxService = taxService;
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 @Override
153 public void saveRoutingDataForRelatedDocuments(Integer accountsPayablePurchasingDocumentLinkIdentifier) {
154
155 try {
156
157 List<RequisitionView> reqViews = getRelatedViews(RequisitionView.class, accountsPayablePurchasingDocumentLinkIdentifier);
158 for (RequisitionView view : reqViews) {
159 Document doc = documentService.getByDocumentHeaderId(view.getDocumentNumber());
160 doc.getDocumentHeader().getWorkflowDocument().saveDocumentData();
161 }
162
163
164 List<PurchaseOrderView> poViews = getRelatedViews(PurchaseOrderView.class, accountsPayablePurchasingDocumentLinkIdentifier);
165 for (PurchaseOrderView view : poViews) {
166 Document doc = documentService.getByDocumentHeaderId(view.getDocumentNumber());
167 doc.getDocumentHeader().getWorkflowDocument().saveDocumentData();
168 }
169
170
171 List<PaymentRequestView> preqViews = getRelatedViews(PaymentRequestView.class, accountsPayablePurchasingDocumentLinkIdentifier);
172 for (PaymentRequestView view : preqViews) {
173 Document doc = documentService.getByDocumentHeaderId(view.getDocumentNumber());
174 doc.getDocumentHeader().getWorkflowDocument().saveDocumentData();
175 }
176
177
178 List<InvoiceView> invViews = getRelatedViews(InvoiceView.class, accountsPayablePurchasingDocumentLinkIdentifier);
179 for (InvoiceView invView : invViews) {
180 Document doc = documentService.getByDocumentHeaderId(invView.getDocumentNumber());
181 doc.getDocumentHeader().getWorkflowDocument().saveDocumentData();
182 }
183
184
185 List<CreditMemoView> cmViews = getRelatedViews(CreditMemoView.class, accountsPayablePurchasingDocumentLinkIdentifier);
186 for (CreditMemoView view : cmViews) {
187 Document doc = documentService.getByDocumentHeaderId(view.getDocumentNumber());
188 doc.getDocumentHeader().getWorkflowDocument().saveDocumentData();
189 }
190
191
192 List<LineItemReceivingView> lineViews = getRelatedViews(LineItemReceivingView.class, accountsPayablePurchasingDocumentLinkIdentifier);
193 for (LineItemReceivingView view : lineViews) {
194 Document doc = documentService.getByDocumentHeaderId(view.getDocumentNumber());
195 doc.getDocumentHeader().getWorkflowDocument().saveDocumentData();
196 }
197
198
199 List<CorrectionReceivingView> corrViews = getRelatedViews(CorrectionReceivingView.class, accountsPayablePurchasingDocumentLinkIdentifier);
200 for (CorrectionReceivingView view : corrViews) {
201 Document doc = documentService.getByDocumentHeaderId(view.getDocumentNumber());
202 doc.getDocumentHeader().getWorkflowDocument().saveDocumentData();
203 }
204
205
206 List<BulkReceivingView> bulkViews = getRelatedViews(BulkReceivingView.class, accountsPayablePurchasingDocumentLinkIdentifier);
207 for (BulkReceivingView view : bulkViews) {
208 Document doc = documentService.getByDocumentHeaderId(view.getDocumentNumber());
209 doc.getDocumentHeader().getWorkflowDocument().saveDocumentData();
210 }
211 } catch (WorkflowException e) {
212 throw new IllegalArgumentException("unable to save routing data for related docs", e);
213 }
214
215 }
216
217
218
219
220 @Override
221 public List<String> getRelatedDocumentIds(Integer accountsPayablePurchasingDocumentLinkIdentifier) {
222 LOG.debug("getRelatedDocumentIds() started");
223 List<String> documentIdList = new ArrayList<String>();
224
225
226 List<RequisitionView> reqViews = getRelatedViews(RequisitionView.class, accountsPayablePurchasingDocumentLinkIdentifier);
227 for (RequisitionView view : reqViews) {
228 documentIdList.add(view.getDocumentNumber());
229 }
230
231
232 List<PurchaseOrderView> poViews = getRelatedViews(PurchaseOrderView.class, accountsPayablePurchasingDocumentLinkIdentifier);
233 for (PurchaseOrderView view : poViews) {
234 documentIdList.add(view.getDocumentNumber());
235 }
236
237
238 List<PaymentRequestView> preqViews = getRelatedViews(PaymentRequestView.class, accountsPayablePurchasingDocumentLinkIdentifier);
239 for (PaymentRequestView view : preqViews) {
240 documentIdList.add(view.getDocumentNumber());
241 }
242
243
244 List<InvoiceView> invViews = getRelatedViews(InvoiceView.class, accountsPayablePurchasingDocumentLinkIdentifier);
245 for (InvoiceView invView : invViews) {
246 documentIdList.add(invView.getDocumentNumber());
247 }
248
249
250 List<CreditMemoView> cmViews = getRelatedViews(CreditMemoView.class, accountsPayablePurchasingDocumentLinkIdentifier);
251 for (CreditMemoView view : cmViews) {
252 documentIdList.add(view.getDocumentNumber());
253 }
254
255
256 List<LineItemReceivingView> lineViews = getRelatedViews(LineItemReceivingView.class, accountsPayablePurchasingDocumentLinkIdentifier);
257 for (LineItemReceivingView view : lineViews) {
258 documentIdList.add(view.getDocumentNumber());
259 }
260
261
262 List<CorrectionReceivingView> corrViews = getRelatedViews(CorrectionReceivingView.class, accountsPayablePurchasingDocumentLinkIdentifier);
263 for (CorrectionReceivingView view : corrViews) {
264 documentIdList.add(view.getDocumentNumber());
265 }
266
267
268 List<BulkReceivingView> bulkViews = getRelatedViews(BulkReceivingView.class, accountsPayablePurchasingDocumentLinkIdentifier);
269 for (BulkReceivingView view : bulkViews) {
270 documentIdList.add(view.getDocumentNumber());
271 }
272
273
274
275 return documentIdList;
276 }
277
278
279
280
281 @Override
282 @SuppressWarnings("unchecked")
283 @Transactional
284 public List getRelatedViews(Class clazz, Integer accountsPayablePurchasingDocumentLinkIdentifier) {
285 LOG.debug("getRelatedViews() started");
286
287 Map criteria = new HashMap();
288 String st = clazz.getSimpleName();
289
290
291 if (st.equals("InvoiceView")) {
292 Map criteriaMap = new HashMap();
293 criteriaMap.put("accountsPayablePurchasingDocumentLinkIdentifier", accountsPayablePurchasingDocumentLinkIdentifier);
294 List<OleInvoiceItem> boInvoiceItemList = (List<OleInvoiceItem>) businessObjectService.findMatching(OleInvoiceItem.class, criteriaMap);
295 List boList = new ArrayList();
296 if (boInvoiceItemList.size() > 0) {
297 for (OleInvoiceItem item : boInvoiceItemList) {
298 accountsPayablePurchasingDocumentLinkIdentifier =item.getInvoiceDocument().getAccountsPayablePurchasingDocumentLinkIdentifier();
299 criteria.put("accountsPayablePurchasingDocumentLinkIdentifier", accountsPayablePurchasingDocumentLinkIdentifier);
300 boList.addAll((List) businessObjectService.findMatchingOrderBy(clazz, criteria, OLEPropertyConstants.DOCUMENT_NUMBER, false));
301
302 }
303 return boList;
304 }
305 }
306 criteria.put("accountsPayablePurchasingDocumentLinkIdentifier", accountsPayablePurchasingDocumentLinkIdentifier);
307
308 List boList = (List) businessObjectService.findMatchingOrderBy(clazz, criteria, OLEPropertyConstants.DOCUMENT_NUMBER, false);
309 return boList;
310 }
311
312
313
314
315 @Override
316 @SuppressWarnings("unchecked")
317 public void addBelowLineItems(PurchasingAccountsPayableDocument document) {
318 LOG.debug("addBelowLineItems() started");
319
320 String[] itemTypes = getBelowTheLineForDocument(document);
321
322 List<PurApItem> existingItems = document.getItems();
323
324 List<PurApItem> belowTheLine = new ArrayList<PurApItem>();
325
326 sortBelowTheLine(itemTypes, existingItems, belowTheLine);
327
328 List<String> existingItemTypes = new ArrayList<String>();
329 for (PurApItem existingItem : existingItems) {
330 existingItemTypes.add(existingItem.getItemTypeCode());
331 }
332
333 Class itemClass = document.getItemClass();
334
335 for (int i = 0; i < itemTypes.length; i++) {
336 int lastFound;
337 if (!existingItemTypes.contains(itemTypes[i])) {
338 try {
339 if (i > 0) {
340 lastFound = existingItemTypes.lastIndexOf(itemTypes[i - 1]) + 1;
341 } else {
342 lastFound = existingItemTypes.size();
343 }
344 PurApItem newItem = (PurApItem) itemClass.newInstance();
345 newItem.setItemTypeCode(itemTypes[i]);
346 newItem.setPurapDocument(document);
347 existingItems.add(lastFound, newItem);
348 existingItemTypes.add(itemTypes[i]);
349 } catch (Exception e) {
350
351 }
352 }
353 }
354
355 document.fixItemReferences();
356 }
357
358
359
360
361
362
363
364
365 protected void sortBelowTheLine(String[] itemTypes, List<PurApItem> existingItems, List<PurApItem> belowTheLine) {
366 LOG.debug("sortBelowTheLine() started");
367
368
369 for (int i = 0; i < existingItems.size(); i++) {
370 PurApItem purApItem = existingItems.get(i);
371 if (purApItem.getItemType().isAdditionalChargeIndicator()) {
372 belowTheLine.add(existingItems.get(i));
373 }
374 }
375 existingItems.removeAll(belowTheLine);
376 for (String itemType : itemTypes) {
377 for (PurApItem purApItem : belowTheLine) {
378 if (StringUtils.equalsIgnoreCase(purApItem.getItemTypeCode(), itemType)) {
379 existingItems.add(purApItem);
380 break;
381 }
382 }
383 }
384 belowTheLine.removeAll(existingItems);
385 if (belowTheLine.size() != 0) {
386 throw new RuntimeException("below the line item sort didn't work: trying to remove an item without adding it back");
387 }
388 }
389
390
391
392
393 @Override
394 public void sortBelowTheLine(PurchasingAccountsPayableDocument document) {
395 LOG.debug("sortBelowTheLine() started");
396
397 String[] itemTypes = getBelowTheLineForDocument(document);
398
399 List<PurApItem> existingItems = document.getItems();
400
401 List<PurApItem> belowTheLine = new ArrayList<PurApItem>();
402
403 sortBelowTheLine(itemTypes, existingItems, belowTheLine);
404 }
405
406
407
408
409 @Override
410 public String[] getBelowTheLineForDocument(PurchasingAccountsPayableDocument document) {
411 LOG.debug("getBelowTheLineForDocument() started");
412
413
414
415
416
417
418
419
420
421
422
423
424
425 String documentType = dataDictionaryService.getDocumentTypeNameByClass(document.getClass());
426
427 try {
428 return parameterService.getParameterValuesAsString(Class.forName(PurapConstants.PURAP_DETAIL_TYPE_CODE_MAP.get(documentType)), PurapConstants.BELOW_THE_LINES_PARAMETER).toArray(new String[]{});
429 } catch (ClassNotFoundException e) {
430 throw new RuntimeException("The getBelowTheLineForDocument method of PurapServiceImpl was unable to resolve the document class for type: " + PurapConstants.PURAP_DETAIL_TYPE_CODE_MAP.get(documentType), e);
431 }
432 }
433
434
435
436
437
438 @Override
439 public PurApItem getBelowTheLineByType(PurchasingAccountsPayableDocument document, ItemType iT) {
440 LOG.debug("getBelowTheLineByType() started");
441
442 String[] itemTypes = getBelowTheLineForDocument(document);
443 boolean foundItemType = false;
444 for (String itemType : itemTypes) {
445 if (StringUtils.equals(iT.getItemTypeCode(), itemType)) {
446 foundItemType = true;
447 break;
448 }
449 }
450 if (!foundItemType) {
451 return null;
452 }
453
454 PurApItem belowTheLineItem = null;
455 for (PurApItem item : document.getItems()) {
456 if (item.getItemType().isAdditionalChargeIndicator()) {
457 if (StringUtils.equals(iT.getItemTypeCode(), item.getItemType().getItemTypeCode())) {
458 belowTheLineItem = item;
459 break;
460 }
461 }
462 }
463 return belowTheLineItem;
464 }
465
466
467
468
469 @Override
470 public Date getDateFromOffsetFromToday(int offsetDays) {
471 Calendar calendar = dateTimeService.getCurrentCalendar();
472 calendar.add(Calendar.DATE, offsetDays);
473 return new Date(calendar.getTimeInMillis());
474 }
475
476
477
478
479 @Override
480 public boolean isDateInPast(Date compareDate) {
481 LOG.debug("isDateInPast() started");
482
483 Date today = dateTimeService.getCurrentSqlDate();
484 int diffFromToday = dateTimeService.dateDiff(today, compareDate, false);
485 return (diffFromToday < 0);
486 }
487
488
489
490
491 @Override
492 public boolean isDateMoreThanANumberOfDaysAway(Date compareDate, int daysAway) {
493 LOG.debug("isDateMoreThanANumberOfDaysAway() started");
494
495 Date todayAtMidnight = dateTimeService.getCurrentSqlDateMidnight();
496 Calendar daysAwayCalendar = dateTimeService.getCalendar(todayAtMidnight);
497 daysAwayCalendar.add(Calendar.DATE, daysAway);
498 Timestamp daysAwayTime = new Timestamp(daysAwayCalendar.getTime().getTime());
499 Calendar compareCalendar = dateTimeService.getCalendar(compareDate);
500 compareCalendar.set(Calendar.HOUR, 0);
501 compareCalendar.set(Calendar.MINUTE, 0);
502 compareCalendar.set(Calendar.SECOND, 0);
503 compareCalendar.set(Calendar.MILLISECOND, 0);
504 compareCalendar.set(Calendar.AM_PM, Calendar.AM);
505 Timestamp compareTime = new Timestamp(compareCalendar.getTime().getTime());
506 return (compareTime.compareTo(daysAwayTime) > 0);
507 }
508
509
510
511
512 @Override
513 public boolean isDateAYearBeforeToday(Date compareDate) {
514 LOG.debug("isDateAYearBeforeToday() started");
515
516 Calendar calendar = dateTimeService.getCurrentCalendar();
517 calendar.add(Calendar.YEAR, -1);
518 Date yearAgo = new Date(calendar.getTimeInMillis());
519 int diffFromYearAgo = dateTimeService.dateDiff(compareDate, yearAgo, false);
520 return (diffFromYearAgo > 0);
521 }
522
523
524
525
526 @Override
527 @SuppressWarnings("unchecked")
528 public KualiDecimal getApoLimit(Integer vendorContractGeneratedIdentifier, String chart, String org) {
529 LOG.debug("getApoLimit() started");
530
531 KualiDecimal purchaseOrderTotalLimit = vendorService.getApoLimitFromContract(vendorContractGeneratedIdentifier, chart, org);
532
533
534 if (ObjectUtils.isNull(purchaseOrderTotalLimit) && !ObjectUtils.isNull(chart) && !ObjectUtils.isNull(org)) {
535 OrganizationParameter organizationParameter = new OrganizationParameter();
536 organizationParameter.setChartOfAccountsCode(chart);
537 organizationParameter.setOrganizationCode(org);
538 Map orgParamKeys = persistenceService.getPrimaryKeyFieldValues(organizationParameter);
539 orgParamKeys.put(KRADPropertyConstants.ACTIVE_INDICATOR, true);
540 organizationParameter = businessObjectService.findByPrimaryKey(OrganizationParameter.class, orgParamKeys);
541 purchaseOrderTotalLimit = (organizationParameter == null) ? null : organizationParameter.getOrganizationAutomaticPurchaseOrderLimit();
542 }
543
544 if (ObjectUtils.isNull(purchaseOrderTotalLimit)) {
545 String defaultLimit = parameterService.getParameterValueAsString(RequisitionDocument.class, PurapParameterConstants.AUTOMATIC_PURCHASE_ORDER_DEFAULT_LIMIT_AMOUNT);
546 purchaseOrderTotalLimit = new KualiDecimal(defaultLimit);
547 }
548
549 return purchaseOrderTotalLimit;
550 }
551
552
553
554
555 @Override
556 public boolean isFullDocumentEntryCompleted(PurchasingAccountsPayableDocument purapDocument) {
557 LOG.debug("isFullDocumentEntryCompleted() started");
558
559
560 boolean value = false;
561 if (purapDocument instanceof PaymentRequestDocument) {
562 value = PurapConstants.PaymentRequestStatuses.STATUS_ORDER.isFullDocumentEntryCompleted(purapDocument.getApplicationDocumentStatus());
563 } else if (purapDocument instanceof VendorCreditMemoDocument) {
564 value = PurapConstants.CreditMemoStatuses.STATUS_ORDER.isFullDocumentEntryCompleted(purapDocument.getApplicationDocumentStatus());
565 } else if (purapDocument instanceof OleInvoiceDocument) {
566 value = PurapConstants.InvoiceStatuses.STATUS_ORDER.isFullDocumentEntryCompleted(purapDocument.getApplicationDocumentStatus());
567 }
568 return value;
569 }
570
571
572
573
574 @Override
575 public boolean isPaymentRequestFullDocumentEntryCompleted(String purapDocumentStatus) {
576 LOG.debug("isPaymentRequestFullDocumentEntryCompleted() started");
577 return PurapConstants.PaymentRequestStatuses.STATUS_ORDER.isFullDocumentEntryCompleted(purapDocumentStatus);
578 }
579
580
581
582
583 @Override
584 public boolean isVendorCreditMemoFullDocumentEntryCompleted(String purapDocumentStatus) {
585 LOG.debug("isVendorCreditMemoFullDocumentEntryCompleted() started");
586 return PurapConstants.CreditMemoStatuses.STATUS_ORDER.isFullDocumentEntryCompleted(purapDocumentStatus);
587 }
588
589
590
591
592 @Override
593 public boolean isInvoiceFullDocumentEntryCompleted(String purapDocumentStatus) {
594 LOG.debug("isInvoiceFullDocumentEntryCompleted() started");
595 return PurapConstants.InvoiceStatuses.STATUS_ORDER.isFullDocumentEntryCompleted(purapDocumentStatus);
596 }
597
598
599
600
601
602
603 @Override
604 public void performLogicForCloseReopenPO(PurchasingAccountsPayableDocument purapDocument) {
605 LOG.debug("performLogicForCloseReopenPO() started");
606
607 if (purapDocument instanceof PaymentRequestDocument) {
608 PaymentRequestDocument paymentRequest = (PaymentRequestDocument) purapDocument;
609
610 if (paymentRequest.isClosePurchaseOrderIndicator() && PurchaseOrderStatuses.APPDOC_OPEN.equals(paymentRequest.getPurchaseOrderDocument().getApplicationDocumentStatus())) {
611
612
613 processCloseReopenPo((AccountsPayableDocumentBase) purapDocument, PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_CLOSE_DOCUMENT);
614 }
615
616 } else if (purapDocument instanceof VendorCreditMemoDocument) {
617 VendorCreditMemoDocument creditMemo = (VendorCreditMemoDocument) purapDocument;
618
619 if (creditMemo.isReopenPurchaseOrderIndicator() && PurchaseOrderStatuses.APPDOC_CLOSED.equals(creditMemo.getPurchaseOrderDocument().getApplicationDocumentStatus())) {
620
621
622 processCloseReopenPo((AccountsPayableDocumentBase) purapDocument, PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_REOPEN_DOCUMENT);
623 }
624
625 } else {
626 throw new RuntimeException("Attempted to perform full entry logic for unhandled document type '" + purapDocument.getClass().getName() + "'");
627 }
628
629 }
630
631
632
633
634
635
636
637 @Override
638 public void deleteUnenteredItems(PurapItemOperations document) {
639 LOG.debug("deleteUnenteredItems() started");
640
641 List<PurapEnterableItem> deletionList = new ArrayList<PurapEnterableItem>();
642 for (PurapEnterableItem item : (List<PurapEnterableItem>) document.getItems()) {
643 if (!item.isConsideredEntered()) {
644 deletionList.add(item);
645 }
646 }
647 document.getItems().removeAll(deletionList);
648 }
649
650
651
652
653
654
655
656 @SuppressWarnings("unchecked")
657 public void processCloseReopenPo(AccountsPayableDocumentBase apDocument, String docType) {
658 LOG.debug("processCloseReopenPo() started");
659
660 String action = null;
661 String newStatus = null;
662
663 if (PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_CLOSE_DOCUMENT.equals(docType)) {
664 action = "closed";
665 newStatus = PurchaseOrderStatuses.APPDOC_PENDING_CLOSE;
666 } else if (PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_REOPEN_DOCUMENT.equals(docType)) {
667 action = "reopened";
668 newStatus = PurchaseOrderStatuses.APPDOC_PENDING_REOPEN;
669 } else {
670 String errorMessage = "Method processCloseReopenPo called using ID + '" + apDocument.getPurapDocumentIdentifier() + "' and invalid doc type '" + docType + "'";
671 LOG.error(errorMessage);
672 throw new RuntimeException(errorMessage);
673 }
674
675
676 Integer poId = apDocument.getPurchaseOrderIdentifier();
677 PurchaseOrderDocument purchaseOrderDocument = purchaseOrderService.getCurrentPurchaseOrder(poId);
678 if (!StringUtils.equalsIgnoreCase(purchaseOrderDocument.getDocumentHeader().getWorkflowDocument().getDocumentTypeName(), docType)) {
679
680
681 purchaseOrderService.createAndRoutePotentialChangeDocument(purchaseOrderDocument.getDocumentNumber(), docType, assemblePurchaseOrderNote(apDocument, docType, action), new ArrayList(), newStatus);
682 }
683
684
685
686
687
688 if (PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_CLOSE_DOCUMENT.equals(docType)) {
689 apDocument.setClosePurchaseOrderIndicator(false);
690
691
692 String userName = apDocument.getLastActionPerformedByPersonName();
693 StringBuffer poNote = new StringBuffer("");
694 poNote.append("PO was closed manually by ");
695 poNote.append(userName);
696 poNote.append(" in approving PREQ with ID ");
697 poNote.append(apDocument.getDocumentNumber());
698
699
700 try {
701 Note noteObj = documentService.createNoteFromDocument(apDocument.getPurchaseOrderDocument(), poNote.toString());
702 noteObj.setNoteTypeCode(apDocument.getPurchaseOrderDocument().getNoteType().getCode());
703 apDocument.getPurchaseOrderDocument().addNote(noteObj);
704 noteService.save(noteObj);
705 } catch (Exception e) {
706 String errorMessage = "Error creating and saving close note for purchase order with document service";
707 LOG.error("processCloseReopenPo() " + errorMessage, e);
708 throw new RuntimeException(errorMessage, e);
709 }
710 } else if (PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_REOPEN_DOCUMENT.equals(docType)) {
711 apDocument.setReopenPurchaseOrderIndicator(false);
712 }
713
714 }
715
716
717
718
719
720
721
722
723 protected String assemblePurchaseOrderNote(AccountsPayableDocumentBase apDocument, String docType, String action) {
724 LOG.debug("assemblePurchaseOrderNote() started");
725
726 String documentLabel = dataDictionaryService.getDocumentLabelByClass(apDocument.getClass());
727 StringBuffer closeReopenNote = new StringBuffer("");
728 String userName = GlobalVariables.getUserSession().getPerson().getName();
729 closeReopenNote.append(dataDictionaryService.getDocumentLabelByTypeName(OLEConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER));
730 closeReopenNote.append(" will be manually ");
731 closeReopenNote.append(action);
732 closeReopenNote.append(" by ");
733 closeReopenNote.append(userName);
734 closeReopenNote.append(" when approving ");
735 closeReopenNote.append(documentLabel);
736 closeReopenNote.append(" with ");
737 closeReopenNote.append(dataDictionaryService.getAttributeLabel(apDocument.getClass(), PurapPropertyConstants.PURAP_DOC_ID));
738 closeReopenNote.append(" ");
739 closeReopenNote.append(apDocument.getPurapDocumentIdentifier());
740
741 return closeReopenNote.toString();
742 }
743
744
745
746
747 @Override
748 public Object performLogicWithFakedUserSession(String requiredPersonPersonUserId, LogicContainer logicToRun, Object... objects) throws WorkflowException, Exception {
749 LOG.debug("performLogicWithFakedUserSession() started");
750
751 if (StringUtils.isBlank(requiredPersonPersonUserId)) {
752 throw new RuntimeException("Attempted to perform logic with a fake user session with a blank user person id: '" + requiredPersonPersonUserId + "'");
753 }
754 if (ObjectUtils.isNull(logicToRun)) {
755 throw new RuntimeException("Attempted to perform logic with a fake user session with no logic to run");
756 }
757 UserSession actualUserSession = GlobalVariables.getUserSession();
758 try {
759 GlobalVariables.setUserSession(new UserSession(requiredPersonPersonUserId));
760 return logicToRun.runLogic(objects);
761 } finally {
762 GlobalVariables.setUserSession(actualUserSession);
763 }
764 }
765
766
767
768
769 @Override
770 public void saveDocumentNoValidation(Document document) {
771 try {
772
773
774
775
776 if(document != null) {
777 if (document.getDocumentHeader() != null && document.getDocumentHeader().getDocumentNumber() == null) {
778 WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
779 document.refreshReferenceObject("documentHeader");
780 document.getDocumentHeader().setWorkflowDocument(workflowDocument);
781 }
782 documentService.saveDocument(document, DocumentSystemSaveEvent.class);
783
784
785
786
787 final DocumentAttributeIndexingQueue documentAttributeIndexingQueue = KewApiServiceLocator.getDocumentAttributeIndexingQueue();
788
789 documentAttributeIndexingQueue.indexDocument(document.getDocumentNumber());
790 }
791 } catch (WorkflowException we) {
792 String errorMsg = "Workflow error saving document # " + document.getDocumentHeader().getDocumentNumber() + " " + we.getMessage();
793 LOG.error(errorMsg, we);
794 throw new RuntimeException(errorMsg, we);
795 } catch (NumberFormatException ne) {
796 String errorMsg = "Invalid document number format for document # " + document.getDocumentHeader().getDocumentNumber() + " " + ne.getMessage();
797 LOG.error(errorMsg, ne);
798 throw new RuntimeException(errorMsg, ne);
799 }
800 }
801
802
803
804
805 @Override
806 public boolean isDocumentStoppedInRouteNode(PurchasingAccountsPayableDocument document, String nodeName) {
807 WorkflowDocument workflowDoc = document.getDocumentHeader().getWorkflowDocument();
808 Set<String> currentRouteLevels = workflowDoc.getCurrentNodeNames();
809 if (currentRouteLevels.contains(nodeName) && workflowDoc.isApprovalRequested()) {
810 return true;
811 }
812 return false;
813 }
814
815
816
817
818 @Override
819 public boolean allowEncumberNextFiscalYear() {
820 LOG.debug("allowEncumberNextFiscalYear() started");
821
822 java.util.Date today = dateTimeService.getCurrentDate();
823 java.util.Date closingDate = universityDateService.getLastDateOfFiscalYear(universityDateService.getCurrentFiscalYear());
824 int allowEncumberNext = (Integer.parseInt(parameterService.getParameterValueAsString(RequisitionDocument.class, PurapRuleConstants.ALLOW_ENCUMBER_NEXT_YEAR_DAYS)));
825 int diffTodayClosing = dateTimeService.dateDiff(today, closingDate, false);
826
827 if (ObjectUtils.isNotNull(closingDate) && ObjectUtils.isNotNull(today) && ObjectUtils.isNotNull(allowEncumberNext)) {
828 if (LOG.isDebugEnabled()) {
829 LOG.debug("allowEncumberNextFiscalYear() today = " + dateTimeService.toDateString(today) + "; encumber next FY range = " + allowEncumberNext + " - " + dateTimeService.toDateTimeString(today));
830 }
831
832 if (allowEncumberNext >= diffTodayClosing && diffTodayClosing >= KualiDecimal.ZERO.intValue()) {
833 LOG.debug("allowEncumberNextFiscalYear() encumber next FY allowed; return true.");
834 return true;
835 }
836 }
837 LOG.debug("allowEncumberNextFiscalYear() encumber next FY not allowed; return false.");
838 return false;
839 }
840
841
842
843
844 @Override
845 public List<Integer> getAllowedFiscalYears() {
846 List<Integer> allowedYears = new ArrayList<Integer>();
847 Integer currentFY = universityDateService.getCurrentFiscalYear();
848 allowedYears.add(currentFY);
849 if (allowEncumberNextFiscalYear()) {
850 allowedYears.add(currentFY + 1);
851 }
852 return allowedYears;
853 }
854
855
856
857
858 @Override
859 public boolean isTodayWithinApoAllowedRange() {
860 java.util.Date today = dateTimeService.getCurrentDate();
861 Integer currentFY = universityDateService.getCurrentFiscalYear();
862 java.util.Date closingDate = universityDateService.getLastDateOfFiscalYear(currentFY);
863 int allowApoDate = (Integer.parseInt(parameterService.getParameterValueAsString(RequisitionDocument.class, PurapRuleConstants.ALLOW_APO_NEXT_FY_DAYS)));
864 int diffTodayClosing = dateTimeService.dateDiff(today, closingDate, true);
865
866 return diffTodayClosing <= allowApoDate;
867 }
868
869
870
871
872 @Override
873 public void clearTax(PurchasingAccountsPayableDocument purapDocument, boolean useTax) {
874 for (PurApItem item : purapDocument.getItems()) {
875 if (useTax) {
876 item.getUseTaxItems().clear();
877 } else {
878 item.setItemTaxAmount(null);
879 }
880 }
881 }
882
883 @Override
884 public void updateUseTaxIndicator(PurchasingAccountsPayableDocument purapDocument, boolean newUseTaxIndicatorValue) {
885 boolean currentUseTaxIndicator = purapDocument.isUseTaxIndicator();
886 if (currentUseTaxIndicator != newUseTaxIndicatorValue) {
887
888 clearTax(purapDocument, currentUseTaxIndicator);
889 }
890 purapDocument.setUseTaxIndicator(newUseTaxIndicatorValue);
891 }
892
893
894
895
896 @Override
897 public void calculateTax(PurchasingAccountsPayableDocument purapDocument) {
898
899 boolean salesTaxInd = SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_SALES_TAX_IND);
900 boolean useTaxIndicator = purapDocument.isUseTaxIndicator();
901 String deliveryState = getDeliveryState(purapDocument);
902 String deliveryPostalCode = getDeliveryPostalCode(purapDocument);
903 Date transactionTaxDate = purapDocument.getTransactionTaxDate();
904
905
906 if (salesTaxInd || useTaxIndicator) {
907
908 for (PurApItem item : purapDocument.getItems()) {
909 if (isTaxable(useTaxIndicator, deliveryState, item)) {
910 calculateItemTax(useTaxIndicator, deliveryPostalCode, transactionTaxDate, item, item.getUseTaxClass(), purapDocument);
911 }
912 }
913 }
914 }
915
916 @Override
917 public String getDeliveryState(PurchasingAccountsPayableDocument purapDocument) {
918 if (purapDocument instanceof PurchasingDocument) {
919 PurchasingDocument document = (PurchasingDocument) purapDocument;
920 return document.getDeliveryStateCode();
921 } else if (purapDocument instanceof AccountsPayableDocument) {
922 AccountsPayableDocument document = (AccountsPayableDocument) purapDocument;
923 if (document.getPurchaseOrderDocument() == null) {
924 throw new RuntimeException("PurchaseOrder document does not exists");
925 }
926 return document.getPurchaseOrderDocument().getDeliveryStateCode();
927 }
928 return null;
929 }
930
931 protected String getDeliveryPostalCode(PurchasingAccountsPayableDocument purapDocument) {
932 if (purapDocument instanceof PurchasingDocument) {
933 PurchasingDocument document = (PurchasingDocument) purapDocument;
934 return document.getDeliveryPostalCode();
935 } else if (purapDocument instanceof AccountsPayableDocument) {
936 AccountsPayableDocument docBase = (AccountsPayableDocument) purapDocument;
937 if (docBase.getPurchaseOrderDocument() == null) {
938 throw new RuntimeException("PurchaseOrder document does not exists");
939 }
940 return docBase.getPurchaseOrderDocument().getDeliveryPostalCode();
941 }
942 return null;
943 }
944
945
946
947
948
949
950
951
952
953 @Override
954 public boolean isTaxable(boolean useTaxIndicator, String deliveryState, PurApItem item) {
955
956 boolean taxable = false;
957
958 if (item.getItemType().isTaxableIndicator() &&
959 ((ObjectUtils.isNull(item.getItemTaxAmount()) && useTaxIndicator == false) || useTaxIndicator) &&
960 (doesCommodityAllowCallToTaxService(item)) &&
961 (doesAccountAllowCallToTaxService(deliveryState, item))) {
962
963 taxable = true;
964 }
965 return taxable;
966 }
967
968
969
970
971 @Override
972 public boolean isTaxableForSummary(boolean useTaxIndicator, String deliveryState, PurApItem item) {
973
974 boolean taxable = false;
975
976 if (item.getItemType().isTaxableIndicator() &&
977 (doesCommodityAllowCallToTaxService(item)) &&
978 (doesAccountAllowCallToTaxService(deliveryState, item))) {
979
980 taxable = true;
981 }
982 return taxable;
983 }
984
985
986
987
988
989
990
991 protected boolean doesCommodityAllowCallToTaxService(PurApItem item) {
992 boolean callService = true;
993
994
995 if (item.getItemType().isLineItemIndicator()) {
996 if (item instanceof PurchasingItem) {
997 PurchasingItemBase purItem = (PurchasingItemBase) item;
998 callService = isCommodityCodeTaxable(purItem.getCommodityCode());
999 }
1000 else if (item instanceof AccountsPayableItem) {
1001 AccountsPayableItem apItem = (AccountsPayableItem) item;
1002 PurchaseOrderItem poItem = apItem.getPurchaseOrderItem();
1003 if (ObjectUtils.isNotNull(poItem)) {
1004 callService = isCommodityCodeTaxable(poItem.getCommodityCode());
1005 }
1006 }
1007 }
1008
1009 return callService;
1010 }
1011
1012 protected boolean isCommodityCodeTaxable(CommodityCode commodityCode) {
1013 boolean isTaxable = true;
1014
1015 if (ObjectUtils.isNotNull(commodityCode)) {
1016
1017 if (commodityCode.isSalesTaxIndicator() == false) {
1018
1019 isTaxable = false;
1020 }
1021
1022 }
1023
1024 return isTaxable;
1025 }
1026
1027
1028
1029
1030 @Override
1031 public boolean isDeliveryStateTaxable(String deliveryState) {
1032 ParameterEvaluator parmEval = SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.PURCHASING_DOCUMENT.class, TaxParameters.TAXABLE_DELIVERY_STATES, deliveryState);
1033 return parmEval.evaluationSucceeds();
1034 }
1035
1036
1037
1038
1039
1040
1041
1042
1043 protected boolean doesAccountAllowCallToTaxService(String deliveryState, PurApItem item) {
1044 boolean callService = false;
1045 boolean deliveryStateTaxable = isDeliveryStateTaxable(deliveryState);
1046
1047 for (PurApAccountingLine acctLine : item.getSourceAccountingLines()) {
1048 if (isAccountingLineTaxable(acctLine, deliveryStateTaxable)) {
1049 callService = true;
1050 break;
1051 }
1052 }
1053
1054 return callService;
1055 }
1056
1057
1058
1059
1060 @Override
1061 public boolean isAccountingLineTaxable(PurApAccountingLine acctLine, boolean deliveryStateTaxable) {
1062 boolean isTaxable = false;
1063 String parameterSuffix = null;
1064
1065 if (deliveryStateTaxable) {
1066 parameterSuffix = TaxParameters.FOR_TAXABLE_STATES_SUFFIX;
1067 } else {
1068 parameterSuffix = TaxParameters.FOR_NON_TAXABLE_STATES_SUFFIX;
1069 }
1070
1071
1072 if (isAccountTaxable(parameterSuffix, acctLine) && isObjectCodeTaxable(parameterSuffix, acctLine)) {
1073 isTaxable = true;
1074 }
1075
1076 return isTaxable;
1077 }
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087 protected boolean isAccountTaxable(String parameterSuffix, PurApAccountingLine acctLine) {
1088
1089 boolean isAccountTaxable = false;
1090 String fundParam = TaxParameters.TAXABLE_FUND_GROUPS_PREFIX + parameterSuffix;
1091 String subFundParam = TaxParameters.TAXABLE_SUB_FUND_GROUPS_PREFIX + parameterSuffix;
1092 ParameterEvaluator fundParamEval = null;
1093 ParameterEvaluator subFundParamEval = null;
1094
1095 if (ObjectUtils.isNull(acctLine.getAccount().getSubFundGroup())) {
1096 acctLine.refreshNonUpdateableReferences();
1097 }
1098
1099 fundParamEval = SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.PURCHASING_DOCUMENT.class, fundParam, acctLine.getAccount().getSubFundGroup().getFundGroupCode());
1100 subFundParamEval = SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.PURCHASING_DOCUMENT.class, subFundParam, acctLine.getAccount().getSubFundGroupCode());
1101
1102 if ((isAllowedFound(fundParamEval) && (isAllowedFound(subFundParamEval) || isAllowedNotFound(subFundParamEval) || isDeniedNotFound(subFundParamEval))) ||
1103 (isAllowedNotFound(fundParamEval) && isAllowedFound(subFundParamEval)) ||
1104 (isDeniedFound(fundParamEval) && isAllowedFound(subFundParamEval)) ||
1105 (isDeniedNotFound(fundParamEval) && (isAllowedFound(subFundParamEval) || isAllowedNotFound(subFundParamEval) || isDeniedNotFound(subFundParamEval)))) {
1106
1107 isAccountTaxable = true;
1108 }
1109
1110 return isAccountTaxable;
1111 }
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121 protected boolean isObjectCodeTaxable(String parameterSuffix, PurApAccountingLine acctLine) {
1122
1123 boolean isObjectCodeTaxable = false;
1124 String levelParam = TaxParameters.TAXABLE_OBJECT_LEVELS_PREFIX + parameterSuffix;
1125 String consolidationParam = TaxParameters.TAXABLE_OBJECT_CONSOLIDATIONS_PREFIX + parameterSuffix;
1126 ParameterEvaluator levelParamEval = null;
1127 ParameterEvaluator consolidationParamEval = null;
1128
1129
1130 acctLine.getObjectCode().refreshReferenceObject("financialObjectLevel");
1131
1132 levelParamEval = SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.PURCHASING_DOCUMENT.class, levelParam, acctLine.getObjectCode().getFinancialObjectLevelCode());
1133 consolidationParamEval = SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.PURCHASING_DOCUMENT.class, consolidationParam, acctLine.getObjectCode().getFinancialObjectLevel().getFinancialConsolidationObjectCode());
1134
1135 if ((isAllowedFound(levelParamEval) && (isAllowedFound(consolidationParamEval) || isAllowedNotFound(consolidationParamEval) || isDeniedNotFound(consolidationParamEval))) ||
1136 (isAllowedNotFound(levelParamEval) && isAllowedFound(consolidationParamEval)) ||
1137 (isDeniedFound(levelParamEval) && isAllowedFound(consolidationParamEval)) ||
1138 (isDeniedNotFound(levelParamEval) && (isAllowedFound(consolidationParamEval) || isAllowedNotFound(consolidationParamEval) || isDeniedNotFound(consolidationParamEval)))) {
1139
1140 isObjectCodeTaxable = true;
1141 }
1142
1143 return isObjectCodeTaxable;
1144 }
1145
1146
1147
1148
1149
1150
1151
1152 protected boolean isAllowedFound(ParameterEvaluator eval) {
1153 boolean exists = false;
1154
1155 if (eval.evaluationSucceeds() && eval.constraintIsAllow()) {
1156 exists = true;
1157 }
1158
1159 return exists;
1160 }
1161
1162
1163
1164
1165
1166
1167
1168 protected boolean isAllowedNotFound(ParameterEvaluator eval) {
1169 boolean exists = false;
1170
1171 if (eval.evaluationSucceeds() == false && eval.constraintIsAllow()) {
1172 exists = true;
1173 }
1174
1175 return exists;
1176 }
1177
1178
1179
1180
1181
1182
1183
1184 protected boolean isDeniedFound(ParameterEvaluator eval) {
1185 boolean exists = false;
1186
1187 if (eval.evaluationSucceeds() == false && eval.constraintIsAllow() == false) {
1188 exists = true;
1189 }
1190
1191 return exists;
1192 }
1193
1194
1195
1196
1197
1198
1199
1200 protected boolean isDeniedNotFound(ParameterEvaluator eval) {
1201 boolean exists = false;
1202
1203 if (eval.evaluationSucceeds() && eval.constraintIsAllow() == false) {
1204 exists = true;
1205 }
1206
1207 return exists;
1208 }
1209
1210
1211
1212
1213
1214
1215
1216
1217 @SuppressWarnings("unchecked")
1218 protected void calculateItemTax(boolean useTaxIndicator,
1219 String deliveryPostalCode,
1220 Date transactionTaxDate,
1221 PurApItem item,
1222 Class itemUseTaxClass,
1223 PurchasingAccountsPayableDocument purapDocument) {
1224
1225 if (!useTaxIndicator) {
1226 if (!StringUtils.equals(item.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE) &&
1227 !StringUtils.equals(item.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) {
1228 KualiDecimal taxAmount = taxService.getTotalSalesTaxAmount(transactionTaxDate, deliveryPostalCode, item.getExtendedPrice());
1229 item.setItemTaxAmount(taxAmount);
1230 }
1231 } else {
1232 KualiDecimal extendedPrice = item.getExtendedPrice();
1233
1234 if (StringUtils.equals(item.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) {
1235 KualiDecimal taxablePrice = getFullDiscountTaxablePrice(extendedPrice, purapDocument);
1236 extendedPrice = taxablePrice;
1237 }
1238 List<TaxDetail> taxDetails = taxService.getUseTaxDetails(transactionTaxDate, deliveryPostalCode, extendedPrice);
1239 List<PurApItemUseTax> newUseTaxItems = new ArrayList<PurApItemUseTax>();
1240 if (taxDetails != null) {
1241 for (TaxDetail taxDetail : taxDetails) {
1242 try {
1243 PurApItemUseTax useTaxitem = (PurApItemUseTax) itemUseTaxClass.newInstance();
1244 useTaxitem.setChartOfAccountsCode(taxDetail.getChartOfAccountsCode());
1245 useTaxitem.setFinancialObjectCode(taxDetail.getFinancialObjectCode());
1246 useTaxitem.setAccountNumber(taxDetail.getAccountNumber());
1247 useTaxitem.setItemIdentifier(item.getItemIdentifier());
1248 useTaxitem.setRateCode(taxDetail.getRateCode());
1249 useTaxitem.setTaxAmount(taxDetail.getTaxAmount());
1250 newUseTaxItems.add(useTaxitem);
1251 } catch (Exception e) {
1252
1253
1254
1255
1256 throw new RuntimeException(e);
1257 }
1258 }
1259 }
1260 item.setUseTaxItems(newUseTaxItems);
1261 }
1262 }
1263
1264 public KualiDecimal getFullDiscountTaxablePrice(KualiDecimal extendedPrice, PurchasingAccountsPayableDocument purapDocument) {
1265 KualiDecimal taxablePrice = KualiDecimal.ZERO;
1266 KualiDecimal taxableLineItemPrice = KualiDecimal.ZERO;
1267 KualiDecimal totalLineItemPrice = KualiDecimal.ZERO;
1268 boolean useTaxIndicator = purapDocument.isUseTaxIndicator();
1269 String deliveryState = getDeliveryState(purapDocument);
1270
1271
1272 for (PurApItem item : purapDocument.getItems()) {
1273 if (item.getItemType().isLineItemIndicator()) {
1274
1275 if (ObjectUtils.isNotNull(item.getExtendedPrice())) {
1276 if (isTaxable(useTaxIndicator, deliveryState, item)) {
1277 taxableLineItemPrice = taxableLineItemPrice.add(item.getExtendedPrice());
1278 totalLineItemPrice = totalLineItemPrice.add(item.getExtendedPrice());
1279 } else {
1280 totalLineItemPrice = totalLineItemPrice.add(item.getExtendedPrice());
1281 }
1282 }
1283 }
1284 }
1285
1286
1287 if (totalLineItemPrice.isNonZero() && ObjectUtils.isNotNull(extendedPrice)) {
1288 taxablePrice = taxableLineItemPrice.divide(totalLineItemPrice).multiply(extendedPrice);
1289 }
1290
1291 return taxablePrice;
1292 }
1293
1294 @Override
1295 public void prorateForTradeInAndFullOrderDiscount(PurchasingAccountsPayableDocument purDoc) {
1296
1297 if (purDoc instanceof VendorCreditMemoDocument) {
1298 throw new RuntimeException("This method not applicable for VCM documents");
1299 }
1300
1301
1302 PurApItem fullOrderDiscount = null;
1303 PurApItem tradeIn = null;
1304 KualiDecimal totalAmount = KualiDecimal.ZERO;
1305 KualiDecimal totalTaxAmount = KualiDecimal.ZERO;
1306
1307 List<PurApAccountingLine> distributedAccounts = null;
1308 List<SourceAccountingLine> summaryAccounts = null;
1309
1310
1311 for (PurApItem item : purDoc.getItems()) {
1312 if (item.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) {
1313 fullOrderDiscount = item;
1314 } else if (item.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE)) {
1315 tradeIn = item;
1316 }
1317 }
1318
1319 if (fullOrderDiscount != null &&
1320 fullOrderDiscount.getExtendedPrice() != null &&
1321 fullOrderDiscount.getExtendedPrice().isNonZero()) {
1322
1323
1324 KNSGlobalVariables.getMessageList().add("Full order discount accounts cleared and regenerated");
1325 fullOrderDiscount.getSourceAccountingLines().clear();
1326
1327 totalAmount = purDoc.getTotalDollarAmountAboveLineItems().subtract(purDoc.getTotalTaxAmountAboveLineItems());
1328 totalTaxAmount = purDoc.getTotalTaxAmountAboveLineItems();
1329
1330
1331 purapAccountingService.updateAccountAmounts(purDoc);
1332
1333
1334 boolean salesTaxInd = SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_SALES_TAX_IND);
1335 boolean useTaxIndicator = purDoc.isUseTaxIndicator();
1336
1337 if (salesTaxInd == true && (ObjectUtils.isNull(fullOrderDiscount.getItemTaxAmount()) && useTaxIndicator == false)) {
1338 KualiDecimal discountAmount = fullOrderDiscount.getExtendedPrice();
1339 KualiDecimal discountTaxAmount = discountAmount.divide(totalAmount).multiply(totalTaxAmount);
1340
1341 fullOrderDiscount.setItemTaxAmount(discountTaxAmount);
1342 }
1343
1344
1345 summaryAccounts = purapAccountingService.generateSummary(PurApItemUtils.getAboveTheLineOnly(purDoc.getItems()));
1346
1347 if (summaryAccounts.size() == 0) {
1348 if (purDoc.shouldGiveErrorForEmptyAccountsProration()) {
1349 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_SUMMARY_ACCOUNTS_LIST_EMPTY, "full order discount");
1350 }
1351 } else {
1352
1353 distributedAccounts = purapAccountingService.generateAccountDistributionForProration(summaryAccounts, totalAmount.add(totalTaxAmount), 2, fullOrderDiscount.getAccountingLineClass());
1354
1355 for (PurApAccountingLine distributedAccount : distributedAccounts) {
1356 BigDecimal percent = distributedAccount.getAccountLinePercent();
1357 BigDecimal roundedPercent = new BigDecimal(Math.round(percent.doubleValue()));
1358 distributedAccount.setAccountLinePercent(roundedPercent);
1359 }
1360
1361
1362 purapAccountingService.updateAccountAmountsWithTotal(distributedAccounts, totalAmount,
1363 fullOrderDiscount.getTotalAmount());
1364
1365 fullOrderDiscount.setSourceAccountingLines(distributedAccounts);
1366 }
1367 } else if (fullOrderDiscount != null &&
1368 (fullOrderDiscount.getExtendedPrice() == null || fullOrderDiscount.getExtendedPrice().isZero())) {
1369 fullOrderDiscount.getSourceAccountingLines().clear();
1370 }
1371
1372
1373 if (tradeIn != null && tradeIn.getExtendedPrice() != null && tradeIn.getExtendedPrice().isNonZero()) {
1374
1375 tradeIn.getSourceAccountingLines().clear();
1376
1377 totalAmount = purDoc.getTotalDollarAmountForTradeIn();
1378 KualiDecimal tradeInTotalAmount = tradeIn.getTotalAmount();
1379
1380 purapAccountingService.updateAccountAmounts(purDoc);
1381
1382
1383
1384 List<PurApItem> clonedTradeInItems = new ArrayList();
1385 Collection<String> objectSubTypesRequiringQty = SpringContext.getBean(ParameterService.class).getParameterValuesAsString(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.OBJECT_SUB_TYPES_REQUIRING_QUANTITY);
1386 Collection<String> purchasingObjectSubTypes = SpringContext.getBean(ParameterService.class).getParameterValuesAsString(OleParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, PurapParameterConstants.PURCHASING_OBJECT_SUB_TYPES);
1387
1388 String tradeInCapitalObjectCode = SpringContext.getBean(ParameterService.class).getParameterValueAsString(PurapConstants.PURAP_NAMESPACE, "Document", "TRADE_IN_OBJECT_CODE_FOR_CAPITAL_ASSET");
1389 String tradeInCapitalLeaseObjCd = SpringContext.getBean(ParameterService.class).getParameterValueAsString(PurapConstants.PURAP_NAMESPACE, "Document", "TRADE_IN_OBJECT_CODE_FOR_CAPITAL_LEASE");
1390
1391 for (PurApItem item : purDoc.getTradeInItems()) {
1392 PurApItem cloneItem = (PurApItem) ObjectUtils.deepCopy(item);
1393 List<PurApAccountingLine> sourceAccountingLines = cloneItem.getSourceAccountingLines();
1394 for (PurApAccountingLine accountingLine : sourceAccountingLines) {
1395 if (objectSubTypesRequiringQty.contains(accountingLine.getObjectCode().getFinancialObjectSubTypeCode())) {
1396 accountingLine.setFinancialObjectCode(tradeInCapitalObjectCode);
1397 } else if (purchasingObjectSubTypes.contains(accountingLine.getObjectCode().getFinancialObjectSubTypeCode())) {
1398 accountingLine.setFinancialObjectCode(tradeInCapitalLeaseObjCd);
1399 }
1400 }
1401 clonedTradeInItems.add(cloneItem);
1402 }
1403
1404
1405 summaryAccounts = purapAccountingService.generateSummary(clonedTradeInItems);
1406 if (summaryAccounts.size() == 0) {
1407 if (purDoc.shouldGiveErrorForEmptyAccountsProration()) {
1408 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_SUMMARY_ACCOUNTS_LIST_EMPTY, "trade in");
1409 }
1410 } else {
1411 distributedAccounts = purapAccountingService.generateAccountDistributionForProration(summaryAccounts, totalAmount, 2, tradeIn.getAccountingLineClass());
1412 for (PurApAccountingLine distributedAccount : distributedAccounts) {
1413 BigDecimal percent = distributedAccount.getAccountLinePercent();
1414 BigDecimal roundedPercent = new BigDecimal(Math.round(percent.doubleValue()));
1415 distributedAccount.setAccountLinePercent(roundedPercent);
1416
1417 resetAccountAmount(distributedAccount, tradeInTotalAmount);
1418 }
1419 tradeIn.setSourceAccountingLines(distributedAccounts);
1420 }
1421 }
1422 }
1423
1424 private void resetAccountAmount(PurApAccountingLine distributedAccount, KualiDecimal tradeInTotalAmount) {
1425 BigDecimal pct = distributedAccount.getAccountLinePercent();
1426 BigDecimal amount = tradeInTotalAmount.bigDecimalValue().multiply(pct).divide(new BigDecimal(100));
1427 distributedAccount.setAmount(new KualiDecimal(amount));
1428 }
1429
1430 @Override
1431 public void clearAllTaxes(PurchasingAccountsPayableDocument purapDoc) {
1432 if (purapDoc.getItems() != null) {
1433 for (int i = 0; i < purapDoc.getItems().size(); i++) {
1434 PurApItem item = purapDoc.getItems().get(i);
1435 if (purapDoc.isUseTaxIndicator()) {
1436 item.setUseTaxItems(new ArrayList<PurApItemUseTax>());
1437 } else {
1438 item.setItemTaxAmount(null);
1439 }
1440 }
1441 }
1442 }
1443
1444
1445
1446
1447
1448
1449
1450
1451 @Override
1452 public boolean isItemTypeConflictWithTaxPolicy(PurchasingDocument purchasingDocument, PurApItem item) {
1453 boolean conflict = false;
1454
1455 String deliveryState = getDeliveryState(purchasingDocument);
1456 if (item.getItemType().isLineItemIndicator()) {
1457 if (item.getItemType().isTaxableIndicator()) {
1458 if (isTaxDisabledForVendor(purchasingDocument)) {
1459 conflict = true;
1460 }
1461 }
1462
1463 if (!item.getSourceAccountingLines().isEmpty()) {
1464 if (!doesAccountAllowCallToTaxService(deliveryState, item)) {
1465 conflict = true;
1466 }
1467 }
1468 }
1469 return conflict;
1470 }
1471
1472
1473
1474
1475
1476
1477
1478 protected boolean isTaxDisabledForVendor(PurchasingDocument purapDocument) {
1479 return false;
1480 }
1481
1482 public PurapAccountingService getPurapAccountingService() {
1483 return purapAccountingService;
1484 }
1485
1486 public void setPurapAccountingService(PurapAccountingService purapAccountingService) {
1487 this.purapAccountingService = purapAccountingService;
1488 }
1489 }
1490