001/*
002 * Copyright 2007 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.ole.select.document.service.impl;
017
018import org.apache.commons.collections.CollectionUtils;
019import org.apache.commons.lang.StringUtils;
020import org.kuali.ole.module.purap.PurapConstants;
021import org.kuali.ole.module.purap.PurapParameterConstants;
022import org.kuali.ole.module.purap.businessobject.*;
023import org.kuali.ole.module.purap.document.PaymentRequestDocument;
024import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
025import org.kuali.ole.module.purap.document.VendorCreditMemoDocument;
026import org.kuali.ole.module.purap.document.service.AccountsPayableService;
027import org.kuali.ole.module.purap.document.service.PurapService;
028import org.kuali.ole.module.purap.document.service.impl.CreditMemoServiceImpl;
029import org.kuali.ole.module.purap.service.PurapAccountingService;
030import org.kuali.ole.module.purap.util.ExpiredOrClosedAccountEntry;
031import org.kuali.ole.select.businessobject.OleCreditMemoItem;
032import org.kuali.ole.select.businessobject.OleInvoiceItem;
033import org.kuali.ole.select.businessobject.OlePaymentRequestItem;
034import org.kuali.ole.select.businessobject.OlePurchaseOrderItem;
035import org.kuali.ole.select.document.OleInvoiceDocument;
036import org.kuali.ole.select.document.OlePaymentRequestDocument;
037import org.kuali.ole.select.document.OleVendorCreditMemoDocument;
038import org.kuali.ole.select.document.service.*;
039import org.kuali.ole.sys.OLEConstants;
040import org.kuali.ole.sys.OLEKeyConstants;
041import org.kuali.ole.sys.businessobject.SourceAccountingLine;
042import org.kuali.ole.vnd.VendorConstants;
043import org.kuali.ole.vnd.VendorUtils;
044import org.kuali.ole.vnd.businessobject.VendorAddress;
045import org.kuali.ole.vnd.businessobject.VendorDetail;
046import org.kuali.ole.vnd.document.service.VendorService;
047import org.kuali.rice.core.api.util.type.AbstractKualiDecimal;
048import org.kuali.rice.core.api.util.type.KualiDecimal;
049import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
050import org.kuali.rice.kew.api.exception.WorkflowException;
051import org.kuali.rice.krad.service.DocumentService;
052import org.kuali.rice.krad.util.GlobalVariables;
053import org.kuali.rice.krad.util.ObjectUtils;
054import org.springframework.transaction.annotation.Transactional;
055
056import java.math.BigDecimal;
057import java.math.RoundingMode;
058import java.util.ArrayList;
059import java.util.HashMap;
060import java.util.List;
061
062/**
063 * Provides services to support the creation of a Credit Memo Document.
064 */
065@Transactional
066public class OleCreditMemoServiceImpl extends CreditMemoServiceImpl implements OleCreditMemoService {
067    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(OleCreditMemoServiceImpl.class);
068
069    private PurapAccountingService purapAccountingService;
070    private PurapService purapService;
071    private OlePaymentRequestService olePaymentRequestService;
072    private VendorService vendorService;
073    private OlePurchaseOrderService olePurchaseOrderService;
074    private OleInvoiceService oleInvoiceService;
075    private AccountsPayableService accountsPayableService;
076    private DocumentService documentService;
077    private OlePurapAccountingService olePurapAccountingService;
078
079
080
081    public void setOlePurchaseOrderService(OlePurchaseOrderService olePurchaseOrderService) {
082        this.olePurchaseOrderService = olePurchaseOrderService;
083    }
084
085    @Override
086    public void setVendorService(VendorService vendorService) {
087        this.vendorService = vendorService;
088    }
089
090    public void setOlePaymentRequestService(OlePaymentRequestService olePaymentRequestService) {
091        this.olePaymentRequestService = olePaymentRequestService;
092    }
093
094    @Override
095    public void setPurapAccountingService(PurapAccountingService purapAccountingService) {
096        this.purapAccountingService = purapAccountingService;
097    }
098
099    @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}