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.getDocumentHeader() != null && document.getDocumentHeader().getDocumentNumber() == null) {
777 WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
778 document.refreshReferenceObject("documentHeader");
779 document.getDocumentHeader().setWorkflowDocument(workflowDocument);
780 }
781 documentService.saveDocument(document, DocumentSystemSaveEvent.class);
782
783
784
785
786 final DocumentAttributeIndexingQueue documentAttributeIndexingQueue = KewApiServiceLocator.getDocumentAttributeIndexingQueue();
787
788 documentAttributeIndexingQueue.indexDocument(document.getDocumentNumber());
789 } catch (WorkflowException we) {
790 String errorMsg = "Workflow error saving document # " + document.getDocumentHeader().getDocumentNumber() + " " + we.getMessage();
791 LOG.error(errorMsg, we);
792 throw new RuntimeException(errorMsg, we);
793 } catch (NumberFormatException ne) {
794 String errorMsg = "Invalid document number format for document # " + document.getDocumentHeader().getDocumentNumber() + " " + ne.getMessage();
795 LOG.error(errorMsg, ne);
796 throw new RuntimeException(errorMsg, ne);
797 }
798 }
799
800
801
802
803 @Override
804 public boolean isDocumentStoppedInRouteNode(PurchasingAccountsPayableDocument document, String nodeName) {
805 WorkflowDocument workflowDoc = document.getDocumentHeader().getWorkflowDocument();
806 Set<String> currentRouteLevels = workflowDoc.getCurrentNodeNames();
807 if (currentRouteLevels.contains(nodeName) && workflowDoc.isApprovalRequested()) {
808 return true;
809 }
810 return false;
811 }
812
813
814
815
816 @Override
817 public boolean allowEncumberNextFiscalYear() {
818 LOG.debug("allowEncumberNextFiscalYear() started");
819
820 java.util.Date today = dateTimeService.getCurrentDate();
821 java.util.Date closingDate = universityDateService.getLastDateOfFiscalYear(universityDateService.getCurrentFiscalYear());
822 int allowEncumberNext = (Integer.parseInt(parameterService.getParameterValueAsString(RequisitionDocument.class, PurapRuleConstants.ALLOW_ENCUMBER_NEXT_YEAR_DAYS)));
823 int diffTodayClosing = dateTimeService.dateDiff(today, closingDate, false);
824
825 if (ObjectUtils.isNotNull(closingDate) && ObjectUtils.isNotNull(today) && ObjectUtils.isNotNull(allowEncumberNext)) {
826 if (LOG.isDebugEnabled()) {
827 LOG.debug("allowEncumberNextFiscalYear() today = " + dateTimeService.toDateString(today) + "; encumber next FY range = " + allowEncumberNext + " - " + dateTimeService.toDateTimeString(today));
828 }
829
830 if (allowEncumberNext >= diffTodayClosing && diffTodayClosing >= KualiDecimal.ZERO.intValue()) {
831 LOG.debug("allowEncumberNextFiscalYear() encumber next FY allowed; return true.");
832 return true;
833 }
834 }
835 LOG.debug("allowEncumberNextFiscalYear() encumber next FY not allowed; return false.");
836 return false;
837 }
838
839
840
841
842 @Override
843 public List<Integer> getAllowedFiscalYears() {
844 List<Integer> allowedYears = new ArrayList<Integer>();
845 Integer currentFY = universityDateService.getCurrentFiscalYear();
846 allowedYears.add(currentFY);
847 if (allowEncumberNextFiscalYear()) {
848 allowedYears.add(currentFY + 1);
849 }
850 return allowedYears;
851 }
852
853
854
855
856 @Override
857 public boolean isTodayWithinApoAllowedRange() {
858 java.util.Date today = dateTimeService.getCurrentDate();
859 Integer currentFY = universityDateService.getCurrentFiscalYear();
860 java.util.Date closingDate = universityDateService.getLastDateOfFiscalYear(currentFY);
861 int allowApoDate = (Integer.parseInt(parameterService.getParameterValueAsString(RequisitionDocument.class, PurapRuleConstants.ALLOW_APO_NEXT_FY_DAYS)));
862 int diffTodayClosing = dateTimeService.dateDiff(today, closingDate, true);
863
864 return diffTodayClosing <= allowApoDate;
865 }
866
867
868
869
870 @Override
871 public void clearTax(PurchasingAccountsPayableDocument purapDocument, boolean useTax) {
872 for (PurApItem item : purapDocument.getItems()) {
873 if (useTax) {
874 item.getUseTaxItems().clear();
875 } else {
876 item.setItemTaxAmount(null);
877 }
878 }
879 }
880
881 @Override
882 public void updateUseTaxIndicator(PurchasingAccountsPayableDocument purapDocument, boolean newUseTaxIndicatorValue) {
883 boolean currentUseTaxIndicator = purapDocument.isUseTaxIndicator();
884 if (currentUseTaxIndicator != newUseTaxIndicatorValue) {
885
886 clearTax(purapDocument, currentUseTaxIndicator);
887 }
888 purapDocument.setUseTaxIndicator(newUseTaxIndicatorValue);
889 }
890
891
892
893
894 @Override
895 public void calculateTax(PurchasingAccountsPayableDocument purapDocument) {
896
897 boolean salesTaxInd = SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_SALES_TAX_IND);
898 boolean useTaxIndicator = purapDocument.isUseTaxIndicator();
899 String deliveryState = getDeliveryState(purapDocument);
900 String deliveryPostalCode = getDeliveryPostalCode(purapDocument);
901 Date transactionTaxDate = purapDocument.getTransactionTaxDate();
902
903
904 if (salesTaxInd || useTaxIndicator) {
905
906 for (PurApItem item : purapDocument.getItems()) {
907 if (isTaxable(useTaxIndicator, deliveryState, item)) {
908 calculateItemTax(useTaxIndicator, deliveryPostalCode, transactionTaxDate, item, item.getUseTaxClass(), purapDocument);
909 }
910 }
911 }
912 }
913
914 @Override
915 public String getDeliveryState(PurchasingAccountsPayableDocument purapDocument) {
916 if (purapDocument instanceof PurchasingDocument) {
917 PurchasingDocument document = (PurchasingDocument) purapDocument;
918 return document.getDeliveryStateCode();
919 } else if (purapDocument instanceof AccountsPayableDocument) {
920 AccountsPayableDocument document = (AccountsPayableDocument) purapDocument;
921 if (document.getPurchaseOrderDocument() == null) {
922 throw new RuntimeException("PurchaseOrder document does not exists");
923 }
924 return document.getPurchaseOrderDocument().getDeliveryStateCode();
925 }
926 return null;
927 }
928
929 protected String getDeliveryPostalCode(PurchasingAccountsPayableDocument purapDocument) {
930 if (purapDocument instanceof PurchasingDocument) {
931 PurchasingDocument document = (PurchasingDocument) purapDocument;
932 return document.getDeliveryPostalCode();
933 } else if (purapDocument instanceof AccountsPayableDocument) {
934 AccountsPayableDocument docBase = (AccountsPayableDocument) purapDocument;
935 if (docBase.getPurchaseOrderDocument() == null) {
936 throw new RuntimeException("PurchaseOrder document does not exists");
937 }
938 return docBase.getPurchaseOrderDocument().getDeliveryPostalCode();
939 }
940 return null;
941 }
942
943
944
945
946
947
948
949
950
951 @Override
952 public boolean isTaxable(boolean useTaxIndicator, String deliveryState, PurApItem item) {
953
954 boolean taxable = false;
955
956 if (item.getItemType().isTaxableIndicator() &&
957 ((ObjectUtils.isNull(item.getItemTaxAmount()) && useTaxIndicator == false) || useTaxIndicator) &&
958 (doesCommodityAllowCallToTaxService(item)) &&
959 (doesAccountAllowCallToTaxService(deliveryState, item))) {
960
961 taxable = true;
962 }
963 return taxable;
964 }
965
966
967
968
969 @Override
970 public boolean isTaxableForSummary(boolean useTaxIndicator, String deliveryState, PurApItem item) {
971
972 boolean taxable = false;
973
974 if (item.getItemType().isTaxableIndicator() &&
975 (doesCommodityAllowCallToTaxService(item)) &&
976 (doesAccountAllowCallToTaxService(deliveryState, item))) {
977
978 taxable = true;
979 }
980 return taxable;
981 }
982
983
984
985
986
987
988
989 protected boolean doesCommodityAllowCallToTaxService(PurApItem item) {
990 boolean callService = true;
991
992
993 if (item.getItemType().isLineItemIndicator()) {
994 if (item instanceof PurchasingItem) {
995 PurchasingItemBase purItem = (PurchasingItemBase) item;
996 callService = isCommodityCodeTaxable(purItem.getCommodityCode());
997 }
998 else if (item instanceof AccountsPayableItem) {
999 AccountsPayableItem apItem = (AccountsPayableItem) item;
1000 PurchaseOrderItem poItem = apItem.getPurchaseOrderItem();
1001 if (ObjectUtils.isNotNull(poItem)) {
1002 callService = isCommodityCodeTaxable(poItem.getCommodityCode());
1003 }
1004 }
1005 }
1006
1007 return callService;
1008 }
1009
1010 protected boolean isCommodityCodeTaxable(CommodityCode commodityCode) {
1011 boolean isTaxable = true;
1012
1013 if (ObjectUtils.isNotNull(commodityCode)) {
1014
1015 if (commodityCode.isSalesTaxIndicator() == false) {
1016
1017 isTaxable = false;
1018 }
1019
1020 }
1021
1022 return isTaxable;
1023 }
1024
1025
1026
1027
1028 @Override
1029 public boolean isDeliveryStateTaxable(String deliveryState) {
1030 ParameterEvaluator parmEval = SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.PURCHASING_DOCUMENT.class, TaxParameters.TAXABLE_DELIVERY_STATES, deliveryState);
1031 return parmEval.evaluationSucceeds();
1032 }
1033
1034
1035
1036
1037
1038
1039
1040
1041 protected boolean doesAccountAllowCallToTaxService(String deliveryState, PurApItem item) {
1042 boolean callService = false;
1043 boolean deliveryStateTaxable = isDeliveryStateTaxable(deliveryState);
1044
1045 for (PurApAccountingLine acctLine : item.getSourceAccountingLines()) {
1046 if (isAccountingLineTaxable(acctLine, deliveryStateTaxable)) {
1047 callService = true;
1048 break;
1049 }
1050 }
1051
1052 return callService;
1053 }
1054
1055
1056
1057
1058 @Override
1059 public boolean isAccountingLineTaxable(PurApAccountingLine acctLine, boolean deliveryStateTaxable) {
1060 boolean isTaxable = false;
1061 String parameterSuffix = null;
1062
1063 if (deliveryStateTaxable) {
1064 parameterSuffix = TaxParameters.FOR_TAXABLE_STATES_SUFFIX;
1065 } else {
1066 parameterSuffix = TaxParameters.FOR_NON_TAXABLE_STATES_SUFFIX;
1067 }
1068
1069
1070 if (isAccountTaxable(parameterSuffix, acctLine) && isObjectCodeTaxable(parameterSuffix, acctLine)) {
1071 isTaxable = true;
1072 }
1073
1074 return isTaxable;
1075 }
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085 protected boolean isAccountTaxable(String parameterSuffix, PurApAccountingLine acctLine) {
1086
1087 boolean isAccountTaxable = false;
1088 String fundParam = TaxParameters.TAXABLE_FUND_GROUPS_PREFIX + parameterSuffix;
1089 String subFundParam = TaxParameters.TAXABLE_SUB_FUND_GROUPS_PREFIX + parameterSuffix;
1090 ParameterEvaluator fundParamEval = null;
1091 ParameterEvaluator subFundParamEval = null;
1092
1093 if (ObjectUtils.isNull(acctLine.getAccount().getSubFundGroup())) {
1094 acctLine.refreshNonUpdateableReferences();
1095 }
1096
1097 fundParamEval = SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.PURCHASING_DOCUMENT.class, fundParam, acctLine.getAccount().getSubFundGroup().getFundGroupCode());
1098 subFundParamEval = SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.PURCHASING_DOCUMENT.class, subFundParam, acctLine.getAccount().getSubFundGroupCode());
1099
1100 if ((isAllowedFound(fundParamEval) && (isAllowedFound(subFundParamEval) || isAllowedNotFound(subFundParamEval) || isDeniedNotFound(subFundParamEval))) ||
1101 (isAllowedNotFound(fundParamEval) && isAllowedFound(subFundParamEval)) ||
1102 (isDeniedFound(fundParamEval) && isAllowedFound(subFundParamEval)) ||
1103 (isDeniedNotFound(fundParamEval) && (isAllowedFound(subFundParamEval) || isAllowedNotFound(subFundParamEval) || isDeniedNotFound(subFundParamEval)))) {
1104
1105 isAccountTaxable = true;
1106 }
1107
1108 return isAccountTaxable;
1109 }
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119 protected boolean isObjectCodeTaxable(String parameterSuffix, PurApAccountingLine acctLine) {
1120
1121 boolean isObjectCodeTaxable = false;
1122 String levelParam = TaxParameters.TAXABLE_OBJECT_LEVELS_PREFIX + parameterSuffix;
1123 String consolidationParam = TaxParameters.TAXABLE_OBJECT_CONSOLIDATIONS_PREFIX + parameterSuffix;
1124 ParameterEvaluator levelParamEval = null;
1125 ParameterEvaluator consolidationParamEval = null;
1126
1127
1128 acctLine.getObjectCode().refreshReferenceObject("financialObjectLevel");
1129
1130 levelParamEval = SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.PURCHASING_DOCUMENT.class, levelParam, acctLine.getObjectCode().getFinancialObjectLevelCode());
1131 consolidationParamEval = SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.PURCHASING_DOCUMENT.class, consolidationParam, acctLine.getObjectCode().getFinancialObjectLevel().getFinancialConsolidationObjectCode());
1132
1133 if ((isAllowedFound(levelParamEval) && (isAllowedFound(consolidationParamEval) || isAllowedNotFound(consolidationParamEval) || isDeniedNotFound(consolidationParamEval))) ||
1134 (isAllowedNotFound(levelParamEval) && isAllowedFound(consolidationParamEval)) ||
1135 (isDeniedFound(levelParamEval) && isAllowedFound(consolidationParamEval)) ||
1136 (isDeniedNotFound(levelParamEval) && (isAllowedFound(consolidationParamEval) || isAllowedNotFound(consolidationParamEval) || isDeniedNotFound(consolidationParamEval)))) {
1137
1138 isObjectCodeTaxable = true;
1139 }
1140
1141 return isObjectCodeTaxable;
1142 }
1143
1144
1145
1146
1147
1148
1149
1150 protected boolean isAllowedFound(ParameterEvaluator eval) {
1151 boolean exists = false;
1152
1153 if (eval.evaluationSucceeds() && eval.constraintIsAllow()) {
1154 exists = true;
1155 }
1156
1157 return exists;
1158 }
1159
1160
1161
1162
1163
1164
1165
1166 protected boolean isAllowedNotFound(ParameterEvaluator eval) {
1167 boolean exists = false;
1168
1169 if (eval.evaluationSucceeds() == false && eval.constraintIsAllow()) {
1170 exists = true;
1171 }
1172
1173 return exists;
1174 }
1175
1176
1177
1178
1179
1180
1181
1182 protected boolean isDeniedFound(ParameterEvaluator eval) {
1183 boolean exists = false;
1184
1185 if (eval.evaluationSucceeds() == false && eval.constraintIsAllow() == false) {
1186 exists = true;
1187 }
1188
1189 return exists;
1190 }
1191
1192
1193
1194
1195
1196
1197
1198 protected boolean isDeniedNotFound(ParameterEvaluator eval) {
1199 boolean exists = false;
1200
1201 if (eval.evaluationSucceeds() && eval.constraintIsAllow() == false) {
1202 exists = true;
1203 }
1204
1205 return exists;
1206 }
1207
1208
1209
1210
1211
1212
1213
1214
1215 @SuppressWarnings("unchecked")
1216 protected void calculateItemTax(boolean useTaxIndicator,
1217 String deliveryPostalCode,
1218 Date transactionTaxDate,
1219 PurApItem item,
1220 Class itemUseTaxClass,
1221 PurchasingAccountsPayableDocument purapDocument) {
1222
1223 if (!useTaxIndicator) {
1224 if (!StringUtils.equals(item.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE) &&
1225 !StringUtils.equals(item.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) {
1226 KualiDecimal taxAmount = taxService.getTotalSalesTaxAmount(transactionTaxDate, deliveryPostalCode, item.getExtendedPrice());
1227 item.setItemTaxAmount(taxAmount);
1228 }
1229 } else {
1230 KualiDecimal extendedPrice = item.getExtendedPrice();
1231
1232 if (StringUtils.equals(item.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) {
1233 KualiDecimal taxablePrice = getFullDiscountTaxablePrice(extendedPrice, purapDocument);
1234 extendedPrice = taxablePrice;
1235 }
1236 List<TaxDetail> taxDetails = taxService.getUseTaxDetails(transactionTaxDate, deliveryPostalCode, extendedPrice);
1237 List<PurApItemUseTax> newUseTaxItems = new ArrayList<PurApItemUseTax>();
1238 if (taxDetails != null) {
1239 for (TaxDetail taxDetail : taxDetails) {
1240 try {
1241 PurApItemUseTax useTaxitem = (PurApItemUseTax) itemUseTaxClass.newInstance();
1242 useTaxitem.setChartOfAccountsCode(taxDetail.getChartOfAccountsCode());
1243 useTaxitem.setFinancialObjectCode(taxDetail.getFinancialObjectCode());
1244 useTaxitem.setAccountNumber(taxDetail.getAccountNumber());
1245 useTaxitem.setItemIdentifier(item.getItemIdentifier());
1246 useTaxitem.setRateCode(taxDetail.getRateCode());
1247 useTaxitem.setTaxAmount(taxDetail.getTaxAmount());
1248 newUseTaxItems.add(useTaxitem);
1249 } catch (Exception e) {
1250
1251
1252
1253
1254 throw new RuntimeException(e);
1255 }
1256 }
1257 }
1258 item.setUseTaxItems(newUseTaxItems);
1259 }
1260 }
1261
1262 public KualiDecimal getFullDiscountTaxablePrice(KualiDecimal extendedPrice, PurchasingAccountsPayableDocument purapDocument) {
1263 KualiDecimal taxablePrice = KualiDecimal.ZERO;
1264 KualiDecimal taxableLineItemPrice = KualiDecimal.ZERO;
1265 KualiDecimal totalLineItemPrice = KualiDecimal.ZERO;
1266 boolean useTaxIndicator = purapDocument.isUseTaxIndicator();
1267 String deliveryState = getDeliveryState(purapDocument);
1268
1269
1270 for (PurApItem item : purapDocument.getItems()) {
1271 if (item.getItemType().isLineItemIndicator()) {
1272
1273 if (ObjectUtils.isNotNull(item.getExtendedPrice())) {
1274 if (isTaxable(useTaxIndicator, deliveryState, item)) {
1275 taxableLineItemPrice = taxableLineItemPrice.add(item.getExtendedPrice());
1276 totalLineItemPrice = totalLineItemPrice.add(item.getExtendedPrice());
1277 } else {
1278 totalLineItemPrice = totalLineItemPrice.add(item.getExtendedPrice());
1279 }
1280 }
1281 }
1282 }
1283
1284
1285 if (totalLineItemPrice.isNonZero() && ObjectUtils.isNotNull(extendedPrice)) {
1286 taxablePrice = taxableLineItemPrice.divide(totalLineItemPrice).multiply(extendedPrice);
1287 }
1288
1289 return taxablePrice;
1290 }
1291
1292 @Override
1293 public void prorateForTradeInAndFullOrderDiscount(PurchasingAccountsPayableDocument purDoc) {
1294
1295 if (purDoc instanceof VendorCreditMemoDocument) {
1296 throw new RuntimeException("This method not applicable for VCM documents");
1297 }
1298
1299
1300 PurApItem fullOrderDiscount = null;
1301 PurApItem tradeIn = null;
1302 KualiDecimal totalAmount = KualiDecimal.ZERO;
1303 KualiDecimal totalTaxAmount = KualiDecimal.ZERO;
1304
1305 List<PurApAccountingLine> distributedAccounts = null;
1306 List<SourceAccountingLine> summaryAccounts = null;
1307
1308
1309 for (PurApItem item : purDoc.getItems()) {
1310 if (item.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) {
1311 fullOrderDiscount = item;
1312 } else if (item.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE)) {
1313 tradeIn = item;
1314 }
1315 }
1316
1317 if (fullOrderDiscount != null &&
1318 fullOrderDiscount.getExtendedPrice() != null &&
1319 fullOrderDiscount.getExtendedPrice().isNonZero()) {
1320
1321
1322 KNSGlobalVariables.getMessageList().add("Full order discount accounts cleared and regenerated");
1323 fullOrderDiscount.getSourceAccountingLines().clear();
1324
1325 totalAmount = purDoc.getTotalDollarAmountAboveLineItems().subtract(purDoc.getTotalTaxAmountAboveLineItems());
1326 totalTaxAmount = purDoc.getTotalTaxAmountAboveLineItems();
1327
1328
1329 purapAccountingService.updateAccountAmounts(purDoc);
1330
1331
1332 boolean salesTaxInd = SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_SALES_TAX_IND);
1333 boolean useTaxIndicator = purDoc.isUseTaxIndicator();
1334
1335 if (salesTaxInd == true && (ObjectUtils.isNull(fullOrderDiscount.getItemTaxAmount()) && useTaxIndicator == false)) {
1336 KualiDecimal discountAmount = fullOrderDiscount.getExtendedPrice();
1337 KualiDecimal discountTaxAmount = discountAmount.divide(totalAmount).multiply(totalTaxAmount);
1338
1339 fullOrderDiscount.setItemTaxAmount(discountTaxAmount);
1340 }
1341
1342
1343 summaryAccounts = purapAccountingService.generateSummary(PurApItemUtils.getAboveTheLineOnly(purDoc.getItems()));
1344
1345 if (summaryAccounts.size() == 0) {
1346 if (purDoc.shouldGiveErrorForEmptyAccountsProration()) {
1347 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_SUMMARY_ACCOUNTS_LIST_EMPTY, "full order discount");
1348 }
1349 } else {
1350
1351 distributedAccounts = purapAccountingService.generateAccountDistributionForProration(summaryAccounts, totalAmount.add(totalTaxAmount), 2, fullOrderDiscount.getAccountingLineClass());
1352
1353 for (PurApAccountingLine distributedAccount : distributedAccounts) {
1354 BigDecimal percent = distributedAccount.getAccountLinePercent();
1355 BigDecimal roundedPercent = new BigDecimal(Math.round(percent.doubleValue()));
1356 distributedAccount.setAccountLinePercent(roundedPercent);
1357 }
1358
1359
1360 purapAccountingService.updateAccountAmountsWithTotal(distributedAccounts, totalAmount,
1361 fullOrderDiscount.getTotalAmount());
1362
1363 fullOrderDiscount.setSourceAccountingLines(distributedAccounts);
1364 }
1365 } else if (fullOrderDiscount != null &&
1366 (fullOrderDiscount.getExtendedPrice() == null || fullOrderDiscount.getExtendedPrice().isZero())) {
1367 fullOrderDiscount.getSourceAccountingLines().clear();
1368 }
1369
1370
1371 if (tradeIn != null && tradeIn.getExtendedPrice() != null && tradeIn.getExtendedPrice().isNonZero()) {
1372
1373 tradeIn.getSourceAccountingLines().clear();
1374
1375 totalAmount = purDoc.getTotalDollarAmountForTradeIn();
1376 KualiDecimal tradeInTotalAmount = tradeIn.getTotalAmount();
1377
1378 purapAccountingService.updateAccountAmounts(purDoc);
1379
1380
1381
1382 List<PurApItem> clonedTradeInItems = new ArrayList();
1383 Collection<String> objectSubTypesRequiringQty = SpringContext.getBean(ParameterService.class).getParameterValuesAsString(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.OBJECT_SUB_TYPES_REQUIRING_QUANTITY);
1384 Collection<String> purchasingObjectSubTypes = SpringContext.getBean(ParameterService.class).getParameterValuesAsString(OleParameterConstants.CAPITAL_ASSET_BUILDER_DOCUMENT.class, PurapParameterConstants.PURCHASING_OBJECT_SUB_TYPES);
1385
1386 String tradeInCapitalObjectCode = SpringContext.getBean(ParameterService.class).getParameterValueAsString(PurapConstants.PURAP_NAMESPACE, "Document", "TRADE_IN_OBJECT_CODE_FOR_CAPITAL_ASSET");
1387 String tradeInCapitalLeaseObjCd = SpringContext.getBean(ParameterService.class).getParameterValueAsString(PurapConstants.PURAP_NAMESPACE, "Document", "TRADE_IN_OBJECT_CODE_FOR_CAPITAL_LEASE");
1388
1389 for (PurApItem item : purDoc.getTradeInItems()) {
1390 PurApItem cloneItem = (PurApItem) ObjectUtils.deepCopy(item);
1391 List<PurApAccountingLine> sourceAccountingLines = cloneItem.getSourceAccountingLines();
1392 for (PurApAccountingLine accountingLine : sourceAccountingLines) {
1393 if (objectSubTypesRequiringQty.contains(accountingLine.getObjectCode().getFinancialObjectSubTypeCode())) {
1394 accountingLine.setFinancialObjectCode(tradeInCapitalObjectCode);
1395 } else if (purchasingObjectSubTypes.contains(accountingLine.getObjectCode().getFinancialObjectSubTypeCode())) {
1396 accountingLine.setFinancialObjectCode(tradeInCapitalLeaseObjCd);
1397 }
1398 }
1399 clonedTradeInItems.add(cloneItem);
1400 }
1401
1402
1403 summaryAccounts = purapAccountingService.generateSummary(clonedTradeInItems);
1404 if (summaryAccounts.size() == 0) {
1405 if (purDoc.shouldGiveErrorForEmptyAccountsProration()) {
1406 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_SUMMARY_ACCOUNTS_LIST_EMPTY, "trade in");
1407 }
1408 } else {
1409 distributedAccounts = purapAccountingService.generateAccountDistributionForProration(summaryAccounts, totalAmount, 2, tradeIn.getAccountingLineClass());
1410 for (PurApAccountingLine distributedAccount : distributedAccounts) {
1411 BigDecimal percent = distributedAccount.getAccountLinePercent();
1412 BigDecimal roundedPercent = new BigDecimal(Math.round(percent.doubleValue()));
1413 distributedAccount.setAccountLinePercent(roundedPercent);
1414
1415 resetAccountAmount(distributedAccount, tradeInTotalAmount);
1416 }
1417 tradeIn.setSourceAccountingLines(distributedAccounts);
1418 }
1419 }
1420 }
1421
1422 private void resetAccountAmount(PurApAccountingLine distributedAccount, KualiDecimal tradeInTotalAmount) {
1423 BigDecimal pct = distributedAccount.getAccountLinePercent();
1424 BigDecimal amount = tradeInTotalAmount.bigDecimalValue().multiply(pct).divide(new BigDecimal(100));
1425 distributedAccount.setAmount(new KualiDecimal(amount));
1426 }
1427
1428 @Override
1429 public void clearAllTaxes(PurchasingAccountsPayableDocument purapDoc) {
1430 if (purapDoc.getItems() != null) {
1431 for (int i = 0; i < purapDoc.getItems().size(); i++) {
1432 PurApItem item = purapDoc.getItems().get(i);
1433 if (purapDoc.isUseTaxIndicator()) {
1434 item.setUseTaxItems(new ArrayList<PurApItemUseTax>());
1435 } else {
1436 item.setItemTaxAmount(null);
1437 }
1438 }
1439 }
1440 }
1441
1442
1443
1444
1445
1446
1447
1448
1449 @Override
1450 public boolean isItemTypeConflictWithTaxPolicy(PurchasingDocument purchasingDocument, PurApItem item) {
1451 boolean conflict = false;
1452
1453 String deliveryState = getDeliveryState(purchasingDocument);
1454 if (item.getItemType().isLineItemIndicator()) {
1455 if (item.getItemType().isTaxableIndicator()) {
1456 if (isTaxDisabledForVendor(purchasingDocument)) {
1457 conflict = true;
1458 }
1459 }
1460
1461 if (!item.getSourceAccountingLines().isEmpty()) {
1462 if (!doesAccountAllowCallToTaxService(deliveryState, item)) {
1463 conflict = true;
1464 }
1465 }
1466 }
1467 return conflict;
1468 }
1469
1470
1471
1472
1473
1474
1475
1476 protected boolean isTaxDisabledForVendor(PurchasingDocument purapDocument) {
1477 return false;
1478 }
1479
1480 public PurapAccountingService getPurapAccountingService() {
1481 return purapAccountingService;
1482 }
1483
1484 public void setPurapAccountingService(PurapAccountingService purapAccountingService) {
1485 this.purapAccountingService = purapAccountingService;
1486 }
1487 }
1488