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