001/*
002 * Copyright 2011 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
018
019import org.apache.commons.lang.StringUtils;
020import org.kuali.ole.module.purap.PurapConstants;
021import org.kuali.ole.module.purap.businessobject.*;
022import org.kuali.ole.module.purap.document.CorrectionReceivingDocument;
023import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
024import org.kuali.ole.module.purap.document.ReceivingDocument;
025import org.kuali.ole.module.purap.document.service.ReceivingService;
026import org.kuali.ole.module.purap.document.service.impl.ReceivingServiceImpl;
027import org.kuali.ole.select.businessobject.*;
028import org.kuali.ole.sys.OLEConstants;
029import org.kuali.ole.sys.context.SpringContext;
030import org.kuali.rice.core.api.util.type.KualiDecimal;
031import org.kuali.rice.kew.api.exception.WorkflowException;
032import org.kuali.rice.krad.bo.AdHocRoutePerson;
033import org.kuali.rice.krad.service.BusinessObjectService;
034import org.kuali.rice.krad.util.ObjectUtils;
035import org.springframework.transaction.annotation.Transactional;
036
037import java.util.ArrayList;
038import java.util.HashMap;
039import java.util.List;
040import java.util.Map;
041
042/**
043 * This class has implementation for ReceivingService with respect to OLE.
044 */
045
046@Transactional
047public class OleReceivingServiceImpl extends ReceivingServiceImpl implements ReceivingService {
048
049    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(OleReceivingServiceImpl.class);
050
051    /**
052     * This method is overridden to set total parts received and total parts damaged for
053     * a PurchaseOrderItem
054     *
055     * @param receivingDocument ReceivingDocument from which total parts received and damaged are to be set in PO
056     * @param poDoc             Purchase order document to set total parts received and damaged
057     * @return
058     * @see org.kuali.ole.module.purap.document.service.impl.ReceivingServiceImpl#updateReceivingTotalsOnPurchaseOrder(org.kuali.ole.module.purap.document.ReceivingDocument, org.kuali.ole.module.purap.document.PurchaseOrderDocument)
059     */
060    @Override
061    protected void updateReceivingTotalsOnPurchaseOrder(ReceivingDocument receivingDocument, PurchaseOrderDocument poDoc) {
062        LOG.debug("Inside updateReceivingTotalsOnPurchaseOrder of OleReceivingServiceImpl");
063        super.updateReceivingTotalsOnPurchaseOrder(receivingDocument, poDoc);
064        for (OleReceivingItem receivingItem : (List<OleReceivingItem>) receivingDocument.getItems()) {
065            ItemType itemType = receivingItem.getItemType();
066            if (!StringUtils.equalsIgnoreCase(itemType.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE)) {
067                //TODO: Chris - this method of getting the line out of po should be turned into a method that can get an item based on a combo or itemType and line
068                OlePurchaseOrderItem poItem = (OlePurchaseOrderItem) poDoc.getItemByLineNumber(receivingItem.getItemLineNumber());
069
070                if (ObjectUtils.isNotNull(poItem)) {
071                    KualiDecimal poItemPartsReceivedTotal = poItem.getItemReceivedTotalParts();
072
073                    KualiDecimal receivingItemPartsReceivedOriginal = receivingItem.getItemOriginalReceivedTotalParts();
074
075                    if (ObjectUtils.isNull(receivingItemPartsReceivedOriginal)) {
076                        receivingItemPartsReceivedOriginal = KualiDecimal.ZERO;
077                    }
078                    KualiDecimal receivingItemPartsReceived = receivingItem.getItemReceivedTotalParts();
079                    KualiDecimal receivingItemPartsTotalReceivedAdjusted = receivingItemPartsReceived.subtract(receivingItemPartsReceivedOriginal);
080
081                    if (ObjectUtils.isNull(poItemPartsReceivedTotal)) {
082                        poItemPartsReceivedTotal = KualiDecimal.ZERO;
083                    }
084                    KualiDecimal poItemPartsReceivedTotalAdjusted = poItemPartsReceivedTotal.add(receivingItemPartsTotalReceivedAdjusted);
085
086                    KualiDecimal receivingItemPartsReturnedOriginal = receivingItem.getItemOriginalReturnedTotalParts();
087                    if (ObjectUtils.isNull(receivingItemPartsReturnedOriginal)) {
088                        receivingItemPartsReturnedOriginal = KualiDecimal.ZERO;
089                    }
090
091                    KualiDecimal receivingItemPartsReturned = receivingItem.getItemReturnedTotalParts();
092                    if (ObjectUtils.isNull(receivingItemPartsReturned)) {
093                        receivingItemPartsReturned = KualiDecimal.ZERO;
094                    }
095
096                    KualiDecimal receivingItemPartsTotalReturnedAdjusted = receivingItemPartsReturned.subtract(receivingItemPartsReturnedOriginal);
097
098                    poItemPartsReceivedTotalAdjusted = poItemPartsReceivedTotalAdjusted.subtract(receivingItemPartsTotalReturnedAdjusted);
099
100                    poItem.setItemReceivedTotalParts(poItemPartsReceivedTotalAdjusted);
101
102                    KualiDecimal poPartsTotalDamaged = poItem.getItemDamagedTotalParts();
103                    if (ObjectUtils.isNull(poPartsTotalDamaged)) {
104                        poPartsTotalDamaged = KualiDecimal.ZERO;
105                    }
106
107                    KualiDecimal receivingItemPartsTotalDamagedOriginal = receivingItem.getItemOriginalDamagedTotalParts();
108                    if (ObjectUtils.isNull(receivingItemPartsTotalDamagedOriginal)) {
109                        receivingItemPartsTotalDamagedOriginal = KualiDecimal.ZERO;
110                    }
111
112                    KualiDecimal receivingItemPartsTotalDamaged = receivingItem.getItemDamagedTotalParts();
113                    if (ObjectUtils.isNull(receivingItemPartsTotalDamaged)) {
114                        receivingItemPartsTotalDamaged = KualiDecimal.ZERO;
115                    }
116
117                    KualiDecimal receivingItemPartsTotalDamagedAdjusted = receivingItemPartsTotalDamaged.subtract(receivingItemPartsTotalDamagedOriginal);
118
119                    poItem.setItemDamagedTotalParts(poPartsTotalDamaged.add(receivingItemPartsTotalDamagedAdjusted));
120                }
121            }
122        }
123        LOG.debug("Leaving updateReceivingTotalsOnPurchaseOrder of OleReceivingServiceImpl");
124    }
125
126    /**
127     * This method is overridden to set total parts receiving and damaged in OlePurchaseOrderItem from OleLineItemReceivingItem
128     *
129     * @param rlItem Receiving line item from which total damaged and received parts are to be set in PO
130     * @return
131     * @see org.kuali.ole.module.purap.document.service.impl.ReceivingServiceImpl#createPoItemFromReceivingLine(org.kuali.ole.module.purap.businessobject.LineItemReceivingItem)
132     */
133    @Override
134    protected PurchaseOrderItem createPoItemFromReceivingLine(LineItemReceivingItem rlItem) {
135        LOG.debug("Inside createPoItemFromReceivingLine of OleReceivingServiceImpl");
136        OlePurchaseOrderItem poi = (OlePurchaseOrderItem) super.createPoItemFromReceivingLine(rlItem);
137        OleLineItemReceivingItem oleRlItem = (OleLineItemReceivingItem) rlItem;
138        poi.setItemDamagedTotalParts(oleRlItem.getItemDamagedTotalParts());
139        poi.setItemReceivedTotalParts(oleRlItem.getItemReceivedTotalParts());
140        poi.setBibInfoBean(oleRlItem.getBibInfoBean());
141        poi.setItemTitleId(oleRlItem.getItemTitleId());
142        LOG.debug("Leaving createPoItemFromReceivingLine of OleReceivingServiceImpl");
143        return poi;
144    }
145
146
147    /**
148     * This method is overridden to disable notes on a document when quantity returned or damaged is entered.
149     *
150     * @param recDoc Receiving Document
151     * @return
152     * @see org.kuali.ole.module.purap.document.service.impl.ReceivingServiceImpl#createNoteForReturnedAndDamagedItems(org.kuali.ole.module.purap.document.ReceivingDocument)
153     */
154    @Override
155    public void createNoteForReturnedAndDamagedItems(ReceivingDocument recDoc) {
156
157    }
158
159    /**
160     * This method is overridden to include parts values in creating a list of fiscal officers for new unordered items added to a purchase order.
161     *
162     * @param recDoc ReceivingDocument
163     * @return Fiscal officer list to send notification
164     * @see org.kuali.ole.module.purap.document.service.impl.ReceivingServiceImpl#createFyiFiscalOfficerList(org.kuali.ole.module.purap.document.ReceivingDocument)
165     */
166    @Override
167    protected List<AdHocRoutePerson> createFyiFiscalOfficerList(ReceivingDocument recDoc) {
168        LOG.debug("Inside createFyiFiscalOfficerList of OleReceivingServiceImpl");
169        PurchaseOrderDocument po = recDoc.getPurchaseOrderDocument();
170        List<AdHocRoutePerson> adHocRoutePersons = new ArrayList<AdHocRoutePerson>();
171        Map fiscalOfficers = new HashMap();
172        AdHocRoutePerson adHocRoutePerson = null;
173
174        for (OleReceivingItem recItem : (List<OleReceivingItem>) recDoc.getItems()) {
175            //if this item has an item line number then it is coming from the po
176            if (ObjectUtils.isNotNull(recItem.getItemLineNumber())) {
177                OlePurchaseOrderItem poItem = (OlePurchaseOrderItem) po.getItemByLineNumber(recItem.getItemLineNumber());
178
179                if ((poItem.getItemQuantity().isLessThan(poItem.getItemReceivedTotalQuantity()) ||
180                        recItem.getItemDamagedTotalQuantity().isGreaterThan(KualiDecimal.ZERO))
181                        && (((poItem.getItemNoOfParts().kualiDecimalValue()).isLessThan(poItem.getItemReceivedTotalParts()))
182                        || recItem.getItemDamagedTotalParts().isGreaterThan(KualiDecimal.ZERO))) {
183
184                    // loop through accounts and pull off fiscal officer
185                    for (PurApAccountingLine account : poItem.getSourceAccountingLines()) {
186
187                        //check for dupes of fiscal officer
188                        if (fiscalOfficers.containsKey(account.getAccount().getAccountFiscalOfficerUser().getPrincipalName()) == false) {
189
190                            //add fiscal officer to list
191                            fiscalOfficers.put(account.getAccount().getAccountFiscalOfficerUser().getPrincipalName(), account.getAccount().getAccountFiscalOfficerUser().getPrincipalName());
192
193                            //create AdHocRoutePerson object and add to list
194                            adHocRoutePerson = new AdHocRoutePerson();
195                            adHocRoutePerson.setId(account.getAccount().getAccountFiscalOfficerUser().getPrincipalName());
196                            adHocRoutePerson.setActionRequested(OLEConstants.WORKFLOW_FYI_REQUEST);
197                            adHocRoutePersons.add(adHocRoutePerson);
198                        }
199                    }
200
201                }
202
203            }
204        }
205        LOG.debug("Leaving createFyiFiscalOfficerList of OleReceivingServiceImpl");
206        return adHocRoutePersons;
207    }
208
209    /**
210     * This method is overridden to change annotation to include Parts
211     *
212     * @see org.kuali.ole.module.purap.document.service.impl.ReceivingServiceImpl#sendFyiForItems(org.kuali.ole.module.purap.document.ReceivingDocument)
213     */
214    @Override
215    protected void sendFyiForItems(ReceivingDocument recDoc) {
216        LOG.debug("Inside sendFyiForItems of OleReceivingServiceImpl");
217        List<AdHocRoutePerson> fyiList = createFyiFiscalOfficerList(recDoc);
218        String annotation = "Notification of Item exceeded Quantity/Parts or Damaged" + "(document id " + recDoc.getDocumentNumber() + ")";
219        String responsibilityNote = "Please Review";
220
221        for (AdHocRoutePerson adHocPerson : fyiList) {
222            try {
223                recDoc.appSpecificRouteDocumentToUser(
224                        recDoc.getDocumentHeader().getWorkflowDocument(),
225                        adHocPerson.getId(),
226                        annotation,
227                        responsibilityNote);
228            } catch (WorkflowException e) {
229                throw new RuntimeException("Error routing fyi for document with id " + recDoc.getDocumentNumber(), e);
230            }
231
232        }
233        LOG.debug("Leaving sendFyiForItems of OleReceivingServiceImpl");
234    }
235
236    /**
237     * This method deletes unneeded items and updates the totals on the po and does any additional processing based on items i.e.
238     * FYI etc
239     *
240     * @param receivingDocument receiving document
241     */
242    @Override
243    public void completeCorrectionReceivingDocument(ReceivingDocument correctionDocument) {
244        ReceivingDocument receivingDoc = ((CorrectionReceivingDocument) correctionDocument)
245                .getLineItemReceivingDocument();
246
247        if (correctionDocument.getItems().size() >= 1) {
248            for (OleCorrectionReceivingItem correctionItem : (List<OleCorrectionReceivingItem>) correctionDocument.getItems()) {
249                if (!StringUtils.equalsIgnoreCase(correctionItem.getItemType().getItemTypeCode(),
250                        PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE)) {
251                    int itemNumber = correctionItem.getItemLineNumber().intValue();
252                    OleLineItemReceivingItem recItem = (OleLineItemReceivingItem) receivingDoc.getItem(correctionItem
253                            .getItemLineNumber().intValue() - itemNumber);
254                    List<PurchaseOrderItem> purchaseOrderItems = receivingDoc.getPurchaseOrderDocument().getItems();
255                    PurchaseOrderItem poItem = purchaseOrderItems.get(correctionItem.getItemLineNumber().intValue()
256                            - itemNumber);
257
258                    if (ObjectUtils.isNotNull(recItem)) {
259                        recItem.setItemReceivedTotalQuantity(correctionItem.getItemReceivedTotalQuantity());
260                        recItem.setItemReceivedTotalParts(correctionItem.getItemReceivedTotalParts());
261                        recItem.setItemReturnedTotalQuantity(correctionItem.getItemReturnedTotalQuantity());
262                        recItem.setItemReturnedTotalParts(correctionItem.getItemReturnedTotalParts());
263                        recItem.setItemDamagedTotalQuantity(correctionItem.getItemDamagedTotalQuantity());
264                        recItem.setItemDamagedTotalParts(correctionItem.getItemDamagedTotalParts());
265                        updateReceivingItemReceiptStatus(recItem, correctionItem);
266                    }
267                }
268            }
269
270
271        } else {
272            for (CorrectionReceivingItem correctionItem : (List<CorrectionReceivingItem>) correctionDocument.getItems()) {
273                if (!StringUtils.equalsIgnoreCase(correctionItem.getItemType().getItemTypeCode(),
274                        PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE)) {
275                    LineItemReceivingItem recItem = (LineItemReceivingItem) receivingDoc.getItem(correctionItem
276                            .getItemLineNumber().intValue() - 1);
277                    List<PurchaseOrderItem> purchaseOrderItems = receivingDoc.getPurchaseOrderDocument().getItems();
278                    PurchaseOrderItem poItem = purchaseOrderItems
279                            .get(correctionItem.getItemLineNumber().intValue() - 1);
280
281                    if (ObjectUtils.isNotNull(recItem)) {
282                        recItem.setItemReceivedTotalQuantity(correctionItem.getItemReceivedTotalQuantity());
283                        recItem.setItemReturnedTotalQuantity(correctionItem.getItemReturnedTotalQuantity());
284                        recItem.setItemDamagedTotalQuantity(correctionItem.getItemDamagedTotalQuantity());
285                    }
286                }
287            }
288        }
289    }
290
291    public void updateReceivingItemReceiptStatus(OleLineItemReceivingItem recItem,
292                                                 OleCorrectionReceivingItem correctionItem) {
293
294        int finalCopiesReceived = (correctionItem.getItemReceivedTotalQuantity().subtract(
295                correctionItem.getItemReturnedTotalQuantity()).intValue());
296        int finalPartsReceived = (correctionItem.getItemReceivedTotalParts().subtract(
297                correctionItem.getItemReturnedTotalParts()).intValue());
298        if (correctionItem.getItemOriginalReceivedTotalQuantity().intValue() == finalCopiesReceived
299                && correctionItem.getItemOriginalReceivedTotalParts().intValue() == finalPartsReceived) {
300            recItem.setReceiptStatusId(getReceiptStatusDetails(OLEConstants.RCV_RECEIPT_STATUS_RCVD));
301        } else {
302            if (finalCopiesReceived == 0 && finalCopiesReceived == 0) {
303                recItem.setReceiptStatusId(getReceiptStatusDetails(OLEConstants.RCV_RECEIPT_STATUS_NONE));
304            } else {
305                recItem.setReceiptStatusId(getReceiptStatusDetails(OLEConstants.RCV_RECEIPT_STATUS_EXPTD));
306            }
307        }
308    }
309
310    public int getReceiptStatusDetails(String receiptStatusCd) {
311        int receiptStatusId = 0;
312        Map<String, String> receiptStatusCdMap = new HashMap<String, String>();
313        receiptStatusCdMap.put(OLEConstants.RCPT_STATUS_CD, receiptStatusCd);
314        List<OleReceiptStatus> oleReceiptStatusList = (List) SpringContext.getBean(BusinessObjectService.class)
315                .findMatching(OleReceiptStatus.class, receiptStatusCdMap);
316        for (OleReceiptStatus oleReceiptStatus : oleReceiptStatusList) {
317            receiptStatusId = oleReceiptStatus.getReceiptStatusId().intValue();
318        }
319        return receiptStatusId;
320    }
321
322}
323