View Javadoc
1   /*
2    * Copyright 2007 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.select.document.service.impl;
17  
18  import org.apache.commons.collections.CollectionUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.ole.module.purap.PurapConstants;
21  import org.kuali.ole.module.purap.PurapParameterConstants;
22  import org.kuali.ole.module.purap.businessobject.*;
23  import org.kuali.ole.module.purap.document.PaymentRequestDocument;
24  import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
25  import org.kuali.ole.module.purap.document.VendorCreditMemoDocument;
26  import org.kuali.ole.module.purap.document.service.AccountsPayableService;
27  import org.kuali.ole.module.purap.document.service.PurapService;
28  import org.kuali.ole.module.purap.document.service.impl.CreditMemoServiceImpl;
29  import org.kuali.ole.module.purap.service.PurapAccountingService;
30  import org.kuali.ole.module.purap.util.ExpiredOrClosedAccountEntry;
31  import org.kuali.ole.select.businessobject.OleCreditMemoItem;
32  import org.kuali.ole.select.businessobject.OleInvoiceItem;
33  import org.kuali.ole.select.businessobject.OlePaymentRequestItem;
34  import org.kuali.ole.select.businessobject.OlePurchaseOrderItem;
35  import org.kuali.ole.select.document.OleInvoiceDocument;
36  import org.kuali.ole.select.document.OlePaymentRequestDocument;
37  import org.kuali.ole.select.document.OleVendorCreditMemoDocument;
38  import org.kuali.ole.select.document.service.*;
39  import org.kuali.ole.sys.OLEConstants;
40  import org.kuali.ole.sys.OLEKeyConstants;
41  import org.kuali.ole.sys.businessobject.SourceAccountingLine;
42  import org.kuali.ole.vnd.VendorConstants;
43  import org.kuali.ole.vnd.VendorUtils;
44  import org.kuali.ole.vnd.businessobject.VendorAddress;
45  import org.kuali.ole.vnd.businessobject.VendorDetail;
46  import org.kuali.ole.vnd.document.service.VendorService;
47  import org.kuali.rice.core.api.util.type.AbstractKualiDecimal;
48  import org.kuali.rice.core.api.util.type.KualiDecimal;
49  import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
50  import org.kuali.rice.kew.api.exception.WorkflowException;
51  import org.kuali.rice.krad.service.DocumentService;
52  import org.kuali.rice.krad.util.GlobalVariables;
53  import org.kuali.rice.krad.util.ObjectUtils;
54  import org.springframework.transaction.annotation.Transactional;
55  
56  import java.math.BigDecimal;
57  import java.math.RoundingMode;
58  import java.util.ArrayList;
59  import java.util.HashMap;
60  import java.util.List;
61  
62  /**
63   * Provides services to support the creation of a Credit Memo Document.
64   */
65  @Transactional
66  public class OleCreditMemoServiceImpl extends CreditMemoServiceImpl implements OleCreditMemoService {
67      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(OleCreditMemoServiceImpl.class);
68  
69      private PurapAccountingService purapAccountingService;
70      private PurapService purapService;
71      private OlePaymentRequestService olePaymentRequestService;
72      private VendorService vendorService;
73      private OlePurchaseOrderService olePurchaseOrderService;
74      private OleInvoiceService oleInvoiceService;
75      private AccountsPayableService accountsPayableService;
76      private DocumentService documentService;
77      private OlePurapAccountingService olePurapAccountingService;
78  
79  
80  
81      public void setOlePurchaseOrderService(OlePurchaseOrderService olePurchaseOrderService) {
82          this.olePurchaseOrderService = olePurchaseOrderService;
83      }
84  
85      @Override
86      public void setVendorService(VendorService vendorService) {
87          this.vendorService = vendorService;
88      }
89  
90      public void setOlePaymentRequestService(OlePaymentRequestService olePaymentRequestService) {
91          this.olePaymentRequestService = olePaymentRequestService;
92      }
93  
94      @Override
95      public void setPurapAccountingService(PurapAccountingService purapAccountingService) {
96          this.purapAccountingService = purapAccountingService;
97      }
98  
99      @Override
100     public void setPurapService(PurapService purapService) {
101         this.purapService = purapService;
102     }
103 
104     public void setOleInvoiceService(OleInvoiceService oleInvoiceService) {
105         this.oleInvoiceService = oleInvoiceService;
106     }
107 
108     public void setAccountsPayableService(AccountsPayableService accountsPayableService) {
109         this.accountsPayableService = accountsPayableService;
110     }
111 
112     public void setDocumentService(DocumentService documentService) {
113         this.documentService = documentService;
114     }
115 
116     public void setOlePurapAccountingService(OlePurapAccountingService olePurapAccountingService) {
117         this.olePurapAccountingService = olePurapAccountingService;
118     }
119 
120     /**
121      * @see org.kuali.ole.module.purap.document.service.CreditMemoService# calculateCreditMemo(org.kuali.ole.module.purap.document.VendorCreditMemoDocument)
122      */
123     @Override
124     public void calculateCreditMemo(VendorCreditMemoDocument cmDocument) {
125         OleVendorCreditMemoDocument oleVendorCreditMemoDocument = (OleVendorCreditMemoDocument) cmDocument;
126         cmDocument.updateExtendedPriceOnItems();
127         KualiDecimal totalAmount = KualiDecimal.ZERO;
128         KualiDecimal totalQty = KualiDecimal.ZERO;
129         KualiDecimal totalSurcharge = KualiDecimal.ZERO;
130         List<PurApItem> items = new ArrayList<>();
131         //purapAccountingService.updateAccountAmounts(cmDocument);
132         for (OleCreditMemoItem item : (List<OleCreditMemoItem>) cmDocument.getItems()) {
133             // make sure restocking fee is negative
134             if (StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_RESTCK_FEE_CODE, item.getItemTypeCode())) {
135                 if (item.getItemUnitPrice() != null) {
136                     item.setExtendedPrice(item.getExtendedPrice().abs().negated());
137                     item.setItemUnitPrice(item.getItemUnitPrice().abs().negate());
138                 }
139             }
140             if (StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_MISC_CRDT_CODE, item.getItemTypeCode()) ||
141                     StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_RESTCK_FEE_CODE, item.getItemTypeCode()) ||
142                     StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_FREIGHT_CODE, item.getItemTypeCode()) ||
143                     StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_SHIP_AND_HAND_CODE, item.getItemTypeCode()) ||
144                     StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_MISC_CODE, item.getItemTypeCode()) ||
145                     StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_MIN_ORDER_CODE, item.getItemTypeCode())) {
146                 if (item.getItemUnitPrice() != null && ((OleVendorCreditMemoDocument)cmDocument).getInvoiceIdentifier() == null) {
147                     calculateProrateItemSurcharge((OleVendorCreditMemoDocument) cmDocument);
148                 }
149             }if(item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
150                 //     invoiceItem.setRelatedViews(null);
151                 if (item.getItemQuantity() != null) {
152                     totalQty = totalQty.add(item.getItemQuantity());
153                 }
154             }
155 
156             if (!(item.getItemType().isQuantityBasedGeneralLedgerIndicator()) && item.getExtendedPrice()!=null) {
157                 totalSurcharge = totalSurcharge.add(item.getExtendedPrice());
158             }
159             items.add(item);
160         }
161 
162         //calculate tax if cm not based on vendor
163         if (cmDocument.isSourceVendor() == false) {
164             purapService.calculateTax(cmDocument);
165         }
166 
167         // proration
168         if (cmDocument.isSourceVendor()) {
169             // no proration on vendor
170             return;
171         }
172 
173         oleVendorCreditMemoDocument.setProrateBy(oleVendorCreditMemoDocument.isProrateQty() ?
174                 OLEConstants.PRORATE_BY_QTY : oleVendorCreditMemoDocument.isProrateManual() ?
175                 OLEConstants.MANUAL_PRORATE : oleVendorCreditMemoDocument.isProrateDollar() ?
176                 OLEConstants.PRORATE_BY_DOLLAR : oleVendorCreditMemoDocument.isNoProrate() ?
177                 OLEConstants.NO_PRORATE : null);
178         for (OleCreditMemoItem item : (List<OleCreditMemoItem>) cmDocument.getItems()) {
179 
180             // skip above the line
181             if (item.getItemType().isLineItemIndicator()) {
182                 continue;
183             }
184             totalAmount = cmDocument.getTotalDollarAmountAboveLineItems();
185             totalAmount = totalAmount.subtract(totalSurcharge);
186             // purapAccountingService.updateAccountAmounts(invoiceDocument);
187 
188             if ((ObjectUtils.isNotNull(item.getExtendedPrice())) && (KualiDecimal.ZERO.compareTo(item.getExtendedPrice()) != 0)) {
189 
190                 List<PurApAccountingLine> distributedAccounts = null;
191                 List<SourceAccountingLine> summaryAccounts = null;
192 
193                 totalAmount = cmDocument.getLineItemTotal();
194                 // this should do nothing on preq which is fine
195                 if(oleVendorCreditMemoDocument.isProrateDollar() || oleVendorCreditMemoDocument.isProrateQty()){
196                     summaryAccounts = olePurapAccountingService.generateSummary(items);
197                 }
198                 if(oleVendorCreditMemoDocument.isProrateDollar()){
199                     distributedAccounts = olePurapAccountingService.generateAccountDistributionForProration(summaryAccounts, totalAmount, PurapConstants.PRORATION_SCALE, CreditMemoAccount.class);
200                 }else if(oleVendorCreditMemoDocument.isProrateQty()) {
201                     distributedAccounts = olePurapAccountingService.generateAccountDistributionForProrationByQty(summaryAccounts, totalQty, PurapConstants.PRORATION_SCALE, CreditMemoAccount.class);
202                 }
203 
204                 if (CollectionUtils.isNotEmpty(distributedAccounts) ) {
205                     item.setSourceAccountingLines(distributedAccounts);
206                 }
207             }
208             purapAccountingService.updateItemAccountAmounts(item);
209 
210         }
211         purapAccountingService.updateAccountAmounts(cmDocument);
212         // end proration          
213     }
214 
215 
216     public void calculateProrateItemSurcharge(OleVendorCreditMemoDocument vendorCreditMemoDocument) {
217         LOG.debug("Inside Calculation for ProrateItemSurcharge");
218         vendorCreditMemoDocument.setProrateBy(vendorCreditMemoDocument.isProrateQty() ? OLEConstants.PRORATE_BY_QTY :
219                 vendorCreditMemoDocument.isProrateManual() ? OLEConstants.MANUAL_PRORATE :
220                         vendorCreditMemoDocument.isProrateDollar() ? OLEConstants.PRORATE_BY_DOLLAR : vendorCreditMemoDocument.isNoProrate() ? OLEConstants.NO_PRORATE : null);
221         BigDecimal addChargeItem = BigDecimal.ZERO;
222         List<OleCreditMemoItem> item = (List<OleCreditMemoItem>) vendorCreditMemoDocument.getItems();
223         for (OleCreditMemoItem items : item) {
224             if (!items.getItemType().isQuantityBasedGeneralLedgerIndicator() && !items.getItemTypeCode().equalsIgnoreCase(PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE) && items.getItemUnitPrice() != null) {
225                 addChargeItem = addChargeItem.add(items.getItemUnitPrice());
226             }
227         }
228         List<BigDecimal> newUnitPriceList = new ArrayList<BigDecimal>();
229         BigDecimal totalExtPrice = new BigDecimal(0);
230         BigDecimal newUnitPrice = new BigDecimal(0);
231         BigDecimal extPrice = new BigDecimal(0);
232         BigDecimal unitPricePercent = new BigDecimal(0);
233         BigDecimal hundred = new BigDecimal(100);
234         BigDecimal one = new BigDecimal(1);
235         BigDecimal totalSurCharge = new BigDecimal(0);
236         BigDecimal totalItemQuantity = new BigDecimal(0);
237         BigDecimal itemSurchargeCons = new BigDecimal(0);
238         for (int i = 0; item.size() > i; i++) {
239             OleCreditMemoItem items = (OleCreditMemoItem) vendorCreditMemoDocument.getItem(i);
240             if ((items.getItemType().isQuantityBasedGeneralLedgerIndicator()) && !ObjectUtils.isNull(items.getItemQuantity())) {
241                 if (vendorCreditMemoDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
242                     totalItemQuantity = totalItemQuantity.add(items.getItemQuantity().bigDecimalValue());
243                 }
244                 if (vendorCreditMemoDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_DOLLAR) || vendorCreditMemoDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE) || vendorCreditMemoDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
245                     /*if (items.getItemDiscount() == null) {
246                         items.setItemDiscount(KualiDecimal.ZERO);
247                     }
248                     if (items.getItemDiscountType() != null && items.getItemDiscountType().equalsIgnoreCase(OleSelectConstant.DISCOUNT_TYPE_PERCENTAGE)) {
249                         newUnitPrice = (hundred.subtract(items.getItemDiscount().bigDecimalValue())).divide(hundred).multiply(items.getItemListPrice().bigDecimalValue());
250                     }
251                     else {
252                         newUnitPrice = items.getItemListPrice().bigDecimalValue().subtract(items.getItemDiscount().bigDecimalValue());
253                     }*/
254                     newUnitPrice = items.getItemUnitPrice();
255                     newUnitPriceList.add(newUnitPrice);
256                     extPrice = newUnitPrice.multiply(items.getItemQuantity().bigDecimalValue());
257                     totalExtPrice = totalExtPrice.add(extPrice);
258                 }
259                 if (vendorCreditMemoDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE)) {
260                     if (items.getItemSurcharge() == null) {
261                         items.setItemSurcharge(BigDecimal.ZERO);
262                     }
263                     totalSurCharge = totalSurCharge.add(items.getItemQuantity().bigDecimalValue().multiply(items.getItemSurcharge()));
264                 }
265             }
266 
267         }
268         if (vendorCreditMemoDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
269             if (totalItemQuantity.compareTo(BigDecimal.ZERO) != 0) {
270                 itemSurchargeCons = one.divide(totalItemQuantity, 8, RoundingMode.HALF_UP);
271             }
272         }
273         for (int i = 0, j = 0; item.size() > i; i++) {
274             OleCreditMemoItem items = (OleCreditMemoItem) vendorCreditMemoDocument.getItem(i);
275             if (items.getItemType().isQuantityBasedGeneralLedgerIndicator() && newUnitPriceList.size() > j && !ObjectUtils.isNull(items.getItemQuantity())) {
276                 if (vendorCreditMemoDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_DOLLAR)) {
277                     if (totalExtPrice.compareTo(BigDecimal.ZERO) != 0) {
278                         unitPricePercent = newUnitPriceList.get(j).divide(totalExtPrice, 8, RoundingMode.HALF_UP);
279                     }
280                     items.setItemSurcharge(unitPricePercent.multiply(addChargeItem).setScale(4, RoundingMode.HALF_UP));
281                     items.setExtendedPrice((new KualiDecimal((newUnitPriceList.get(j).add(items.getItemSurcharge()).toString()))).multiply(items.getItemQuantity()));
282                 }
283                 if (vendorCreditMemoDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
284                     items.setItemSurcharge(itemSurchargeCons.multiply(addChargeItem).setScale(4, RoundingMode.HALF_UP));
285                     items.setExtendedPrice(new KualiDecimal(((newUnitPriceList.get(j).add(items.getItemSurcharge()).toString()))).multiply(items.getItemQuantity()));
286                 }
287                 if (vendorCreditMemoDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE) && items.getItemSurcharge() != null) {
288                     items.setExtendedPrice(new KualiDecimal(((newUnitPriceList.get(j).add(items.getItemSurcharge()).toString()))).multiply(items.getItemQuantity()));
289                 }
290                 j++;
291             }
292         }
293         if (vendorCreditMemoDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE)) {
294             if (totalSurCharge.compareTo(addChargeItem) != 0) {
295                 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, OLEKeyConstants.ERROR_PAYMENT_REQUEST_TOTAL_MISMATCH);
296             }
297         }
298         LOG.debug("Leaving Calculation for ProrateItemSurcharge");
299     }
300 
301 
302     /**
303      * Populates the credit memo items from the payment request items.
304      *
305      * @param cmDocument - Credit Memo Document to Populate
306      */
307     @Override
308     protected void populateItemLinesFromPreq(VendorCreditMemoDocument cmDocument, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
309         OlePaymentRequestDocument preqDocument = (OlePaymentRequestDocument) cmDocument.getPaymentRequestDocument();
310 
311         for (OlePaymentRequestItem preqItemToTemplate : (List<OlePaymentRequestItem>) preqDocument.getItems()) {
312             if (preqItemToTemplate.getItemType().isLineItemIndicator() && ((preqItemToTemplate.getItemType().isQuantityBasedGeneralLedgerIndicator() && preqItemToTemplate.getItemQuantity().isNonZero())
313                     || (preqItemToTemplate.getItemType().isAmountBasedGeneralLedgerIndicator() && preqItemToTemplate.getTotalAmount().isNonZero()))) {
314                 cmDocument.getItems().add(new OleCreditMemoItem(cmDocument, preqItemToTemplate, (OlePurchaseOrderItem) preqItemToTemplate.getPurchaseOrderItem(), expiredOrClosedAccountList));
315             }
316         }
317 
318         // add below the line items
319         purapService.addBelowLineItems(cmDocument);
320 
321         cmDocument.fixItemReferences();
322     }
323 
324     /**
325      * Populate Credit Memo of type Payment Request.
326      *
327      * @param cmDocument - Credit Memo Document to Populate
328      */
329     @Override
330     protected void populateDocumentFromPreq(VendorCreditMemoDocument cmDocument, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
331         PaymentRequestDocument paymentRequestDocument = olePaymentRequestService.getPaymentRequestById(cmDocument.getPaymentRequestIdentifier());
332         cmDocument.getDocumentHeader().setOrganizationDocumentNumber(paymentRequestDocument.getDocumentHeader().getOrganizationDocumentNumber());
333         cmDocument.setPaymentRequestDocument(paymentRequestDocument);
334         cmDocument.setPurchaseOrderDocument(paymentRequestDocument.getPurchaseOrderDocument());
335         cmDocument.setUseTaxIndicator(paymentRequestDocument.isUseTaxIndicator());
336 
337         // credit memo address taken directly from payment request
338         cmDocument.setVendorHeaderGeneratedIdentifier(paymentRequestDocument.getVendorHeaderGeneratedIdentifier());
339         cmDocument.setVendorDetailAssignedIdentifier(paymentRequestDocument.getVendorDetailAssignedIdentifier());
340         cmDocument.setVendorAddressGeneratedIdentifier(paymentRequestDocument.getVendorAddressGeneratedIdentifier());
341         cmDocument.setVendorCustomerNumber(paymentRequestDocument.getVendorCustomerNumber());
342         cmDocument.setVendorName(paymentRequestDocument.getVendorName());
343         cmDocument.setVendorLine1Address(paymentRequestDocument.getVendorLine1Address());
344         cmDocument.setVendorLine2Address(paymentRequestDocument.getVendorLine2Address());
345         cmDocument.setVendorCityName(paymentRequestDocument.getVendorCityName());
346         cmDocument.setVendorStateCode(paymentRequestDocument.getVendorStateCode());
347         cmDocument.setVendorPostalCode(paymentRequestDocument.getVendorPostalCode());
348         cmDocument.setVendorCountryCode(paymentRequestDocument.getVendorCountryCode());
349         cmDocument.setVendorAttentionName(paymentRequestDocument.getVendorAttentionName());
350         cmDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(paymentRequestDocument.getAccountsPayablePurchasingDocumentLinkIdentifier());
351         cmDocument.setPaymentMethodId(paymentRequestDocument.getVendorDetail().getPaymentMethodId());
352         cmDocument.setPurchaseOrderTypeId(paymentRequestDocument.getPurchaseOrderTypeId());
353         // prep the item lines (also collect warnings for later display) this is only done on paymentRequest
354         purapAccountingService.convertMoneyToPercent(paymentRequestDocument);
355         populateItemLinesFromPreq(cmDocument, expiredOrClosedAccountList);
356     }
357 
358 
359     @Override
360     protected void populateDocumentFromPO(VendorCreditMemoDocument cmDocument, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
361         PurchaseOrderDocument purchaseOrderDocument = olePurchaseOrderService.getCurrentPurchaseOrder(cmDocument.getPurchaseOrderIdentifier());
362         cmDocument.setPurchaseOrderDocument(purchaseOrderDocument);
363         cmDocument.getDocumentHeader().setOrganizationDocumentNumber(purchaseOrderDocument.getDocumentHeader().getOrganizationDocumentNumber());
364         cmDocument.setUseTaxIndicator(cmDocument.isUseTaxIndicator());
365 
366         cmDocument.setVendorHeaderGeneratedIdentifier(purchaseOrderDocument.getVendorHeaderGeneratedIdentifier());
367         cmDocument.setVendorDetailAssignedIdentifier(purchaseOrderDocument.getVendorDetailAssignedIdentifier());
368         cmDocument.setVendorCustomerNumber(purchaseOrderDocument.getVendorCustomerNumber());
369         cmDocument.setVendorName(purchaseOrderDocument.getVendorName());
370         cmDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(purchaseOrderDocument.getAccountsPayablePurchasingDocumentLinkIdentifier());
371         cmDocument.setPaymentMethodId(purchaseOrderDocument.getVendorDetail().getPaymentMethodId());
372         cmDocument.setPurchaseOrderTypeId(purchaseOrderDocument.getPurchaseOrderTypeId());
373         // populate cm vendor address with the default remit address type for the vendor if found
374         String userCampus = GlobalVariables.getUserSession().getPerson().getCampusCode();
375         VendorAddress vendorAddress = vendorService.getVendorDefaultAddress(purchaseOrderDocument.getVendorHeaderGeneratedIdentifier(), purchaseOrderDocument.getVendorDetailAssignedIdentifier(), VendorConstants.AddressTypes.REMIT, userCampus);
376         if (vendorAddress != null) {
377             cmDocument.templateVendorAddress(vendorAddress);
378             cmDocument.setVendorAddressGeneratedIdentifier(vendorAddress.getVendorAddressGeneratedIdentifier());
379             cmDocument.setVendorAttentionName(StringUtils.defaultString(vendorAddress.getVendorAttentionName()));
380         } else {
381             // set address from PO
382             cmDocument.setVendorAddressGeneratedIdentifier(purchaseOrderDocument.getVendorAddressGeneratedIdentifier());
383             cmDocument.setVendorLine1Address(purchaseOrderDocument.getVendorLine1Address());
384             cmDocument.setVendorLine2Address(purchaseOrderDocument.getVendorLine2Address());
385             cmDocument.setVendorCityName(purchaseOrderDocument.getVendorCityName());
386             cmDocument.setVendorStateCode(purchaseOrderDocument.getVendorStateCode());
387             cmDocument.setVendorPostalCode(purchaseOrderDocument.getVendorPostalCode());
388             cmDocument.setVendorCountryCode(purchaseOrderDocument.getVendorCountryCode());
389 
390 
391             boolean blankAttentionLine = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(PurapConstants.PURAP_NAMESPACE, "Document", PurapParameterConstants.BLANK_ATTENTION_LINE_FOR_PO_TYPE_ADDRESS, false);
392             if (blankAttentionLine) {
393                 cmDocument.setVendorAttentionName(StringUtils.EMPTY);
394             } else {
395                 cmDocument.setVendorAttentionName(StringUtils.defaultString(purchaseOrderDocument.getVendorAttentionName()));
396             }
397         }
398 
399         populateItemLinesFromPO(cmDocument, expiredOrClosedAccountList);
400     }
401 
402     /**
403      * Populates the credit memo items from the payment request items.
404      *
405      * @param cmDocument - Credit Memo Document to Populate
406      */
407     @Override
408     protected void populateItemLinesFromPO(VendorCreditMemoDocument cmDocument, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
409         List<PurchaseOrderItem> invoicedItems = getPOInvoicedItems(cmDocument.getPurchaseOrderDocument());
410         for (PurchaseOrderItem poItem : invoicedItems) {
411             if ((poItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && poItem.getItemInvoicedTotalQuantity().isNonZero())
412                     || (poItem.getItemType().isAmountBasedGeneralLedgerIndicator() && poItem.getItemInvoicedTotalAmount().isNonZero())) {
413                 OleCreditMemoItem olecreditMemoItem = new OleCreditMemoItem(cmDocument, (OlePurchaseOrderItem) poItem, expiredOrClosedAccountList);
414                 cmDocument.getItems().add(olecreditMemoItem);
415                 PurchasingCapitalAssetItem purchasingCAMSItem = cmDocument.getPurchaseOrderDocument().getPurchasingCapitalAssetItemByItemIdentifier(poItem.getItemIdentifier());
416                 if (purchasingCAMSItem != null) {
417                     olecreditMemoItem.setCapitalAssetTransactionTypeCode(purchasingCAMSItem.getCapitalAssetTransactionTypeCode());
418                 }
419             }
420         }
421 
422         // add below the line items
423         purapService.addBelowLineItems(cmDocument);
424 
425         cmDocument.fixItemReferences();
426     }
427 
428     @Override
429     protected void populateDocumentFromVendor(VendorCreditMemoDocument cmDocument) {
430         Integer vendorHeaderId = VendorUtils.getVendorHeaderId(cmDocument.getVendorNumber());
431         Integer vendorDetailId = VendorUtils.getVendorDetailId(cmDocument.getVendorNumber());
432 
433         VendorDetail vendorDetail = vendorService.getVendorDetail(vendorHeaderId, vendorDetailId);
434         cmDocument.setVendorDetail(vendorDetail);
435 
436         cmDocument.setVendorHeaderGeneratedIdentifier(vendorDetail.getVendorHeaderGeneratedIdentifier());
437         cmDocument.setVendorDetailAssignedIdentifier(vendorDetail.getVendorDetailAssignedIdentifier());
438         cmDocument.setVendorCustomerNumber(vendorDetail.getVendorNumber());
439         cmDocument.setVendorName(vendorDetail.getVendorName());
440         cmDocument.setPaymentMethodId(vendorDetail.getPaymentMethodId());
441 
442         // credit memo type vendor uses the default remit type address for the vendor if found
443         String userCampus = GlobalVariables.getUserSession().getPerson().getCampusCode();
444         VendorAddress vendorAddress = vendorService.getVendorDefaultAddress(vendorHeaderId, vendorDetailId, VendorConstants.AddressTypes.REMIT, userCampus);
445         if (vendorAddress == null) {
446             // pick up the default vendor po address type
447             vendorAddress = vendorService.getVendorDefaultAddress(vendorHeaderId, vendorDetailId, VendorConstants.AddressTypes.PURCHASE_ORDER, userCampus);
448         }
449 
450         cmDocument.setVendorAddressGeneratedIdentifier(vendorAddress.getVendorAddressGeneratedIdentifier());
451         cmDocument.templateVendorAddress(vendorAddress);
452 
453         // add below the line items
454         purapService.addBelowLineItems(cmDocument);
455     }
456 
457     /**
458      * @see org.kuali.ole.module.purap.document.service.CreditMemoCreateService# populateDocumentAfterInit(org.kuali.ole.module.purap.document.CreditMemoDocument)
459      */
460     @Override
461     public void populateDocumentAfterInit(VendorCreditMemoDocument cmDocument) {
462 
463         OleVendorCreditMemoDocument vendorCreditMemoDocument = (OleVendorCreditMemoDocument) cmDocument;
464         // make a call to search for expired/closed accounts
465         HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList = accountsPayableService.getExpiredOrClosedAccountList(cmDocument);
466 
467         if (vendorCreditMemoDocument.isSourceDocumentPaymentRequest() && vendorCreditMemoDocument.getInvoiceIdentifier() == null) {
468             populateDocumentFromPreq(vendorCreditMemoDocument, expiredOrClosedAccountList);
469         } else if (vendorCreditMemoDocument.isSourceDocumentPurchaseOrder() && vendorCreditMemoDocument.getInvoiceIdentifier() == null) {
470             populateDocumentFromPO(vendorCreditMemoDocument, expiredOrClosedAccountList);
471         } else if (vendorCreditMemoDocument.getInvoiceIdentifier() != null) {
472             populateDocumentFromInvoice(vendorCreditMemoDocument, expiredOrClosedAccountList);
473         } else {
474             populateDocumentFromVendor(vendorCreditMemoDocument);
475         }
476 
477         populateDocumentDescription(vendorCreditMemoDocument);
478 
479         // write a note for expired/closed accounts if any exist and add a message stating there were expired/closed accounts at the
480         // top of the document
481         accountsPayableService.generateExpiredOrClosedAccountNote(cmDocument, expiredOrClosedAccountList);
482 
483         // set indicator so a message is displayed for accounts that were replaced due to expired/closed status
484         if (ObjectUtils.isNotNull(expiredOrClosedAccountList) && !expiredOrClosedAccountList.isEmpty()) {
485             cmDocument.setContinuationAccountIndicator(true);
486         }
487 
488     }
489 
490     @Override
491     public void populateDocumentFromInvoice(OleVendorCreditMemoDocument cmDocument, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
492         OleInvoiceDocument invoiceDocument = oleInvoiceService.getInvoiceDocumentById(cmDocument.getInvoiceIdentifier());
493         //cmDocument.setPurchaseOrderDocument();
494         cmDocument.getDocumentHeader().setOrganizationDocumentNumber(invoiceDocument.getDocumentHeader().getOrganizationDocumentNumber());
495         cmDocument.setUseTaxIndicator(cmDocument.isUseTaxIndicator());
496         cmDocument.setPaymentMethodId(invoiceDocument.getPaymentMethodId());
497         cmDocument.setOlePaymentMethod(invoiceDocument.getPaymentMethod());
498         cmDocument.setVendorHeaderGeneratedIdentifier(invoiceDocument.getVendorHeaderGeneratedIdentifier());
499         cmDocument.setVendorDetailAssignedIdentifier(invoiceDocument.getVendorDetailAssignedIdentifier());
500         cmDocument.setVendorCustomerNumber(invoiceDocument.getVendorCustomerNumber());
501         cmDocument.setVendorName(invoiceDocument.getVendorName());
502        // cmDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(invoiceDocument.getAccountsPayablePurchasingDocumentLinkIdentifier());
503         cmDocument.setPaymentMethodId(invoiceDocument.getPaymentMethodId());
504         cmDocument.setPurchaseOrderTypeId(invoiceDocument.getPurchaseOrderTypeId());
505         // populate cm vendor address with the default remit address type for the vendor if found
506         String userCampus = GlobalVariables.getUserSession().getPerson().getCampusCode();
507         VendorAddress vendorAddress = vendorService.getVendorDefaultAddress(invoiceDocument.getVendorHeaderGeneratedIdentifier(), invoiceDocument.getVendorDetailAssignedIdentifier(), VendorConstants.AddressTypes.REMIT, userCampus);
508         if (vendorAddress != null) {
509             cmDocument.templateVendorAddress(vendorAddress);
510             cmDocument.setVendorAddressGeneratedIdentifier(vendorAddress.getVendorAddressGeneratedIdentifier());
511             cmDocument.setVendorAttentionName(StringUtils.defaultString(vendorAddress.getVendorAttentionName()));
512         } else {
513             // set address from PO
514             cmDocument.setVendorAddressGeneratedIdentifier(invoiceDocument.getVendorAddressGeneratedIdentifier());
515             cmDocument.setVendorLine1Address(invoiceDocument.getVendorLine1Address());
516             cmDocument.setVendorLine2Address(invoiceDocument.getVendorLine2Address());
517             cmDocument.setVendorCityName(invoiceDocument.getVendorCityName());
518             cmDocument.setVendorStateCode(invoiceDocument.getVendorStateCode());
519             cmDocument.setVendorPostalCode(invoiceDocument.getVendorPostalCode());
520             cmDocument.setVendorCountryCode(invoiceDocument.getVendorCountryCode());
521 
522 
523             boolean blankAttentionLine = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(PurapConstants.PURAP_NAMESPACE, "Document", PurapParameterConstants.BLANK_ATTENTION_LINE_FOR_PO_TYPE_ADDRESS, false);
524             if (blankAttentionLine) {
525                 cmDocument.setVendorAttentionName(StringUtils.EMPTY);
526             } else {
527                 cmDocument.setVendorAttentionName(StringUtils.defaultString(invoiceDocument.getVendorAttentionName()));
528             }
529         }
530 
531         //populateItemLinesFromInvoice(invoiceDocument, cmDocument, expiredOrClosedAccountList);
532     }
533 
534 
535     /**
536      * Populates the credit memo items from the payment request items.
537      *
538      * @param cmDocument - Credit Memo Document to Populate
539      */
540     @Override
541     public void populateItemLinesFromInvoice(OleInvoiceDocument invoiceDocument, OleVendorCreditMemoDocument cmDocument,
542                                              HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
543 
544         List<OleInvoiceItem> invoicedItems = invoiceDocument.getItems();
545         for (OleInvoiceItem invoiceItem : invoicedItems) {
546             if (invoiceItem.getExtendedPrice().isLessThan(AbstractKualiDecimal.ZERO)) {
547                 /*invoiceItem.setItemListPrice(invoiceItem.getItemListPrice().abs());
548                 KualiDecimal listPrice = invoiceItem.getItemListPrice().abs();
549                 BigDecimal unitPrice = invoiceItem.getItemUnitPrice();
550                 BigDecimal itemSurcharge = invoiceItem.getItemSurcharge();
551                 invoiceItem.setItemListPrice(listPrice);
552                 invoiceItem.setItemUnitPrice(unitPrice.abs());
553                 if (invoiceItem.getItemUnitPrice() != null) {
554                     invoiceItem.setItemUnitPrice(invoiceItem.getItemUnitPrice().abs());
555                 }*/
556                 if (!invoiceItem.isDebitItem() && ((invoiceItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && invoiceItem.getItemQuantity().isNonZero())
557                         || (invoiceItem.getItemType().isAmountBasedGeneralLedgerIndicator() && invoiceItem.getTotalAmount().isNonZero()))) {
558                     OleCreditMemoItem olecreditMemoItem = new OleCreditMemoItem(invoiceItem, cmDocument, expiredOrClosedAccountList);
559                     cmDocument.getItems().add(olecreditMemoItem);
560                     PurchasingCapitalAssetItem purchasingCAMSItem = cmDocument.getPurchaseOrderDocument().getPurchasingCapitalAssetItemByItemIdentifier(invoiceItem.getItemIdentifier());
561                     if (purchasingCAMSItem != null) {
562                         olecreditMemoItem.setCapitalAssetTransactionTypeCode(purchasingCAMSItem.getCapitalAssetTransactionTypeCode());
563                     }
564                 }
565             }
566 
567         }
568 
569         // add below the line items
570         purapService.addBelowLineItems(cmDocument);
571 
572         cmDocument.fixItemReferences();
573     }
574 
575     /**
576      * NOTE: in the event of auto-approval failure, this method may throw a RuntimeException, indicating to Spring transactional
577      * management that the transaction should be rolled back.
578      *
579      * @see org.kuali.ole.select.document.service.OleCreditMemoService# autoApproveCreditMemo(org.kuali.ole.module.purap.document.PaymentRequestDocument,
580      *      org.kuali.rice.core.api.util.type.KualiDecimal)
581      */
582     @Override
583     public boolean autoApproveCreditMemo(OleVendorCreditMemoDocument creditMemoDoc) {
584         try {
585             // Much of the rice frameworks assumes that document instances that are saved via DocumentService.saveDocument are
586             // those
587             // that were dynamically created by PojoFormBase (i.e., the Document instance wasn't created from OJB). We need to
588             // make
589             // a deep copy and materialize collections to fulfill that assumption so that collection elements will delete
590             // properly
591 
592             // TODO: maybe rewriting PurapService.calculateItemTax could be rewritten so that the a deep copy doesn't need to be
593             // made
594             // by taking advantage of OJB's managed array lists
595             try {
596                 ObjectUtils.materializeUpdateableCollections(creditMemoDoc);
597                 for (OleCreditMemoItem item : (List<OleCreditMemoItem>) creditMemoDoc.getItems()) {
598                     ObjectUtils.materializeUpdateableCollections(item);
599                 }
600             } catch (Exception ex) {
601                 throw new RuntimeException(ex);
602             }
603             creditMemoDoc = (OleVendorCreditMemoDocument) ObjectUtils.deepCopy(creditMemoDoc);
604             //purapService.updateStatus(doc, PaymentRequestStatuses.AUTO_APPROVED);
605             creditMemoDoc.updateAndSaveAppDocStatus(PurapConstants.CreditMemoStatuses.APPDOC_COMPLETE);
606 
607             documentService.blanketApproveDocument(creditMemoDoc, "auto-approving: Total is below threshold.", null);
608         } catch (WorkflowException we) {
609             LOG.error("Exception encountered when approving document number " + creditMemoDoc.getDocumentNumber() + ".", we);
610             // throw a runtime exception up so that we can force a rollback
611             throw new RuntimeException("Exception encountered when approving document number " + creditMemoDoc.getDocumentNumber() + ".", we);
612         }
613         return true;
614     }
615 }