View Javadoc
1   /*
2    * Copyright 2008 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.module.purap.document.service.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.joda.time.DateTime;
20  import org.kuali.ole.module.purap.PurapConstants;
21  import org.kuali.ole.module.purap.PurapConstants.PurchaseOrderDocTypes;
22  import org.kuali.ole.module.purap.PurapConstants.PurchaseOrderStatuses;
23  import org.kuali.ole.module.purap.PurapKeyConstants;
24  import org.kuali.ole.module.purap.PurapParameterConstants;
25  import org.kuali.ole.module.purap.businessobject.*;
26  import org.kuali.ole.module.purap.document.*;
27  import org.kuali.ole.module.purap.document.dataaccess.ReceivingDao;
28  import org.kuali.ole.module.purap.document.service.LogicContainer;
29  import org.kuali.ole.module.purap.document.service.PurapService;
30  import org.kuali.ole.module.purap.document.service.PurchaseOrderService;
31  import org.kuali.ole.module.purap.document.service.ReceivingService;
32  import org.kuali.ole.module.purap.document.validation.event.AttributedContinuePurapEvent;
33  import org.kuali.ole.select.businessobject.*;
34  import org.kuali.ole.sys.OLEConstants;
35  import org.kuali.ole.sys.context.SpringContext;
36  import org.kuali.ole.sys.service.GeneralLedgerPendingEntryService;
37  import org.kuali.rice.core.api.config.property.ConfigurationService;
38  import org.kuali.rice.core.api.util.type.KualiDecimal;
39  import org.kuali.rice.core.api.util.type.KualiInteger;
40  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
41  import org.kuali.rice.kew.api.KewApiServiceLocator;
42  import org.kuali.rice.kew.api.WorkflowDocument;
43  import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
44  import org.kuali.rice.kew.api.document.search.DocumentSearchResult;
45  import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
46  import org.kuali.rice.kew.api.exception.WorkflowException;
47  import org.kuali.rice.krad.bo.AdHocRoutePerson;
48  import org.kuali.rice.krad.bo.Note;
49  import org.kuali.rice.krad.document.Document;
50  import org.kuali.rice.krad.service.BusinessObjectService;
51  import org.kuali.rice.krad.service.DocumentService;
52  import org.kuali.rice.krad.service.NoteService;
53  import org.kuali.rice.krad.util.GlobalVariables;
54  import org.kuali.rice.krad.util.ObjectUtils;
55  import org.kuali.rice.krad.workflow.service.WorkflowDocumentService;
56  import org.springframework.transaction.annotation.Transactional;
57  
58  import java.math.BigDecimal;
59  import java.text.MessageFormat;
60  import java.util.ArrayList;
61  import java.util.HashMap;
62  import java.util.List;
63  import java.util.Map;
64  
65  @Transactional
66  public class ReceivingServiceImpl implements ReceivingService {
67      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ReceivingServiceImpl.class);
68  
69      protected PurchaseOrderService purchaseOrderService;
70      protected ReceivingDao receivingDao;
71      protected DocumentService documentService;
72      protected WorkflowDocumentService workflowDocumentService;
73      protected ConfigurationService configurationService;
74      protected PurapService purapService;
75      protected NoteService noteService;
76  
77      public void setPurchaseOrderService(PurchaseOrderService purchaseOrderService) {
78          this.purchaseOrderService = purchaseOrderService;
79      }
80  
81      public void setReceivingDao(ReceivingDao receivingDao) {
82          this.receivingDao = receivingDao;
83      }
84  
85      public void setDocumentService(DocumentService documentService) {
86          this.documentService = documentService;
87      }
88  
89      public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) {
90          this.workflowDocumentService = workflowDocumentService;
91      }
92  
93      public void setConfigurationService(ConfigurationService configurationService) {
94          this.configurationService = configurationService;
95      }
96  
97      public void setPurapService(PurapService purapService) {
98          this.purapService = purapService;
99      }
100 
101     public void setNoteService(NoteService noteService) {
102         this.noteService = noteService;
103     }
104 
105     /**
106      * @see org.kuali.ole.module.purap.document.service.ReceivingService#populateReceivingLineFromPurchaseOrder(org.kuali.ole.module.purap.document.LineItemReceivingDocument)
107      */
108     @Override
109     public void populateReceivingLineFromPurchaseOrder(LineItemReceivingDocument rlDoc) {
110 
111         if (rlDoc == null) {
112             rlDoc = new LineItemReceivingDocument();
113         }
114 
115         //retrieve po by doc id
116         PurchaseOrderDocument poDoc = null;
117         poDoc = purchaseOrderService.getCurrentPurchaseOrder(rlDoc.getPurchaseOrderIdentifier());
118 
119         if (poDoc != null) {
120             rlDoc.populateReceivingLineFromPurchaseOrder(poDoc);
121         }
122 
123     }
124 
125     @Override
126     public void populateCorrectionReceivingFromReceivingLine(CorrectionReceivingDocument rcDoc) {
127 
128         if (rcDoc == null) {
129             rcDoc = new CorrectionReceivingDocument();
130         }
131 
132         //retrieve receiving line by doc id
133         LineItemReceivingDocument rlDoc = rcDoc.getLineItemReceivingDocument();
134 
135         if (rlDoc != null) {
136             rcDoc.populateCorrectionReceivingFromReceivingLine(rlDoc);
137         }
138 
139     }
140 
141     /**
142      * @see org.kuali.ole.module.purap.document.service.ReceivingService#populateAndSaveLineItemReceivingDocument(org.kuali.ole.module.purap.document.LineItemReceivingDocument)
143      */
144     @Override
145     public void populateAndSaveLineItemReceivingDocument(LineItemReceivingDocument rlDoc) throws WorkflowException {
146         try {
147             documentService.saveDocument(rlDoc, AttributedContinuePurapEvent.class);
148         } catch (WorkflowException we) {
149             String errorMsg = "Error saving document # " + rlDoc.getDocumentHeader().getDocumentNumber() + " " + we.getMessage();
150             //LOG.error(errorMsg, we);
151             throw new RuntimeException(errorMsg, we);
152         }
153     }
154 
155     /**
156      * @see org.kuali.ole.module.purap.document.service.ReceivingService#populateCorrectionReceivingDocument(org.kuali.ole.module.purap.document.CorrectionReceivingDocument)
157      */
158     @Override
159     public void populateCorrectionReceivingDocument(CorrectionReceivingDocument rcDoc) {
160         populateCorrectionReceivingFromReceivingLine(rcDoc);
161     }
162 
163     /**
164      * @see org.kuali.ole.module.purap.document.service.ReceivingService#canCreateLineItemReceivingDocument(java.lang.Integer, java.lang.String)
165      */
166     @Override
167     public boolean canCreateLineItemReceivingDocument(Integer poId, String receivingDocumentNumber) throws RuntimeException {
168 
169         PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(poId);
170 
171         return canCreateLineItemReceivingDocument(po, receivingDocumentNumber);
172     }
173 
174     /**
175      * @see org.kuali.ole.module.purap.document.service.ReceivingService#canCreateLineItemReceivingDocument(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
176      */
177     @Override
178     public boolean canCreateLineItemReceivingDocument(PurchaseOrderDocument po) throws RuntimeException {
179         return canCreateLineItemReceivingDocument(po, null);
180     }
181 
182     protected boolean canCreateLineItemReceivingDocument(PurchaseOrderDocument po, String receivingDocumentNumber) {
183         boolean canCreate = false;
184 
185         if (isPurchaseOrderValidForLineItemReceivingDocumentCreation(po) &&
186                 !isLineItemReceivingDocumentInProcessForPurchaseOrder(po.getPurapDocumentIdentifier(), receivingDocumentNumber) &&
187                 !isCorrectionReceivingDocumentInProcessForPurchaseOrder(po.getPurapDocumentIdentifier(), null)) {
188             canCreate = true;
189         }
190 
191         return canCreate;
192     }
193 
194     @Override
195     public boolean isPurchaseOrderActiveForLineItemReceivingDocumentCreation(Integer poId) {
196         PurchaseOrderDocument po = purchaseOrderService.getCurrentPurchaseOrder(poId);
197         return isPurchaseOrderValidForLineItemReceivingDocumentCreation(po);
198     }
199 
200     protected boolean isPurchaseOrderValidForLineItemReceivingDocumentCreation(PurchaseOrderDocument po) {
201         return po != null &&
202                 ObjectUtils.isNotNull(po.getPurapDocumentIdentifier()) &&
203                 po.isPurchaseOrderCurrentIndicator() &&
204                 (PurchaseOrderStatuses.APPDOC_OPEN.equals(po.getApplicationDocumentStatus()) ||
205                         PurchaseOrderStatuses.APPDOC_CLOSED.equals(po.getApplicationDocumentStatus()) ||
206                         PurchaseOrderStatuses.APPDOC_PAYMENT_HOLD.equals(po.getApplicationDocumentStatus()));
207     }
208 
209     @Override
210     public boolean canCreateCorrectionReceivingDocument(LineItemReceivingDocument rl) throws RuntimeException {
211         return canCreateCorrectionReceivingDocument(rl, null);
212     }
213 
214     @Override
215     public boolean canCreateCorrectionReceivingDocument(LineItemReceivingDocument rl, String receivingCorrectionDocNumber) throws RuntimeException {
216 
217         boolean canCreate = false;
218         WorkflowDocument workflowDocument = null;
219 
220         try {
221             workflowDocument = workflowDocumentService.loadWorkflowDocument(rl.getDocumentNumber(), GlobalVariables.getUserSession().getPerson());
222         } catch (WorkflowException we) {
223             throw new RuntimeException(we);
224         }
225 
226         if (workflowDocument.isFinal() &&
227                 !isCorrectionReceivingDocumentInProcessForReceivingLine(rl.getDocumentNumber(), receivingCorrectionDocNumber)) {
228             canCreate = true;
229         }
230 
231         return canCreate;
232     }
233 
234     protected boolean isLineItemReceivingDocumentInProcessForPurchaseOrder(Integer poId, String receivingDocumentNumber) throws RuntimeException {
235         return !getLineItemReceivingDocumentNumbersInProcessForPurchaseOrder(poId, receivingDocumentNumber).isEmpty();
236     }
237 
238     @Override
239     public List<String> getLineItemReceivingDocumentNumbersInProcessForPurchaseOrder(Integer poId,
240                                                                                      String receivingDocumentNumber) {
241 
242         List<String> inProcessDocNumbers = new ArrayList<String>();
243         List<String> docNumbers = receivingDao.getDocumentNumbersByPurchaseOrderId(poId);
244         WorkflowDocument workflowDocument = null;
245 
246         for (String docNumber : docNumbers) {
247 
248             try {
249                 workflowDocument = workflowDocumentService.loadWorkflowDocument(docNumber, GlobalVariables.getUserSession().getPerson());
250             } catch (WorkflowException we) {
251                 throw new RuntimeException(we);
252             }
253 
254             if (!(workflowDocument.isCanceled() ||
255                     workflowDocument.isException() ||
256                     workflowDocument.isFinal()) &&
257                     docNumber.equals(receivingDocumentNumber) == false) {
258                 inProcessDocNumbers.add(docNumber);
259             }
260         }
261 
262         return inProcessDocNumbers;
263     }
264 
265     @Override
266     public List<LineItemReceivingDocument> getLineItemReceivingDocumentsInFinalForPurchaseOrder(Integer poId) {
267 
268         List<String> finalDocNumbers = new ArrayList<String>();
269         List<String> docNumbers = receivingDao.getDocumentNumbersByPurchaseOrderId(poId);
270         WorkflowDocument workflowDocument = null;
271 
272         for (String docNumber : docNumbers) {
273 
274             try {
275                 workflowDocument = workflowDocumentService.loadWorkflowDocument(docNumber, GlobalVariables.getUserSession().getPerson());
276             } catch (WorkflowException we) {
277                 throw new RuntimeException(we);
278             }
279 
280             if (workflowDocument.isFinal()) {
281                 finalDocNumbers.add(docNumber);
282             }
283         }
284 
285         if (finalDocNumbers.size() > 0) {
286             try {
287                 List<LineItemReceivingDocument> docs = new ArrayList<LineItemReceivingDocument>();
288                 for (Document doc : documentService.getDocumentsByListOfDocumentHeaderIds(LineItemReceivingDocument.class, finalDocNumbers)) {
289                     docs.add((LineItemReceivingDocument) doc);
290                 }
291                 return docs;
292             } catch (WorkflowException e) {
293                 throw new IllegalArgumentException("unable to retrieve LineItemReceivingDocuments", e);
294             }
295         } else {
296             return null;
297         }
298 
299     }
300 
301     protected boolean isCorrectionReceivingDocumentInProcessForPurchaseOrder(Integer poId, String receivingDocumentNumber) throws RuntimeException {
302         return !getCorrectionReceivingDocumentNumbersInProcessForPurchaseOrder(poId, receivingDocumentNumber).isEmpty();
303     }
304 
305     @Override
306     public List<String> getCorrectionReceivingDocumentNumbersInProcessForPurchaseOrder(Integer poId,
307                                                                                        String receivingDocumentNumber) {
308 
309         boolean isInProcess = false;
310 
311         List<String> inProcessDocNumbers = new ArrayList<String>();
312         List<String> docNumbers = receivingDao.getCorrectionReceivingDocumentNumbersByPurchaseOrderId(poId);
313         WorkflowDocument workflowDocument = null;
314 
315         for (String docNumber : docNumbers) {
316 
317             try {
318                 workflowDocument = workflowDocumentService.loadWorkflowDocument(docNumber, GlobalVariables.getUserSession().getPerson());
319             } catch (WorkflowException we) {
320                 throw new RuntimeException(we);
321             }
322 
323             if (!(workflowDocument.isCanceled() ||
324                     workflowDocument.isException() ||
325                     workflowDocument.isFinal()) &&
326                     docNumber.equals(receivingDocumentNumber) == false) {
327                 inProcessDocNumbers.add(docNumber);
328             }
329         }
330 
331         return inProcessDocNumbers;
332     }
333 
334 
335     protected boolean isCorrectionReceivingDocumentInProcessForReceivingLine(String receivingDocumentNumber, String receivingCorrectionDocNumber) throws RuntimeException {
336 
337         boolean isInProcess = false;
338 
339         List<String> docNumbers = receivingDao.getCorrectionReceivingDocumentNumbersByReceivingLineNumber(receivingDocumentNumber);
340         WorkflowDocument workflowDocument = null;
341 
342         for (String docNumber : docNumbers) {
343 
344             try {
345                 workflowDocument = workflowDocumentService.loadWorkflowDocument(docNumber, GlobalVariables.getUserSession().getPerson());
346             } catch (WorkflowException we) {
347                 throw new RuntimeException(we);
348             }
349 
350             if (!(workflowDocument.isCanceled() ||
351                     workflowDocument.isException() ||
352                     workflowDocument.isFinal()) &&
353                     docNumber.equals(receivingCorrectionDocNumber) == false) {
354 
355                 isInProcess = true;
356                 break;
357             }
358         }
359 
360         return isInProcess;
361     }
362 
363     /**
364      * @see org.kuali.ole.module.purap.document.service.ReceivingService#receivingLineDuplicateMessages(org.kuali.ole.module.purap.document.LineItemReceivingDocument)
365      */
366     @Override
367     public HashMap<String, String> receivingLineDuplicateMessages(LineItemReceivingDocument rlDoc) {
368         HashMap<String, String> msgs;
369         msgs = new HashMap<String, String>();
370         Integer poId = rlDoc.getPurchaseOrderIdentifier();
371         StringBuffer currentMessage = new StringBuffer("");
372         List<String> docNumbers = null;
373 
374         //check vendor date for duplicates
375         if (rlDoc.getShipmentReceivedDate() != null) {
376             docNumbers = receivingDao.duplicateVendorDate(poId, rlDoc.getShipmentReceivedDate());
377             if (hasDuplicateEntry(docNumbers)) {
378                 appendDuplicateMessage(currentMessage, PurapKeyConstants.MESSAGE_DUPLICATE_RECEIVING_LINE_VENDOR_DATE, rlDoc.getPurchaseOrderIdentifier());
379             }
380         }
381 
382         //check packing slip number for duplicates
383         if (!StringUtils.isEmpty(rlDoc.getShipmentPackingSlipNumber())) {
384             docNumbers = receivingDao.duplicatePackingSlipNumber(poId, rlDoc.getShipmentPackingSlipNumber());
385             if (hasDuplicateEntry(docNumbers)) {
386                 appendDuplicateMessage(currentMessage, PurapKeyConstants.MESSAGE_DUPLICATE_RECEIVING_LINE_PACKING_SLIP_NUMBER, rlDoc.getPurchaseOrderIdentifier());
387             }
388         }
389 
390         //check bill of lading number for duplicates
391         if (!StringUtils.isEmpty(rlDoc.getShipmentBillOfLadingNumber())) {
392             docNumbers = receivingDao.duplicateBillOfLadingNumber(poId, rlDoc.getShipmentBillOfLadingNumber());
393             if (hasDuplicateEntry(docNumbers)) {
394                 appendDuplicateMessage(currentMessage, PurapKeyConstants.MESSAGE_DUPLICATE_RECEIVING_LINE_BILL_OF_LADING_NUMBER, rlDoc.getPurchaseOrderIdentifier());
395             }
396         }
397 
398         //add message if one exists
399         if (currentMessage.length() > 0) {
400             //add suffix
401             appendDuplicateMessage(currentMessage, PurapKeyConstants.MESSAGE_DUPLICATE_RECEIVING_LINE_SUFFIX, rlDoc.getPurchaseOrderIdentifier());
402 
403             //add msg to map
404             msgs.put(PurapConstants.LineItemReceivingDocumentStrings.DUPLICATE_RECEIVING_LINE_QUESTION, currentMessage.toString());
405         }
406 
407         return msgs;
408     }
409 
410     /**
411      * Looks at a list of doc numbers, but only considers an entry duplicate
412      * if the document is in a Final status.
413      *
414      * @param docNumbers
415      * @return
416      */
417     protected boolean hasDuplicateEntry(List<String> docNumbers) {
418 
419         boolean isDuplicate = false;
420         WorkflowDocument workflowDocument = null;
421 
422         for (String docNumber : docNumbers) {
423 
424             try {
425                 workflowDocument = workflowDocumentService.loadWorkflowDocument(docNumber, GlobalVariables.getUserSession().getPerson());
426             } catch (WorkflowException we) {
427                 throw new RuntimeException(we);
428             }
429 
430             //if the doc number exists, and is in final status, consider this a dupe and return
431             if (workflowDocument.isFinal()) {
432                 isDuplicate = true;
433                 break;
434             }
435         }
436 
437         return isDuplicate;
438 
439     }
440 
441     protected void appendDuplicateMessage(StringBuffer currentMessage, String duplicateMessageKey, Integer poId) {
442 
443         //append prefix if this is first call
444         if (currentMessage.length() == 0) {
445             String messageText = configurationService.getPropertyValueAsString(PurapKeyConstants.MESSAGE_DUPLICATE_RECEIVING_LINE_PREFIX);
446             String prefix = MessageFormat.format(messageText, poId.toString());
447 
448             currentMessage.append(prefix);
449         }
450 
451         //append message
452         currentMessage.append(configurationService.getPropertyValueAsString(duplicateMessageKey));
453     }
454 
455     @Override
456     public void completeCorrectionReceivingDocument(ReceivingDocument correctionDocument) {
457 
458         ReceivingDocument receivingDoc = ((CorrectionReceivingDocument) correctionDocument).getLineItemReceivingDocument();
459 
460         for (CorrectionReceivingItem correctionItem : (List<CorrectionReceivingItem>) correctionDocument.getItems()) {
461             if (!StringUtils.equalsIgnoreCase(correctionItem.getItemType().getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE)) {
462 
463                 LineItemReceivingItem recItem = (LineItemReceivingItem) receivingDoc.getItem(correctionItem.getItemLineNumber().intValue() - 1);
464                 List<PurchaseOrderItem> purchaseOrderItems = receivingDoc.getPurchaseOrderDocument().getItems();
465                 PurchaseOrderItem poItem = purchaseOrderItems.get(correctionItem.getItemLineNumber().intValue() - 1);
466 
467                 if (ObjectUtils.isNotNull(recItem)) {
468                     recItem.setItemReceivedTotalQuantity(correctionItem.getItemReceivedTotalQuantity());
469                     recItem.setItemReturnedTotalQuantity(correctionItem.getItemReturnedTotalQuantity());
470                     recItem.setItemDamagedTotalQuantity(correctionItem.getItemDamagedTotalQuantity());
471                 }
472             }
473         }
474 
475     }
476 
477     /**
478      * This method deletes unneeded items and updates the totals on the po and does any additional processing based on items i.e. FYI etc
479      *
480      * @param receivingDocument receiving document
481      */
482     @Override
483     public void completeReceivingDocument(ReceivingDocument receivingDocument) {
484 
485         PurchaseOrderDocument poDoc = null;
486 
487         if (receivingDocument instanceof LineItemReceivingDocument) {
488             // delete unentered items
489             purapService.deleteUnenteredItems(receivingDocument);
490             poDoc = receivingDocument.getPurchaseOrderDocument();
491             SpringContext.getBean(GeneralLedgerPendingEntryService.class).generateGeneralLedgerPendingEntries(poDoc);
492         } else if (receivingDocument instanceof CorrectionReceivingDocument) {
493             CorrectionReceivingDocument correctionDocument = (CorrectionReceivingDocument) receivingDocument;
494             poDoc = purchaseOrderService.getCurrentPurchaseOrder(correctionDocument.getLineItemReceivingDocument().getPurchaseOrderIdentifier());
495         }
496 
497         updateReceivingTotalsOnPurchaseOrder(receivingDocument, poDoc);
498 
499         //TODO: custom doc specific service hook here for correction to do it's receiving doc update
500 
501         purapService.saveDocumentNoValidation(poDoc);
502 
503         // sendFyiForItems(receivingDocument);
504 
505         spawnPoAmendmentForUnorderedItems(receivingDocument, poDoc);
506 
507         purapService.saveDocumentNoValidation(receivingDocument);
508     }
509 
510     @Override
511     public void createNoteForReturnedAndDamagedItems(ReceivingDocument recDoc) {
512 
513         for (ReceivingItem item : (List<ReceivingItem>) recDoc.getItems()) {
514             if (!StringUtils.equalsIgnoreCase(item.getItemType().getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE)) {
515                 if (item.getItemReturnedTotalQuantity() != null && item.getItemReturnedTotalQuantity().isGreaterThan(KualiDecimal.ZERO)) {
516                     try {
517                         String noteString = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(PurapKeyConstants.MESSAGE_RECEIVING_LINEITEM_RETURN_NOTE_TEXT);
518                         noteString = item.getItemReturnedTotalQuantity().intValue() + " " + noteString + " " + item.getItemLineNumber();
519                         addNoteToReceivingDocument(recDoc, noteString);
520                     } catch (Exception e) {
521                         String errorMsg = "Note Service Exception caught: " + e.getLocalizedMessage();
522                         throw new RuntimeException(errorMsg, e);
523                     }
524                 }
525 
526                 if (item.getItemDamagedTotalQuantity() != null && item.getItemDamagedTotalQuantity().isGreaterThan(KualiDecimal.ZERO)) {
527                     try {
528                         String noteString = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(PurapKeyConstants.MESSAGE_RECEIVING_LINEITEM_DAMAGE_NOTE_TEXT);
529                         noteString = item.getItemDamagedTotalQuantity().intValue() + " " + noteString + " " + item.getItemLineNumber();
530                         addNoteToReceivingDocument(recDoc, noteString);
531                     } catch (Exception e) {
532                         String errorMsg = "Note Service Exception caught: " + e.getLocalizedMessage();
533                         throw new RuntimeException(errorMsg, e);
534                     }
535                 }
536             }
537         }
538     }
539 
540     protected void updateReceivingTotalsOnPurchaseOrder(ReceivingDocument receivingDocument, PurchaseOrderDocument poDoc) {
541         for (OleReceivingItem receivingItem : (List<OleReceivingItem>) receivingDocument.getItems()) {
542             ItemType itemType = receivingItem.getItemType();
543             if (!StringUtils.equalsIgnoreCase(itemType.getItemTypeCode(), PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE)) {
544                 //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
545                 OlePurchaseOrderItem poItem = (OlePurchaseOrderItem) poDoc.getItemByLineNumber(receivingItem
546                         .getItemLineNumber());
547 
548                 if (ObjectUtils.isNotNull(poItem)) {
549 
550                     KualiDecimal poItemReceivedTotal = poItem.getItemReceivedTotalQuantity();
551 
552                     KualiDecimal receivingItemReceivedOriginal = receivingItem.getItemOriginalReceivedTotalQuantity();
553                     /**
554                      * FIXME: It's coming as null although we set the default value in the LineItemReceivingItem constructor - mpv
555                      */
556                     if (ObjectUtils.isNull(receivingItemReceivedOriginal)) {
557                         receivingItemReceivedOriginal = KualiDecimal.ZERO;
558                     }
559                     KualiDecimal receivingItemReceived = receivingItem.getItemReceivedTotalQuantity();
560                     KualiDecimal receivingItemTotalReceivedAdjested = receivingItemReceived.subtract(receivingItemReceivedOriginal);
561 
562                     if (ObjectUtils.isNull(poItemReceivedTotal)) {
563                         poItemReceivedTotal = KualiDecimal.ZERO;
564                     }
565                     KualiDecimal poItemReceivedTotalAdjusted = poItemReceivedTotal.add(receivingItemTotalReceivedAdjested);
566 
567                     KualiDecimal receivingItemReturnedOriginal = receivingItem.getItemOriginalReturnedTotalQuantity();
568                     if (ObjectUtils.isNull(receivingItemReturnedOriginal)) {
569                         receivingItemReturnedOriginal = KualiDecimal.ZERO;
570                     }
571 
572                     KualiDecimal receivingItemReturned = receivingItem.getItemReturnedTotalQuantity();
573                     if (ObjectUtils.isNull(receivingItemReturned)) {
574                         receivingItemReturned = KualiDecimal.ZERO;
575                     }
576 
577                     KualiDecimal receivingItemTotalReturnedAdjusted = receivingItemReturned.subtract(receivingItemReturnedOriginal);
578 
579                     poItemReceivedTotalAdjusted = poItemReceivedTotalAdjusted.subtract(receivingItemTotalReturnedAdjusted);
580 
581                     poItem.setItemReceivedTotalQuantity(poItemReceivedTotalAdjusted);
582 
583                     KualiDecimal poTotalDamaged = poItem.getItemDamagedTotalQuantity();
584                     if (ObjectUtils.isNull(poTotalDamaged)) {
585                         poTotalDamaged = KualiDecimal.ZERO;
586                     }
587 
588                     KualiDecimal receivingItemTotalDamagedOriginal = receivingItem.getItemOriginalDamagedTotalQuantity();
589                     if (ObjectUtils.isNull(receivingItemTotalDamagedOriginal)) {
590                         receivingItemTotalDamagedOriginal = KualiDecimal.ZERO;
591                     }
592 
593                     KualiDecimal receivingItemTotalDamaged = receivingItem.getItemDamagedTotalQuantity();
594                     if (ObjectUtils.isNull(receivingItemTotalDamaged)) {
595                         receivingItemTotalDamaged = KualiDecimal.ZERO;
596                     }
597 
598                     KualiDecimal receivingItemTotalDamagedAdjusted = receivingItemTotalDamaged.subtract(receivingItemTotalDamagedOriginal);
599 
600                     poItem.setItemDamagedTotalQuantity(poTotalDamaged.add(receivingItemTotalDamagedAdjusted));
601                     // Updating the Total Parts
602                     KualiDecimal poItemPartsReceivedTotal = poItem.getItemReceivedTotalParts();
603 
604                     KualiDecimal receivingItemPartsReceivedOriginal = receivingItem.getItemOriginalReceivedTotalParts();
605 
606                     if (ObjectUtils.isNull(receivingItemPartsReceivedOriginal)) {
607                         receivingItemPartsReceivedOriginal = KualiDecimal.ZERO;
608                     }
609                     KualiDecimal receivingItemPartsReceived = receivingItem.getItemReceivedTotalParts();
610                     KualiDecimal receivingItemPartsTotalReceivedAdjusted = receivingItemPartsReceived
611                             .subtract(receivingItemPartsReceivedOriginal);
612 
613                     if (ObjectUtils.isNull(poItemPartsReceivedTotal)) {
614                         poItemPartsReceivedTotal = KualiDecimal.ZERO;
615                     }
616                     KualiDecimal poItemPartsReceivedTotalAdjusted = poItemPartsReceivedTotal
617                             .add(receivingItemPartsTotalReceivedAdjusted);
618 
619                     KualiDecimal receivingItemPartsReturnedOriginal = receivingItem.getItemOriginalReturnedTotalParts();
620                     if (ObjectUtils.isNull(receivingItemPartsReturnedOriginal)) {
621                         receivingItemPartsReturnedOriginal = KualiDecimal.ZERO;
622                     }
623 
624                     KualiDecimal receivingItemPartsReturned = receivingItem.getItemReturnedTotalParts();
625                     if (ObjectUtils.isNull(receivingItemPartsReturned)) {
626                         receivingItemPartsReturned = KualiDecimal.ZERO;
627                     }
628 
629                     KualiDecimal receivingItemPartsTotalReturnedAdjusted = receivingItemPartsReturned
630                             .subtract(receivingItemPartsReturnedOriginal);
631 
632                     poItemPartsReceivedTotalAdjusted = poItemPartsReceivedTotalAdjusted
633                             .subtract(receivingItemPartsTotalReturnedAdjusted);
634 
635                     poItem.setItemReceivedTotalParts(poItemPartsReceivedTotalAdjusted);
636 
637                     KualiDecimal poPartsTotalDamaged = poItem.getItemDamagedTotalParts();
638                     if (ObjectUtils.isNull(poPartsTotalDamaged)) {
639                         poPartsTotalDamaged = KualiDecimal.ZERO;
640                     }
641 
642                     KualiDecimal receivingItemPartsTotalDamagedOriginal = receivingItem
643                             .getItemOriginalDamagedTotalParts();
644                     if (ObjectUtils.isNull(receivingItemPartsTotalDamagedOriginal)) {
645                         receivingItemPartsTotalDamagedOriginal = KualiDecimal.ZERO;
646                     }
647 
648                     KualiDecimal receivingItemPartsTotalDamaged = receivingItem.getItemDamagedTotalParts();
649                     if (ObjectUtils.isNull(receivingItemPartsTotalDamaged)) {
650                         receivingItemPartsTotalDamaged = KualiDecimal.ZERO;
651                     }
652 
653                     KualiDecimal receivingItemPartsTotalDamagedAdjusted = receivingItemPartsTotalDamaged
654                             .subtract(receivingItemPartsTotalDamagedOriginal);
655 
656                     poItem.setItemDamagedTotalParts(poPartsTotalDamaged.add(receivingItemPartsTotalDamagedAdjusted));
657 
658                 }
659             }
660         }
661     }
662 
663     /**
664      * Spawns PO amendments for new unordered items on a receiving document.
665      *
666      * @param receivingDocument
667      * @param po
668      */
669     protected void spawnPoAmendmentForUnorderedItems(ReceivingDocument receivingDocument, PurchaseOrderDocument po) {
670 
671         //if receiving line document
672         if (receivingDocument instanceof LineItemReceivingDocument) {
673             LineItemReceivingDocument rlDoc = (LineItemReceivingDocument) receivingDocument;
674 
675             //if a new item has been added spawn a purchase order amendment
676             if (hasNewUnorderedItem((LineItemReceivingDocument) receivingDocument)) {
677                 String newSessionUserId = OLEConstants.SYSTEM_USER;
678                 try {
679 
680                     LogicContainer logicToRun = new LogicContainer() {
681                         @Override
682                         public Object runLogic(Object[] objects) throws Exception {
683                             LineItemReceivingDocument rlDoc = (LineItemReceivingDocument) objects[0];
684                             String poDocNumber = (String) objects[1];
685 
686                             //create a PO amendment
687                             PurchaseOrderAmendmentDocument amendmentPo = (PurchaseOrderAmendmentDocument) purchaseOrderService.createAndSavePotentialChangeDocument(poDocNumber, PurchaseOrderDocTypes.PURCHASE_ORDER_AMENDMENT_DOCUMENT, PurchaseOrderStatuses.APPDOC_AMENDMENT);
688 
689                             //add new lines to amendement
690                             addUnorderedItemsToAmendment(amendmentPo, rlDoc);
691 
692                             //route amendment
693                             //documentService.routeDocument(amendmentPo, null, null);
694                             //save document
695                             documentService.saveDocument(amendmentPo);
696                             //add note to amendment po document
697                             String note = "Purchase Order Amendment " + amendmentPo.getPurapDocumentIdentifier() + " (document id " + amendmentPo.getDocumentNumber() + ") created for new unordered line items due to Receiving (document id " + rlDoc.getDocumentNumber() + ")";
698 
699                             Note noteObj = documentService.createNoteFromDocument(amendmentPo, note);
700                             amendmentPo.addNote(noteObj);
701                             noteService.save(noteObj);
702 
703                             return null;
704                         }
705                     };
706 
707                     purapService.performLogicWithFakedUserSession(newSessionUserId, logicToRun, new Object[]{rlDoc, po.getDocumentNumber()});
708                 } catch (WorkflowException e) {
709                     String errorMsg = "Workflow Exception caught: " + e.getLocalizedMessage();
710                     throw new RuntimeException(errorMsg, e);
711                 } catch (Exception e) {
712                     throw new RuntimeException(e);
713                 }
714             }
715         }
716     }
717 
718     /**
719      * Checks the item list for newly added items.
720      *
721      * @param rlDoc
722      * @return
723      */
724     @Override
725     public boolean hasNewUnorderedItem(LineItemReceivingDocument rlDoc) {
726 
727         boolean itemAdded = false;
728 
729         for (LineItemReceivingItem rlItem : (List<LineItemReceivingItem>) rlDoc.getItems()) {
730             if (PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE.equals(rlItem.getItemTypeCode()) &&
731                     !StringUtils.isEmpty(rlItem.getItemReasonAddedCode())) {
732                 itemAdded = true;
733                 break;
734             }
735         }
736 
737         return itemAdded;
738     }
739 
740     /**
741      * Adds an unordered item to a po amendment document.
742      *
743      * @param amendment
744      * @param rlDoc
745      */
746     protected void addUnorderedItemsToAmendment(PurchaseOrderAmendmentDocument amendment, LineItemReceivingDocument rlDoc) {
747 
748         PurchaseOrderItem poi = null;
749         // Added for jira OLE-2515
750 //        OlePurchaseOrderItem  opoi = null;
751 
752         for (OleLineItemReceivingItem rlItem : (List<OleLineItemReceivingItem>) rlDoc.getItems()) {
753 
754             if (PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE.equals(rlItem.getItemTypeCode()) &&
755                     !StringUtils.isEmpty(rlItem.getItemReasonAddedCode())) {
756 
757                 poi = createPoItemFromReceivingLine(rlItem);
758                 poi.setDocumentNumber(amendment.getDocumentNumber());
759                 // add default commodity code from parameter, if commodity code is required on PO and not specified in the unordered item
760                 // Note: if we don't add logic to populate commodity code in LineItemReceivingItem, then at this point this field is always empty for unordered item
761                 if (purchaseOrderService.isCommodityCodeRequiredOnPurchaseOrder() && StringUtils.isEmpty(poi.getPurchasingCommodityCode())) {
762                     String defaultCommodityCode = SpringContext.getBean(ParameterService.class).getParameterValueAsString(PurchaseOrderAmendmentDocument.class, PurapParameterConstants.UNORDERED_ITEM_DEFAULT_COMMODITY_CODE);
763                     poi.setPurchasingCommodityCode(defaultCommodityCode);
764                 }
765                 poi.refreshNonUpdateableReferences();
766                 amendment.addItem(poi);
767             }
768         }
769 
770     }
771 
772     /**
773      * Creates a PO item from a receiving line item.
774      *
775      * @param rlItem
776      * @return
777      */
778     protected PurchaseOrderItem createPoItemFromReceivingLine(LineItemReceivingItem rlItem) {
779 
780         OlePurchaseOrderItem opoi = new OlePurchaseOrderItem();
781         PurchaseOrderItem poi = new OlePurchaseOrderItem();
782 
783         poi.setItemActiveIndicator(true);
784         poi.setItemTypeCode(rlItem.getItemTypeCode());
785         poi.setItemLineNumber(rlItem.getItemLineNumber());
786         poi.setItemCatalogNumber(rlItem.getItemCatalogNumber());
787         poi.setItemDescription(rlItem.getItemDescription());
788 
789         if (rlItem.getItemReturnedTotalQuantity() == null) {
790             poi.setItemQuantity(rlItem.getItemReceivedTotalQuantity());
791         } else {
792             poi.setItemQuantity(rlItem.getItemReceivedTotalQuantity().subtract(rlItem.getItemReturnedTotalQuantity()));
793         }
794 
795         poi.setItemUnitOfMeasureCode(rlItem.getItemUnitOfMeasureCode());
796         poi.setItemUnitPrice(new BigDecimal(0));
797 
798         poi.setItemDamagedTotalQuantity(rlItem.getItemDamagedTotalQuantity());
799         poi.setItemReceivedTotalQuantity(rlItem.getItemReceivedTotalQuantity());
800 
801         return poi;
802     }
803 
804 
805     /**
806      * Creates a PO item from a receiving line item.
807      *
808      * @param rlItem
809      * @return
810      */
811     protected OlePurchaseOrderItem createPoItemFromReceivingLine(OleLineItemReceivingItem rlItem) {
812 
813         //  OlePurchaseOrderItem opoi = new OlePurchaseOrderItem();
814         //  (OleLineItemReceivingItem) rlItem.getItemT
815         //opoi.setItemTitleId(rlItem.getitem);
816         OlePurchaseOrderItem poi = new OlePurchaseOrderItem();
817 
818         poi.setItemTitleId(rlItem.getItemTitleId());
819         poi.setItemActiveIndicator(true);
820         poi.setItemTypeCode(rlItem.getItemTypeCode());
821         poi.setItemLineNumber(rlItem.getItemLineNumber());
822         poi.setItemCatalogNumber(rlItem.getItemCatalogNumber());
823         poi.setItemDescription(rlItem.getItemDescription());
824 
825         if (rlItem.getItemReturnedTotalQuantity() == null) {
826             poi.setItemQuantity(rlItem.getItemReceivedTotalQuantity());
827         } else {
828             poi.setItemQuantity(rlItem.getItemReceivedTotalQuantity().subtract(rlItem.getItemReturnedTotalQuantity()));
829         }
830 
831         poi.setItemUnitOfMeasureCode(rlItem.getItemUnitOfMeasureCode());
832         poi.setItemUnitPrice(new BigDecimal(0));
833 
834         poi.setItemDamagedTotalQuantity(rlItem.getItemDamagedTotalQuantity());
835         poi.setItemReceivedTotalQuantity(rlItem.getItemReceivedTotalQuantity());
836         poi.setItemNoOfParts(new KualiInteger(rlItem.getItemReceivedTotalParts().intValue()));
837 
838         List<OleCopy> copyList = rlItem.getCopyList() != null ? rlItem.getCopyList() : new ArrayList<OleCopy>();
839         Integer receivedCount = 0;
840         for (OleCopy oleCopy : copyList) {
841             if (oleCopy.getReceiptStatus().equalsIgnoreCase("Received")) {
842                 receivedCount++;
843             }
844         }
845         if (receivedCount == 0) {
846             rlItem
847                     .setReceiptStatusId(getReceiptStatusDetails(OLEConstants.PO_RECEIPT_STATUS_NOT_RECEIVED));
848         } else if (receivedCount == copyList.size()) {
849             rlItem
850                     .setReceiptStatusId(getReceiptStatusDetails(OLEConstants.PO_RECEIPT_STATUS_FULLY_RECEIVED));
851         } else {
852             rlItem
853                     .setReceiptStatusId(getReceiptStatusDetails(OLEConstants.PO_RECEIPT_STATUS_PARTIALLY_RECEIVED));
854         }
855         poi.setReceiptStatusId(rlItem.getReceiptStatusId());
856         if (poi.getItemQuantity().equals(new KualiDecimal(1)) && poi.getItemNoOfParts().isGreaterThan(new KualiInteger(1))) {
857             poi.setNoOfCopiesReceived("N/A");
858             poi.setNoOfPartsReceived(receivedCount.toString());
859         } else if (poi.getItemQuantity().isGreaterThan(new KualiDecimal(1)) && poi.getItemNoOfParts().equals(new KualiDecimal(1))) {
860             poi.setNoOfCopiesReceived(receivedCount.toString());
861             poi.setNoOfPartsReceived("N/A");
862         } else if (poi.getItemQuantity().isGreaterThan(new KualiDecimal(1)) && poi.getItemNoOfParts().isGreaterThan(new KualiInteger(1))) {
863             poi.setNoOfCopiesReceived("See Copies Section");
864             poi.setNoOfPartsReceived("See Copies Section");
865         }
866        /* poi.setNoOfCopiesReceived((poi.getNoOfCopiesReceived().add(new KualiInteger(rlItem
867                 .getItemReceivedTotalQuantity().bigDecimalValue()))).subtract(new KualiInteger(rlItem
868                 .getItemReturnedTotalQuantity().bigDecimalValue())));
869         poi.setNoOfPartsReceived((poi.getNoOfPartsReceived().add(new KualiInteger(rlItem.getItemReceivedTotalParts()
870                 .bigDecimalValue()))).subtract(new KualiInteger(rlItem.getItemReturnedTotalParts().bigDecimalValue())));
871         if (poi.getItemQuantity().intValue() == poi.getNoOfCopiesReceived().intValue()
872                 && poi.getItemNoOfParts().intValue() == poi.getNoOfPartsReceived().intValue()) {
873             poi.setReceiptStatusId(getReceiptStatusDetails(OLEConstants.PO_RECEIPT_STATUS_FULLY_RECEIVED));
874         }
875         else {
876             if (poi.getNoOfPartsReceived().isZero() && poi.getNoOfCopiesReceived().isZero()) {
877                 poi.setReceiptStatusId(getReceiptStatusDetails(OLEConstants.PO_RECEIPT_STATUS_NOT_RECEIVED));
878             }
879             else {
880                 poi.setReceiptStatusId(getReceiptStatusDetails(OLEConstants.PO_RECEIPT_STATUS_PARTIALLY_RECEIVED));
881             }
882         }
883         List<OleLineItemReceivingDoc> oleLineItemReceivingItemDocList = new ArrayList<OleLineItemReceivingDoc>();
884         oleLineItemReceivingItemDocList = rlItem.getOleLineItemReceivingItemDocList();
885         Iterator iterator = oleLineItemReceivingItemDocList.iterator();
886         while (iterator.hasNext()) {
887             Object object = iterator.next();
888             if (object instanceof OleLineItemReceivingDoc) {
889                 OleLineItemReceivingDoc oleLineItemReceivingDoc = (OleLineItemReceivingDoc) object;
890                 if (rlItem.getReceivingItemIdentifier().intValue() == oleLineItemReceivingDoc.getReceivingLineItem()
891                         .getReceivingItemIdentifier()) {
892                     if (null != oleLineItemReceivingDoc.getItemTitleId()) {
893                         poi.setItemTitleId(oleLineItemReceivingDoc.getItemTitleId());
894                         List<String> itemTitleIdsList = new ArrayList<String>();
895 
896                         itemTitleIdsList.add(rlItem.getItemTitleId());
897 
898                     }
899                     if (null != oleLineItemReceivingDoc.getItemTitleId()) {
900                         if (rlItem.getItemReceivedTotalQuantity().isGreaterThan(new KualiDecimal(1))
901                                 || rlItem.getItemReceivedTotalParts().isGreaterThan(new KualiDecimal(1))) {
902                             List<OleCopies> copies = rlItem.getCopies();
903                                 poi.setCopies(copies);
904 
905                         }
906 
907                     }
908                 }
909             }
910         }    */
911 
912         return poi;
913     }
914 
915     /**
916      * Creates a list of fiscal officers for new unordered items added to a purchase order.
917      *
918      * @param po
919      * @return
920      */
921     protected List<AdHocRoutePerson> createFyiFiscalOfficerList(ReceivingDocument recDoc) {
922 
923         PurchaseOrderDocument po = recDoc.getPurchaseOrderDocument();
924         List<AdHocRoutePerson> adHocRoutePersons = new ArrayList<AdHocRoutePerson>();
925         Map fiscalOfficers = new HashMap();
926         AdHocRoutePerson adHocRoutePerson = null;
927 
928         for (ReceivingItem recItem : (List<ReceivingItem>) recDoc.getItems()) {
929             //if this item has an item line number then it is coming from the po
930             if (ObjectUtils.isNotNull(recItem.getItemLineNumber())) {
931                 PurchaseOrderItem poItem = (PurchaseOrderItem) po.getItemByLineNumber(recItem.getItemLineNumber());
932 
933                 if (poItem.getItemQuantity().isLessThan(poItem.getItemReceivedTotalQuantity()) ||
934                         recItem.getItemDamagedTotalQuantity().isGreaterThan(KualiDecimal.ZERO)) {
935 
936                     // loop through accounts and pull off fiscal officer
937                     for (PurApAccountingLine account : poItem.getSourceAccountingLines()) {
938 
939                         //check for dupes of fiscal officer
940                         if (fiscalOfficers.containsKey(account.getAccount().getAccountFiscalOfficerUser().getPrincipalName()) == false) {
941 
942                             //add fiscal officer to list
943                             fiscalOfficers.put(account.getAccount().getAccountFiscalOfficerUser().getPrincipalName(), account.getAccount().getAccountFiscalOfficerUser().getPrincipalName());
944 
945                             //create AdHocRoutePerson object and add to list
946                             adHocRoutePerson = new AdHocRoutePerson();
947                             adHocRoutePerson.setId(account.getAccount().getAccountFiscalOfficerUser().getPrincipalName());
948                             adHocRoutePerson.setActionRequested(OLEConstants.WORKFLOW_FYI_REQUEST);
949                             adHocRoutePersons.add(adHocRoutePerson);
950                         }
951                     }
952 
953                 }
954 
955             }
956         }
957 
958         return adHocRoutePersons;
959     }
960 
961     /**
962      * Sends an FYI to fiscal officers for new unordered items.
963      *
964      * @param po
965      */
966     protected void sendFyiForItems(ReceivingDocument recDoc) {
967 
968         List<AdHocRoutePerson> fyiList = createFyiFiscalOfficerList(recDoc);
969         String annotation = "Notification of Item exceeded Quantity or Damaged" + "(document id " + recDoc.getDocumentNumber() + ")";
970         String responsibilityNote = "Please Review";
971 
972         for (AdHocRoutePerson adHocPerson : fyiList) {
973             try {
974                 recDoc.appSpecificRouteDocumentToUser(
975                         recDoc.getDocumentHeader().getWorkflowDocument(),
976                         adHocPerson.getPerson().getPrincipalId(),
977                         annotation,
978                         responsibilityNote);
979             } catch (WorkflowException e) {
980                 throw new RuntimeException("Error routing fyi for document with id " + recDoc.getDocumentNumber(), e);
981             }
982 
983         }
984     }
985 
986     @Override
987     public void addNoteToReceivingDocument(ReceivingDocument receivingDocument, String note) throws Exception {
988         Note noteObj = documentService.createNoteFromDocument(receivingDocument, note);
989         receivingDocument.addNote(noteObj);
990         noteService.save(noteObj);
991     }
992 
993     @Override
994     public String getReceivingDeliveryCampusCode(PurchaseOrderDocument po) {
995         String deliveryCampusCode = "";
996         String latestDocumentNumber = "";
997 
998         List<LineItemReceivingView> rViews = null;
999         WorkflowDocument workflowDocument = null;
1000         DateTime latestCreateDate = null;
1001 
1002         //get related views
1003         if (ObjectUtils.isNotNull(po.getRelatedViews())) {
1004             rViews = po.getRelatedViews().getRelatedLineItemReceivingViews();
1005         }
1006 
1007         //if not empty, then grab the latest receiving view
1008         if (ObjectUtils.isNotNull(rViews) && rViews.isEmpty() == false) {
1009 
1010             for (LineItemReceivingView rView : rViews) {
1011                 try {
1012                     workflowDocument = workflowDocumentService.loadWorkflowDocument(rView.getDocumentNumber(), GlobalVariables.getUserSession().getPerson());
1013 
1014                     //if latest create date is null or the latest is before the current, current is newer
1015                     if (ObjectUtils.isNull(latestCreateDate) || latestCreateDate.isBefore(workflowDocument.getDateCreated())) {
1016                         latestCreateDate = workflowDocument.getDateCreated();
1017                         latestDocumentNumber = workflowDocument.getDocumentId().toString();
1018                     }
1019                 } catch (WorkflowException we) {
1020                     throw new RuntimeException(we);
1021                 }
1022             }
1023 
1024             //if there is a create date, a latest workflow doc was found
1025             if (ObjectUtils.isNotNull(latestCreateDate)) {
1026                 try {
1027                     LineItemReceivingDocument rlDoc = (LineItemReceivingDocument) documentService.getByDocumentHeaderId(latestDocumentNumber);
1028                     deliveryCampusCode = rlDoc.getDeliveryCampusCode();
1029                 } catch (WorkflowException we) {
1030                     throw new RuntimeException(we);
1031                 }
1032             }
1033         }
1034 
1035         return deliveryCampusCode;
1036     }
1037 
1038     /**
1039      * @see org.kuali.ole.module.purap.document.service.ReceivingService#isLineItemReceivingDocumentGeneratedForPurchaseOrder(java.lang.Integer)
1040      */
1041     @Override
1042     public boolean isLineItemReceivingDocumentGeneratedForPurchaseOrder(Integer poId) throws RuntimeException {
1043 
1044         boolean isGenerated = false;
1045 
1046         List<String> docNumbers = receivingDao.getDocumentNumbersByPurchaseOrderId(poId);
1047         WorkflowDocument workflowDocument = null;
1048 
1049         for (String docNumber : docNumbers) {
1050 
1051             try {
1052                 workflowDocument = workflowDocumentService.loadWorkflowDocument(docNumber, GlobalVariables.getUserSession().getPerson());
1053             } catch (WorkflowException we) {
1054                 throw new RuntimeException(we);
1055             }
1056 
1057             if (workflowDocument.isFinal()) {
1058                 isGenerated = true;
1059                 break;
1060             }
1061         }
1062 
1063         return isGenerated;
1064     }
1065 
1066     @Override
1067     public void approveReceivingDocsForPOAmendment() {
1068         List<String> docNumbers = getDocumentsNumbersAwaitingPurchaseOrderOpenStatus();
1069         List<LineItemReceivingDocument> docs = new ArrayList<LineItemReceivingDocument>();
1070         for (String docNumber : docNumbers) {
1071             LineItemReceivingDocument lreq = getLineItemReceivingByDocumentNumber(docNumber);
1072             if (ObjectUtils.isNotNull(lreq)) {
1073                 docs.add(lreq);
1074             }
1075         }
1076         if (docs != null) {
1077             for (LineItemReceivingDocument receivingDoc : docs) {
1078                 if (receivingDoc.getDocumentHeader().getWorkflowDocument().getCurrentNodeNames().contains(PurapConstants.LineItemReceivingDocumentStrings.AWAITING_PO_OPEN_STATUS)) {
1079                     approveReceivingDoc(receivingDoc);
1080                 }
1081             }
1082         }
1083 
1084     }
1085 
1086     /**
1087      * @see org.kuali.ole.module.purap.document.service.PaymentRequestService#getPaymentRequestByDocumentNumber(java.lang.String)
1088      */
1089     public LineItemReceivingDocument getLineItemReceivingByDocumentNumber(String documentNumber) {
1090         LOG.debug("getLineItemReceivingByDocumentNumber() started");
1091 
1092         if (ObjectUtils.isNotNull(documentNumber)) {
1093             try {
1094                 LineItemReceivingDocument doc = (LineItemReceivingDocument) documentService.getByDocumentHeaderId(documentNumber);
1095                 return doc;
1096             } catch (WorkflowException e) {
1097                 String errorMessage = "Error getting LineItemReceiving document from document service";
1098                 LOG.error("getLineItemReceivingByDocumentNumber() " + errorMessage, e);
1099                 throw new RuntimeException(errorMessage, e);
1100             }
1101         }
1102         return null;
1103     }
1104 
1105     protected void approveReceivingDoc(LineItemReceivingDocument receivingDoc) {
1106         PurchaseOrderDocument poDoc = receivingDoc.getPurchaseOrderDocument();
1107         if (purchaseOrderService.isPurchaseOrderOpenForProcessing(poDoc)) {
1108             try {
1109                 SpringContext.getBean(DocumentService.class).approveDocument(receivingDoc, "Approved by the batch job", null);
1110             } catch (WorkflowException e) {
1111                 LOG.error("approveReceivingDoc() Error approving receiving document from awaiting PO open", e);
1112                 throw new RuntimeException("Error approving receiving document from awaiting PO open", e);
1113             }
1114         }
1115     }
1116 
1117     /**
1118      * Gets a list of strings of receiving line item document numbers from
1119      * workflow documents where  applicationdocumentstatus = 'Awaiting Purchase Order Open Status'
1120      * If there are documents then the document number is added to the list
1121      * <p/>
1122      * NOTE: simplify using DocSearch lookup with AppDocStatus
1123      *
1124      * @return list of documentNumbers to retrieve line item receiving documents.
1125      */
1126     protected List<String> getDocumentsNumbersAwaitingPurchaseOrderOpenStatus() {
1127         List<String> receivingDocumentNumbers = new ArrayList<String>();
1128 
1129         DocumentSearchCriteria.Builder documentSearchCriteriaDTO = DocumentSearchCriteria.Builder.create();
1130         documentSearchCriteriaDTO.setDocumentTypeName(PurapConstants.RECEIVING_LINE_ITEM_DOCUMENT_TYPE);
1131         documentSearchCriteriaDTO.setApplicationDocumentStatus(PurapConstants.LineItemReceivingStatuses.APPDOC_AWAITING_PO_OPEN_STATUS);
1132         documentSearchCriteriaDTO.setSaveName(null);
1133 
1134         DocumentSearchResults results = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(null, documentSearchCriteriaDTO.build());
1135 
1136         String documentHeaderId = null;
1137 
1138         for (DocumentSearchResult result : results.getSearchResults()) {
1139             receivingDocumentNumbers.add(result.getDocument().getDocumentId());
1140         }
1141 
1142         return receivingDocumentNumbers;
1143     }
1144 
1145     public int getReceiptStatusDetails(String receiptStatusCd) {
1146         int receiptStatusId = 0;
1147         Map<String, String> receiptStatusCdMap = new HashMap<String, String>();
1148         receiptStatusCdMap.put(OLEConstants.RCPT_STATUS_CD, receiptStatusCd);
1149         List<OleReceiptStatus> oleReceiptStatusList = (List) SpringContext.getBean(BusinessObjectService.class)
1150                 .findMatching(OleReceiptStatus.class, receiptStatusCdMap);
1151         for (OleReceiptStatus oleReceiptStatus : oleReceiptStatusList) {
1152             receiptStatusId = oleReceiptStatus.getReceiptStatusId().intValue();
1153         }
1154         return receiptStatusId;
1155     }
1156 
1157 }
1158