View Javadoc
1   /*
2    * Copyright 2006 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.apache.commons.lang.text.StrBuilder;
20  import org.kuali.ole.coa.businessobject.Account;
21  import org.kuali.ole.coa.service.AccountService;
22  import org.kuali.ole.deliver.batch.OleMailer;
23  import org.kuali.ole.integration.purap.CapitalAssetSystem;
24  import org.kuali.ole.module.purap.*;
25  import org.kuali.ole.module.purap.PurapConstants.*;
26  import org.kuali.ole.module.purap.batch.AutoClosePurchaseOrdersStep;
27  import org.kuali.ole.module.purap.batch.AutoCloseRecurringOrdersStep;
28  import org.kuali.ole.module.purap.businessobject.*;
29  import org.kuali.ole.module.purap.document.*;
30  import org.kuali.ole.module.purap.document.dataaccess.PurchaseOrderDao;
31  import org.kuali.ole.module.purap.document.service.*;
32  import org.kuali.ole.module.purap.edi.PurchaseOrderEdi;
33  import org.kuali.ole.module.purap.pdf.PurchaseOrderParameters;
34  import org.kuali.ole.module.purap.pdf.PurchaseOrderPdf;
35  import org.kuali.ole.module.purap.pdf.PurchaseOrderTransmitParameters;
36  import org.kuali.ole.module.purap.util.PurApObjectUtils;
37  import org.kuali.ole.module.purap.util.ThresholdHelper;
38  import org.kuali.ole.module.purap.util.ThresholdHelper.ThresholdSummary;
39  import org.kuali.ole.select.document.OlePurchaseOrderDocument;
40  import org.kuali.ole.select.document.service.OleSelectDocumentService;
41  import org.kuali.ole.select.service.OleTransmissionService;
42  import org.kuali.ole.sys.OLEConstants;
43  import org.kuali.ole.sys.OLEPropertyConstants;
44  import org.kuali.ole.sys.businessobject.SourceAccountingLine;
45  import org.kuali.ole.sys.context.SpringContext;
46  import org.kuali.ole.sys.document.FinancialSystemTransactionalDocumentBase;
47  import org.kuali.ole.sys.document.validation.event.AttributedRouteDocumentEvent;
48  import org.kuali.ole.sys.document.validation.event.DocumentSystemSaveEvent;
49  import org.kuali.ole.sys.service.impl.OleParameterConstants;
50  import org.kuali.ole.vnd.VendorConstants;
51  import org.kuali.ole.vnd.VendorConstants.AddressTypes;
52  import org.kuali.ole.vnd.businessobject.*;
53  import org.kuali.ole.vnd.document.service.VendorService;
54  import org.kuali.rice.core.api.config.property.ConfigContext;
55  import org.kuali.rice.core.api.config.property.ConfigurationService;
56  import org.kuali.rice.core.api.datetime.DateTimeService;
57  import org.kuali.rice.core.api.mail.*;
58  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
59  import org.kuali.rice.core.api.util.type.KualiDecimal;
60  import org.kuali.rice.coreservice.api.parameter.Parameter;
61  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
62  import org.kuali.rice.kew.api.KewApiConstants;
63  import org.kuali.rice.kew.api.KewApiServiceLocator;
64  import org.kuali.rice.kew.api.WorkflowDocument;
65  import org.kuali.rice.kew.api.action.ActionRequestType;
66  import org.kuali.rice.kew.api.document.WorkflowDocumentService;
67  import org.kuali.rice.kew.api.document.attribute.DocumentAttributeIndexingQueue;
68  import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
69  import org.kuali.rice.kew.api.document.search.DocumentSearchResult;
70  import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
71  import org.kuali.rice.kew.api.exception.WorkflowException;
72  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
73  import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
74  import org.kuali.rice.kew.service.KEWServiceLocator;
75  import org.kuali.rice.kim.api.identity.Person;
76  import org.kuali.rice.kim.api.identity.PersonService;
77  import org.kuali.rice.kns.document.MaintenanceDocument;
78  import org.kuali.rice.kns.maintenance.Maintainable;
79  import org.kuali.rice.kns.service.DataDictionaryService;
80  import org.kuali.rice.kns.util.KNSGlobalVariables;
81  import org.kuali.rice.krad.bo.AdHocRoutePerson;
82  import org.kuali.rice.krad.bo.AdHocRouteRecipient;
83  import org.kuali.rice.krad.bo.Note;
84  import org.kuali.rice.krad.datadictionary.exception.UnknownDocumentTypeException;
85  import org.kuali.rice.krad.document.Document;
86  import org.kuali.rice.krad.document.DocumentBase;
87  import org.kuali.rice.krad.exception.ValidationException;
88  import org.kuali.rice.krad.rules.rule.event.RouteDocumentEvent;
89  import org.kuali.rice.krad.service.*;
90  import org.kuali.rice.krad.util.GlobalVariables;
91  import org.kuali.rice.krad.util.MessageMap;
92  import org.kuali.rice.krad.util.ObjectUtils;
93  import org.springframework.transaction.annotation.Transactional;
94  
95  import java.io.ByteArrayOutputStream;
96  import java.io.File;
97  import java.sql.Timestamp;
98  import java.text.ParseException;
99  import java.util.*;
100 
101 @Transactional
102 public class PurchaseOrderServiceImpl implements PurchaseOrderService {
103     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PurchaseOrderServiceImpl.class);
104 
105     protected BusinessObjectService businessObjectService;
106     protected DateTimeService dateTimeService;
107     protected DocumentService documentService;
108     protected NoteService noteService;
109     protected PurapService purapService;
110     protected PrintService printService;
111     protected PurchaseOrderDao purchaseOrderDao;
112     protected WorkflowDocumentService workflowDocumentService;
113     protected ConfigurationService kualiConfigurationService;
114     protected KualiRuleService kualiRuleService;
115     protected VendorService vendorService;
116     protected RequisitionService requisitionService;
117     protected PurApWorkflowIntegrationService purapWorkflowIntegrationService;
118     protected MaintenanceDocumentService maintenanceDocumentService;
119     protected ParameterService parameterService;
120     protected PersonService personService;
121     protected MailService mailService;
122     protected B2BPurchaseOrderService b2bPurchaseOrderService;
123     protected DataDictionaryService dataDictionaryService;
124     protected String documentNumber;
125     protected String fromEmailAddress;
126     protected List fileNameList;
127     protected String toEmailAddress;
128 
129     protected static final boolean TRANSMISSION_IS_RETRANSMIT = true;
130     protected static final boolean TRANSMISSION_IS_NOT_RETRANSMIT = !TRANSMISSION_IS_RETRANSMIT;
131     protected OlePurapService olePurapService;
132     private OleSelectDocumentService oleSelectDocumentService;
133 
134     public OlePurapService getOlePurapService() {
135         if (olePurapService == null) {
136             olePurapService = SpringContext.getBean(OlePurapService.class);
137         }
138         return olePurapService;
139     }
140 
141     @Override
142     public boolean isPurchaseOrderOpenForProcessing(Integer poId) {
143         return isPurchaseOrderOpenForProcessing(getCurrentPurchaseOrder(poId));
144     }
145 
146     @Override
147     public boolean isPurchaseOrderOpenForProcessing(PurchaseOrderDocument purchaseOrderDocument) {
148         boolean can = PurchaseOrderStatuses.APPDOC_OPEN.equals(purchaseOrderDocument.getApplicationDocumentStatus());
149         can = can && purchaseOrderDocument.isPurchaseOrderCurrentIndicator() && !purchaseOrderDocument.isPendingActionIndicator();
150 
151         // can't be any PREQ or CM that have not completed fullDocumentEntry
152         if (can) {
153             List<PaymentRequestView> preqViews = purchaseOrderDocument.getRelatedViews().getRelatedPaymentRequestViews();
154             if (preqViews != null) {
155                 for (PaymentRequestView preqView : preqViews) {
156                     if (!purapService.isPaymentRequestFullDocumentEntryCompleted(preqView.getApplicationDocumentStatus())) {
157                         return false;
158                     }
159                 }
160             }
161             List<CreditMemoView> cmViews = purchaseOrderDocument.getRelatedViews().getRelatedCreditMemoViews();
162             if (cmViews != null) {
163                 for (CreditMemoView cmView : cmViews) {
164                     if (!purapService.isVendorCreditMemoFullDocumentEntryCompleted(cmView.getApplicationDocumentStatus())) {
165                         return false;
166                     }
167                 }
168             }
169             List<InvoiceView> invViews = purchaseOrderDocument.getRelatedViews().getRelatedInvoiceViews();
170             if (invViews != null) {
171                 for (InvoiceView invView : invViews) {
172                     if (!purapService.isInvoiceFullDocumentEntryCompleted(invView.getApplicationDocumentStatus())) {
173                         return false;
174                     }
175                 }
176             }
177 
178         }
179 
180         // passed all conditions; return true
181         return can;
182     }
183 
184     @Override
185     public boolean isCommodityCodeRequiredOnPurchaseOrder() {
186         boolean enableCommodityCode = parameterService.getParameterValueAsBoolean(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.ENABLE_COMMODITY_CODE_IND);
187         if (!enableCommodityCode) {
188             return false;
189         } else {
190             return parameterService.getParameterValueAsBoolean(PurchaseOrderDocument.class, PurapRuleConstants.ITEMS_REQUIRE_COMMODITY_CODE_IND);
191         }
192     }
193 
194     /**
195      * Sets the error map to a new, empty error map before calling saveDocumentNoValidation to save the document.
196      *
197      * @param document The purchase order document to be saved.
198      */
199     protected void saveDocumentNoValidationUsingClearMessageMap(PurchaseOrderDocument document) {
200         MessageMap errorHolder = GlobalVariables.getMessageMap();
201         GlobalVariables.setMessageMap(new MessageMap());
202         try {
203             purapService.saveDocumentNoValidation(document);
204         } finally {
205             GlobalVariables.setMessageMap(errorHolder);
206         }
207     }
208 
209     /**
210      * Calls the saveDocument method of documentService to save the document.
211      *
212      * @param document The document to be saved.
213      */
214     protected void saveDocumentStandardSave(PurchaseOrderDocument document) {
215         try {
216             documentService.saveDocument(document);
217         } catch (WorkflowException we) {
218             String errorMsg = "Workflow Error saving document # " + document.getDocumentHeader().getDocumentNumber() + " " + we.getMessage();
219             LOG.error(errorMsg, we);
220             throw new RuntimeException(errorMsg, we);
221         }
222     }
223 
224     @Override
225     public PurchasingCapitalAssetItem createCamsItem(PurchasingDocument purDoc, PurApItem purapItem) {
226         PurchasingCapitalAssetItem camsItem = new PurchaseOrderCapitalAssetItem();
227         camsItem.setItemIdentifier(purapItem.getItemIdentifier());
228         // If the system type is INDIVIDUAL then for each of the capital asset items, we need a system attached to it.
229         if (purDoc.getCapitalAssetSystemTypeCode().equals(PurapConstants.CapitalAssetTabStrings.INDIVIDUAL_ASSETS)) {
230             CapitalAssetSystem resultSystem = new PurchaseOrderCapitalAssetSystem();
231             camsItem.setPurchasingCapitalAssetSystem(resultSystem);
232         }
233         camsItem.setPurchasingDocument(purDoc);
234 
235         return camsItem;
236     }
237 
238     @Override
239     public CapitalAssetSystem createCapitalAssetSystem() {
240         CapitalAssetSystem resultSystem = new PurchaseOrderCapitalAssetSystem();
241         return resultSystem;
242     }
243 
244     /**
245      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#createAutomaticPurchaseOrderDocument(org.kuali.ole.module.purap.document.RequisitionDocument)
246      */
247     @Override
248     public void createAutomaticPurchaseOrderDocument(RequisitionDocument reqDocument) {
249         String newSessionUserId = getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER);
250         try {
251 
252             LogicContainer logicToRun = new LogicContainer() {
253                 @Override
254                 public Object runLogic(Object[] objects) throws Exception {
255                     RequisitionDocument doc = (RequisitionDocument) objects[0];
256                     // update REQ data
257                     doc.setPurchaseOrderAutomaticIndicator(Boolean.TRUE);
258                     // create PO and populate with default data
259                     PurchaseOrderDocument po = generatePurchaseOrderFromRequisition(doc);
260                     po.setDefaultValuesForAPO();
261                     //check for print transmission method.. if print is selected
262                     //the doc status needs to be "Pending To Print"..
263                     checkForPrintTransmission(po);
264                     po.setContractManagerCode(PurapConstants.APO_CONTRACT_MANAGER);
265 
266                     //documentService.routeDocument(po, null, null);
267 
268                     final DocumentAttributeIndexingQueue documentAttributeIndexingQueue = KewApiServiceLocator.getDocumentAttributeIndexingQueue();
269                     documentAttributeIndexingQueue.indexDocument(po.getDocumentNumber());
270 
271                     return null;
272                 }
273             };
274             purapService.performLogicWithFakedUserSession(newSessionUserId, logicToRun, new Object[]{reqDocument});
275         } catch (WorkflowException e) {
276             String errorMsg = "Workflow Exception caught: " + e.getLocalizedMessage();
277             LOG.error(errorMsg, e);
278             throw new RuntimeException(errorMsg, e);
279         } catch (Exception e) {
280             throw new RuntimeException(e);
281         }
282     }
283 
284     /**
285      * checks for print option and if chosen then sets the app doc status to
286      * Pending To Print.
287      *
288      * @param po
289      */
290     protected void checkForPrintTransmission(PurchaseOrderDocument po) throws WorkflowException {
291         if (PurapConstants.POTransmissionMethods.PRINT.equals(po.getPurchaseOrderRetransmissionMethodCode())) {
292             po.updateAndSaveAppDocStatus(PurapConstants.PurchaseOrderStatuses.APPDOC_PENDING_PRINT);
293         }
294     }
295 
296     /**
297      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#createPurchaseOrderDocument(org.kuali.ole.module.purap.document.RequisitionDocument,
298      * java.lang.String, java.lang.Integer)
299      */
300     @Override
301     public PurchaseOrderDocument createPurchaseOrderDocument(RequisitionDocument reqDocument, String newSessionUserId, Integer contractManagerCode) {
302         try {
303             LogicContainer logicToRun = new LogicContainer() {
304                 @Override
305                 public Object runLogic(Object[] objects) throws Exception {
306                     RequisitionDocument doc = (RequisitionDocument) objects[0];
307                     PurchaseOrderDocument po = generatePurchaseOrderFromRequisition(doc);
308                     Integer cmCode = (Integer) objects[1];
309                     po.setContractManagerCode(cmCode);
310                     purapService.saveDocumentNoValidation(po);
311                     return po;
312                 }
313             };
314             return (PurchaseOrderDocument) purapService.performLogicWithFakedUserSession(newSessionUserId, logicToRun, new Object[]{reqDocument, contractManagerCode});
315         } catch (WorkflowException e) {
316             String errorMsg = "Workflow Exception caught: " + e.getLocalizedMessage();
317             LOG.error(errorMsg, e);
318             throw new RuntimeException(errorMsg, e);
319         } catch (Exception e) {
320             throw new RuntimeException(e);
321         }
322     }
323 
324     /**
325      * Create Purchase Order and populate with data from Requisition and other default data
326      *
327      * @param reqDocument The requisition document from which we create the purchase order document.
328      * @return The purchase order document created by this method.
329      * @throws WorkflowException
330      */
331     protected PurchaseOrderDocument generatePurchaseOrderFromRequisition(RequisitionDocument reqDocument) throws WorkflowException {
332         PurchaseOrderDocument poDocument = null;
333         poDocument = (PurchaseOrderDocument) documentService.getNewDocument(PurchaseOrderDocTypes.PURCHASE_ORDER_DOCUMENT);
334         poDocument.populatePurchaseOrderFromRequisition(reqDocument);
335 
336         poDocument.updateAndSaveAppDocStatus(PurapConstants.PurchaseOrderStatuses.APPDOC_IN_PROCESS);
337 
338         poDocument.setPurchaseOrderCurrentIndicator(true);
339         poDocument.setPendingActionIndicator(false);
340         /*poDocument.setLicensingRequirementIndicator(reqDocument.isLicensingRequirementIndicator());*/
341        /* poDocument.setLicensingRequirementCode(reqDocument.getLicensingRequirementCode());*/
342 
343         if (RequisitionSources.B2B.equals(poDocument.getRequisitionSourceCode())) {
344             String paramName = PurapParameterConstants.DEFAULT_B2B_VENDOR_CHOICE;
345             String paramValue = parameterService.getParameterValueAsString(PurchaseOrderDocument.class, paramName);
346             poDocument.setPurchaseOrderVendorChoiceCode(paramValue);
347         }
348 
349         if (ObjectUtils.isNotNull(poDocument.getVendorContract())) {
350             poDocument.setVendorPaymentTermsCode(poDocument.getVendorContract().getVendorPaymentTermsCode());
351             poDocument.setVendorShippingPaymentTermsCode(poDocument.getVendorContract().getVendorShippingPaymentTermsCode());
352             poDocument.setVendorShippingTitleCode(poDocument.getVendorContract().getVendorShippingTitleCode());
353         } else {
354             VendorDetail vendor = vendorService.getVendorDetail(poDocument.getVendorHeaderGeneratedIdentifier(), poDocument.getVendorDetailAssignedIdentifier());
355             if (ObjectUtils.isNotNull(vendor)) {
356                 poDocument.setVendorPaymentTermsCode(vendor.getVendorPaymentTermsCode());
357                 poDocument.setVendorShippingPaymentTermsCode(vendor.getVendorShippingPaymentTermsCode());
358                 poDocument.setVendorShippingTitleCode(vendor.getVendorShippingTitleCode());
359             }
360         }
361 
362         if (!PurapConstants.RequisitionSources.B2B.equals(poDocument.getRequisitionSourceCode())) {
363             purapService.addBelowLineItems(poDocument);
364         }
365         poDocument.fixItemReferences();
366 
367         return poDocument;
368     }
369 
370     /**
371      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#getInternalPurchasingDollarLimit(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
372      */
373     @Override
374     public KualiDecimal getInternalPurchasingDollarLimit(PurchaseOrderDocument document) {
375         if ((document.getVendorContract() != null) && (document.getContractManager() != null)) {
376             KualiDecimal contractDollarLimit = vendorService.getApoLimitFromContract(document.getVendorContract().getVendorContractGeneratedIdentifier(), document.getChartOfAccountsCode(), document.getOrganizationCode());
377             // FIXME somehow data fields such as contractManagerDelegationDollarLimit in reference object contractManager didn't get
378             // retrieved
379             // (are null) as supposed to be (this happens whether or not proxy is set to true), even though contractManager is not
380             // null;
381             // so here we have to manually refresh the contractManager to retrieve the fields
382             if (document.getContractManager().getContractManagerDelegationDollarLimit() == null) {
383                 document.refreshReferenceObject(PurapPropertyConstants.CONTRACT_MANAGER);
384             }
385             KualiDecimal contractManagerLimit = document.getContractManager().getContractManagerDelegationDollarLimit();
386             if ((contractDollarLimit != null) && (contractManagerLimit != null)) {
387                 if (contractDollarLimit.compareTo(contractManagerLimit) > 0) {
388                     return contractDollarLimit;
389                 } else {
390                     return contractManagerLimit;
391                 }
392             } else if (contractDollarLimit != null) {
393                 return contractDollarLimit;
394             } else {
395                 return contractManagerLimit;
396             }
397         } else if ((document.getVendorContract() == null) && (document.getContractManager() != null)) {
398             // FIXME As above, here we have to manually refresh the contractManager to retrieve its field
399             if (document.getContractManager().getContractManagerDelegationDollarLimit() == null) {
400                 document.refreshReferenceObject(PurapPropertyConstants.CONTRACT_MANAGER);
401             }
402             return document.getContractManager().getContractManagerDelegationDollarLimit();
403         } else if ((document.getVendorContract() != null) && (document.getContractManager() == null)) {
404             return purapService.getApoLimit(document.getVendorContract().getVendorContractGeneratedIdentifier(), document.getChartOfAccountsCode(), document.getOrganizationCode());
405         } else {
406             String errorMsg = "No internal purchase order dollar limit found for purchase order '" + document.getPurapDocumentIdentifier() + "'.";
407             LOG.warn(errorMsg);
408             return null;
409         }
410     }
411 
412     /**
413      * Loops through the collection of error messages and adding each of them to the error map.
414      *
415      * @param errorKey The resource key used to retrieve the error text from the error message resource bundle.
416      * @param errors   The collection of error messages.
417      */
418     protected void addStringErrorMessagesToMessageMap(String errorKey, Collection<String> errors) {
419         if (ObjectUtils.isNotNull(errors)) {
420             for (String error : errors) {
421                 LOG.error("Adding error message using error key '" + errorKey + "' with text '" + error + "'");
422                 GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, errorKey, error);
423             }
424         }
425     }
426 
427 
428     /**
429      * TODO RELEASE 3 - QUOTE
430      *
431      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#printPurchaseOrderQuoteRequestsListPDF(org.kuali.ole.module.purap.document.PurchaseOrderDocument,
432      * java.io.ByteArrayOutputStream)
433      */
434     @Override
435     public boolean printPurchaseOrderQuoteRequestsListPDF(String documentNumber, ByteArrayOutputStream baosPDF) {
436         PurchaseOrderDocument po = getPurchaseOrderByDocumentNumber(documentNumber);
437         String environment = kualiConfigurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
438         Collection<String> generatePDFErrors = printService.generatePurchaseOrderQuoteRequestsListPdf(po, baosPDF);
439 
440         if (generatePDFErrors.size() > 0) {
441             addStringErrorMessagesToMessageMap(PurapKeyConstants.ERROR_PURCHASE_ORDER_PDF, generatePDFErrors);
442             return false;
443         } else {
444             return true;
445         }
446     }
447 
448     /**
449      * TODO RELEASE 3 - QUOTE
450      *
451      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#printPurchaseOrderQuotePDF(org.kuali.ole.module.purap.document.PurchaseOrderDocument,
452      * org.kuali.ole.module.purap.businessobject.PurchaseOrderVendorQuote, java.io.ByteArrayOutputStream)
453      */
454     @Override
455     public boolean printPurchaseOrderQuotePDF(PurchaseOrderDocument po, PurchaseOrderVendorQuote povq, ByteArrayOutputStream baosPDF) {
456         String environment = kualiConfigurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
457         Collection<String> generatePDFErrors = printService.generatePurchaseOrderQuotePdf(po, povq, baosPDF, environment);
458 
459         if (generatePDFErrors.size() > 0) {
460             addStringErrorMessagesToMessageMap(PurapKeyConstants.ERROR_PURCHASE_ORDER_PDF, generatePDFErrors);
461             return false;
462         } else {
463             return true;
464         }
465     }
466 
467     /**
468      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#performPurchaseOrderFirstTransmitViaPrinting(java.lang.String,
469      * java.io.ByteArrayOutputStream)
470      */
471     @Override
472     public void performPurchaseOrderFirstTransmitViaPrinting(String documentNumber, ByteArrayOutputStream baosPDF) {
473         PurchaseOrderDocument po = getPurchaseOrderByDocumentNumber(documentNumber);
474         String environment = kualiConfigurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
475         Collection<String> generatePDFErrors = printService.generatePurchaseOrderPdf(po, baosPDF, environment, null);
476         if (!generatePDFErrors.isEmpty()) {
477             addStringErrorMessagesToMessageMap(PurapKeyConstants.ERROR_PURCHASE_ORDER_PDF, generatePDFErrors);
478             throw new ValidationException("printing purchase order for first transmission failed");
479         }
480         if (ObjectUtils.isNotNull(po.getPurchaseOrderFirstTransmissionTimestamp())) {
481             // should not call this method for first transmission if document has already been transmitted
482             String errorMsg = "Method to perform first transmit was called on document (doc id " + documentNumber + ") with already filled in 'first transmit date'";
483             LOG.error(errorMsg);
484             throw new RuntimeException(errorMsg);
485         }
486         Timestamp currentDate = dateTimeService.getCurrentTimestamp();
487         po.setPurchaseOrderFirstTransmissionTimestamp(currentDate);
488         po.setPurchaseOrderLastTransmitTimestamp(currentDate);
489         po.setOverrideWorkflowButtons(Boolean.FALSE);
490         boolean performedAction = purapWorkflowIntegrationService.takeAllActionsForGivenCriteria(po, "Action taken automatically as part of document initial print transmission", PurapConstants.PurchaseOrderStatuses.NODE_DOCUMENT_TRANSMISSION, GlobalVariables.getUserSession().getPerson(), null);
491         performedAction=true;
492         po.setApplicationDocumentStatus(PurapConstants.PurchaseOrderStatuses.APPDOC_OPEN);
493         if (!performedAction) {
494             Person systemUserPerson = getPersonService().getPersonByPrincipalName(getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
495             purapWorkflowIntegrationService.takeAllActionsForGivenCriteria(po, "Action taken automatically as part of document initial print transmission by user " + GlobalVariables.getUserSession().getPerson().getName(), PurapConstants.PurchaseOrderStatuses.NODE_DOCUMENT_TRANSMISSION, systemUserPerson, getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
496         }
497         po.setOverrideWorkflowButtons(Boolean.TRUE);
498         if (!po.getApplicationDocumentStatus().equals(PurapConstants.PurchaseOrderStatuses.APPDOC_OPEN)) {
499             attemptSetupOfInitialOpenOfDocument(po);
500         }
501         purapService.saveDocumentNoValidation(po);
502     }
503 
504     /**
505      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#performPurchaseOrderPreviewPrinting(java.lang.String,
506      * java.io.ByteArrayOutputStream)
507      */
508     @Override
509     public void performPurchaseOrderPreviewPrinting(String documentNumber, ByteArrayOutputStream baosPDF) {
510         performPrintPurchaseOrderPDFOnly(documentNumber, baosPDF);
511     }
512 
513     /**
514      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#performPrintPurchaseOrderPDFOnly(java.lang.String,
515      * java.io.ByteArrayOutputStream)
516      */
517     @Override
518     public void performPrintPurchaseOrderPDFOnly(String documentNumber, ByteArrayOutputStream baosPDF) {
519         PurchaseOrderDocument po = getPurchaseOrderByDocumentNumber(documentNumber);
520         String environment = kualiConfigurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
521         Collection<String> generatePDFErrors = printService.generatePurchaseOrderPdf(po, baosPDF, environment, null);
522         if (!generatePDFErrors.isEmpty()) {
523             addStringErrorMessagesToMessageMap(PurapKeyConstants.ERROR_PURCHASE_ORDER_PDF, generatePDFErrors);
524             throw new ValidationException("printing purchase order for first transmission failed");
525         }
526     }
527 
528     /**
529      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#retransmitPurchaseOrderPDF(org.kuali.ole.module.purap.document.PurchaseOrderDocument,
530      * java.io.ByteArrayOutputStream)
531      */
532     @Override
533     public void retransmitPurchaseOrderPDF(PurchaseOrderDocument po, ByteArrayOutputStream baosPDF) {
534 
535         String environment = kualiConfigurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
536         List<PurchaseOrderItem> items = po.getItems();
537         List<PurchaseOrderItem> retransmitItems = new ArrayList<PurchaseOrderItem>();
538         for (PurchaseOrderItem item : items) {
539             if (item.isItemSelectedForRetransmitIndicator()) {
540                 retransmitItems.add(item);
541             }
542         }
543         Collection<String> generatePDFErrors = printService.generatePurchaseOrderPdfForRetransmission(po, baosPDF, environment, retransmitItems);
544 
545         if (generatePDFErrors.size() > 0) {
546             addStringErrorMessagesToMessageMap(PurapKeyConstants.ERROR_PURCHASE_ORDER_PDF, generatePDFErrors);
547             throw new ValidationException("found errors while trying to print po with doc id " + po.getDocumentNumber());
548         }
549         po.setPurchaseOrderLastTransmitTimestamp(dateTimeService.getCurrentTimestamp());
550         purapService.saveDocumentNoValidation(po);
551     }
552 
553     /**
554      * This method creates a new Purchase Order Document using the given document type based off the given source document. This
555      * method will return null if the source document given is null.<br>
556      * <br>
557      * ** THIS METHOD DOES NOT SAVE EITHER THE GIVEN SOURCE DOCUMENT OR THE NEW DOCUMENT CREATED
558      *
559      * @param sourceDocument - document the new Purchase Order Document should be based off of in terms of data
560      * @param docType        - document type of the potential new Purchase Order Document
561      * @return the new Purchase Order Document of the given document type or null if the given source document is null
562      * @throws WorkflowException if a new document cannot be created using the given type
563      */
564     protected PurchaseOrderDocument createPurchaseOrderDocumentFromSourceDocument(PurchaseOrderDocument sourceDocument, String docType) throws WorkflowException {
565         if (ObjectUtils.isNull(sourceDocument)) {
566             String errorMsg = "Attempting to create new PO of type '" + docType + "' from source PO doc that is null";
567             LOG.error(errorMsg);
568             throw new RuntimeException(errorMsg);
569         }
570 
571         PurchaseOrderDocument newPurchaseOrderChangeDocument = (PurchaseOrderDocument) documentService.getNewDocument(docType);
572         newPurchaseOrderChangeDocument.setAccountDistributionMethod(sourceDocument.getAccountDistributionMethod());
573 
574         Set classesToExclude = new HashSet();
575         Class sourceObjectClass = FinancialSystemTransactionalDocumentBase.class;
576         classesToExclude.add(sourceObjectClass);
577         while (sourceObjectClass.getSuperclass() != null) {
578             sourceObjectClass = sourceObjectClass.getSuperclass();
579             classesToExclude.add(sourceObjectClass);
580         }
581         PurApObjectUtils.populateFromBaseWithSuper(sourceDocument, newPurchaseOrderChangeDocument, PurapConstants.uncopyableFieldsForPurchaseOrder(), classesToExclude);
582         newPurchaseOrderChangeDocument.getDocumentHeader().setDocumentDescription(sourceDocument.getDocumentHeader().getDocumentDescription());
583         newPurchaseOrderChangeDocument.getDocumentHeader().setOrganizationDocumentNumber(sourceDocument.getDocumentHeader().getOrganizationDocumentNumber());
584         newPurchaseOrderChangeDocument.getDocumentHeader().setExplanation(sourceDocument.getDocumentHeader().getExplanation());
585         newPurchaseOrderChangeDocument.setPurchaseOrderCurrentIndicator(false);
586         newPurchaseOrderChangeDocument.setPendingActionIndicator(false);
587 
588         // TODO f2f: what is this doing?
589         // Need to find a way to make the ManageableArrayList to expand and populating the items and
590         // accounts, otherwise it will complain about the account on item 1 is missing.
591         for (PurApItem item : (List<PurApItem>) newPurchaseOrderChangeDocument.getItems()) {
592             item.getSourceAccountingLines().iterator();
593             // we only need to do this once to apply to all items, so we can break out of the loop now
594             SequenceAccessorService sas = SpringContext.getBean(SequenceAccessorService.class);
595             Integer itemIdentifier = sas.getNextAvailableSequenceNumber("PO_ITM_ID", PurApItem.class).intValue();
596             item.setItemIdentifier(itemIdentifier);
597         }
598 
599         updateCapitalAssetRelatedCollections(newPurchaseOrderChangeDocument);
600         newPurchaseOrderChangeDocument.refreshNonUpdateableReferences();
601 
602         return newPurchaseOrderChangeDocument;
603     }
604 
605     protected void updateCapitalAssetRelatedCollections(PurchaseOrderDocument newDocument) {
606 
607         for (PurchasingCapitalAssetItem capitalAssetItem : newDocument.getPurchasingCapitalAssetItems()) {
608             Integer lineNumber = capitalAssetItem.getPurchasingItem().getItemLineNumber();
609             PurApItem newItem = newDocument.getItemByLineNumber(lineNumber.intValue());
610             capitalAssetItem.setItemIdentifier(newItem.getItemIdentifier());
611             capitalAssetItem.setPurchasingDocument(newDocument);
612             capitalAssetItem.setCapitalAssetSystemIdentifier(null);
613             CapitalAssetSystem oldSystem = capitalAssetItem.getPurchasingCapitalAssetSystem();
614             capitalAssetItem.setPurchasingCapitalAssetSystem(new PurchaseOrderCapitalAssetSystem(oldSystem));
615 
616         }
617     }
618 
619     /**
620      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#createAndSavePotentialChangeDocument(java.lang.String,
621      * java.lang.String, java.lang.String)
622      */
623     @Override
624     public PurchaseOrderDocument createAndSavePotentialChangeDocument(String documentNumber, String docType, String currentDocumentStatusCode) {
625         PurchaseOrderDocument currentDocument = getPurchaseOrderByDocumentNumber(documentNumber);
626 
627         try {
628             PurchaseOrderDocument newDocument = createPurchaseOrderDocumentFromSourceDocument(currentDocument, docType);
629 
630             if (ObjectUtils.isNotNull(newDocument)) {
631                 newDocument.updateAndSaveAppDocStatus(PurapConstants.PurchaseOrderStatuses.APPDOC_CHANGE_IN_PROCESS);
632 
633                 // set status if needed
634                 if (StringUtils.isNotBlank(currentDocumentStatusCode)) {
635                     currentDocument.updateAndSaveAppDocStatus(currentDocumentStatusCode);
636                 }
637                 try {
638                     documentService.saveDocument(newDocument, DocumentSystemSaveEvent.class);
639                 }
640                 // if we catch a ValidationException it means the new PO doc found errors
641                 catch (ValidationException ve) {
642                     throw ve;
643                 }
644                 // if no validation exception was thrown then rules have passed and we are ok to edit the current PO
645                 currentDocument.setPendingActionIndicator(true);
646                 Note note = new Note();
647                 List<Note> noteList = new ArrayList<Note>();
648                 currentDocument.setNotes(noteList);
649                 saveDocumentNoValidationUsingClearMessageMap(currentDocument);
650                 // savePurchaseOrderData(currentDocument);
651 
652                 return newDocument;
653             } else {
654                 String errorMsg = "Attempting to create new PO of type '" + docType + "' from source PO doc id "
655                         + documentNumber + " returned null for new document";
656                 LOG.error(errorMsg);
657                 throw new RuntimeException(errorMsg);
658             }
659         } catch (WorkflowException we) {
660             String errorMsg = "Workflow Exception caught trying to create and save PO document of type '" + docType
661                     + "' using source document with doc id '" + documentNumber + "'";
662             LOG.error(errorMsg, we);
663             throw new RuntimeException(errorMsg, we);
664         }
665     }
666 
667     /**
668      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#createAndRoutePotentialChangeDocument(java.lang.String,
669      * java.lang.String, java.lang.String, java.util.List, java.lang.String)
670      */
671     @Override
672     public PurchaseOrderDocument createAndRoutePotentialChangeDocument(String documentNumber, String docType, String annotation, List adhocRoutingRecipients, String currentDocumentStatusCode) {
673         PurchaseOrderDocument currentDocument = getPurchaseOrderByDocumentNumber(documentNumber);
674 
675         try {
676             currentDocument.updateAndSaveAppDocStatus(currentDocumentStatusCode);
677         } catch (WorkflowException e) {
678             throw new RuntimeException("Error saving routing data while saving document with id " + currentDocument.getDocumentNumber(), e);
679         }
680 
681         try {
682             PurchaseOrderDocument newDocument = createPurchaseOrderDocumentFromSourceDocument(currentDocument, docType);
683             // newDocument.setStatusCode(PurchaseOrderStatuses.APPDOC_CHANGE_IN_PROCESS);
684             newDocument.updateAndSaveAppDocStatus(PurapConstants.PurchaseOrderStatuses.APPDOC_CHANGE_IN_PROCESS);
685             if (ObjectUtils.isNotNull(newDocument)) {
686                 try {
687                     // set the pending indictor before routing, so that when routing is done in synch mode, the pending indicator
688                     // won't be set again after route finishes and cause inconsistency
689                     currentDocument.setPendingActionIndicator(true);
690                     documentService.routeDocument(newDocument, annotation, adhocRoutingRecipients);
691                 }
692                 // if we catch a ValidationException it means the new PO doc found errors
693                 catch (ValidationException ve) {
694                     // clear the pending indictor if an exception occurs, to leave the existing PO intact
695                     currentDocument.setPendingActionIndicator(false);
696                     //savePurchaseOrderData(currentDocument);
697                     saveDocumentNoValidationUsingClearMessageMap(currentDocument);
698                     throw ve;
699                 }
700                 return newDocument;
701             } else {
702                 String errorMsg = "Attempting to create new PO of type '" + docType + "' from source PO doc id " + documentNumber + " returned null for new document";
703                 LOG.error(errorMsg);
704                 throw new RuntimeException(errorMsg);
705             }
706         } catch (WorkflowException we) {
707             String errorMsg = "Workflow Exception caught trying to create and route PO document of type '" + docType + "' using source document with doc id '" + documentNumber + "'";
708             LOG.error(errorMsg, we);
709             throw new RuntimeException(errorMsg, we);
710         }
711     }
712 
713 
714     public PurchaseOrderDocument createAndRoutePotentialChangeDocument(OlePurchaseOrderDocument  olePurchaseOrderDocument, String docType, String annotation, List adhocRoutingRecipients, String currentDocumentStatusCode) {
715         PurchaseOrderDocument currentDocument = olePurchaseOrderDocument;
716 
717         try {
718             currentDocument.updateAndSaveAppDocStatus(currentDocumentStatusCode);
719         } catch (WorkflowException e) {
720             throw new RuntimeException("Error saving routing data while saving document with id " + currentDocument.getDocumentNumber(), e);
721         }
722 
723         try {
724             PurchaseOrderDocument newDocument = createPurchaseOrderDocumentFromSourceDocument(currentDocument, docType);
725             // newDocument.setStatusCode(PurchaseOrderStatuses.APPDOC_CHANGE_IN_PROCESS);
726             newDocument.updateAndSaveAppDocStatus(PurapConstants.PurchaseOrderStatuses.APPDOC_CHANGE_IN_PROCESS);
727             if (ObjectUtils.isNotNull(newDocument)) {
728                 try {
729                     // set the pending indictor before routing, so that when routing is done in synch mode, the pending indicator
730                     // won't be set again after route finishes and cause inconsistency
731                     currentDocument.setPendingActionIndicator(true);
732                     documentService.routeDocument(newDocument, annotation, adhocRoutingRecipients);
733                 }
734                 // if we catch a ValidationException it means the new PO doc found errors
735                 catch (ValidationException ve) {
736                     // clear the pending indictor if an exception occurs, to leave the existing PO intact
737                     currentDocument.setPendingActionIndicator(false);
738                     //savePurchaseOrderData(currentDocument);
739                     saveDocumentNoValidationUsingClearMessageMap(currentDocument);
740                     throw ve;
741                 }
742                 return newDocument;
743             } else {
744                 String errorMsg = "Attempting to create new PO of type '" + docType + "' from source PO doc id " + documentNumber + " returned null for new document";
745                 LOG.error(errorMsg);
746                 throw new RuntimeException(errorMsg);
747             }
748         } catch (WorkflowException we) {
749             String errorMsg = "Workflow Exception caught trying to create and route PO document of type '" + docType + "' using source document with doc id '" + documentNumber + "'";
750             LOG.error(errorMsg, we);
751             throw new RuntimeException(errorMsg, we);
752         }
753     }
754 
755 
756     /**
757      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#createAndSavePurchaseOrderSplitDocument(java.util.List,
758      * java.lang.String, boolean)
759      */
760     @Override
761     public PurchaseOrderSplitDocument createAndSavePurchaseOrderSplitDocument(List<PurchaseOrderItem> newPOItems, PurchaseOrderDocument currentDocument, boolean copyNotes, String splitNoteText) {
762 
763         if (ObjectUtils.isNull(currentDocument)) {
764             String errorMsg = "Attempting to create new PO of type PurchaseOrderSplitDocument from source PO doc that is null";
765             LOG.error(errorMsg);
766             throw new RuntimeException(errorMsg);
767         }
768         // Following code added to add notes to the current PO Document
769         try {
770             Note splitNote = SpringContext.getBean(DocumentService.class).createNoteFromDocument(currentDocument, splitNoteText);
771             currentDocument.addNote(splitNote);
772             noteService.save(splitNote);
773         } catch (Exception e) {
774             throw new RuntimeException(e);
775         }
776         String documentNumber = currentDocument.getDocumentNumber();
777 
778         try {
779             // Create the new Split PO document (throws WorkflowException)
780             PurchaseOrderSplitDocument newDocument = (PurchaseOrderSplitDocument) documentService.getNewDocument(PurchaseOrderDocTypes.PURCHASE_ORDER_SPLIT_DOCUMENT);
781 
782             if (ObjectUtils.isNotNull(newDocument)) {
783 
784                 // Prepare for copying fields over from the current document.
785                 Set<Class> classesToExclude = getClassesToExcludeFromCopy();
786                 Map<String, Class> uncopyableFields = PurapConstants.UNCOPYABLE_FIELDS_FOR_PO;
787                 uncopyableFields.putAll(PurapConstants.uncopyableFieldsForSplitPurchaseOrder());
788 
789                 // Copy all fields over from the current document except the items and the above-specified fields.
790                 PurApObjectUtils.populateFromBaseWithSuper(currentDocument, newDocument, uncopyableFields, classesToExclude);
791                 newDocument.getDocumentHeader().setDocumentDescription(currentDocument.getDocumentHeader().getDocumentDescription());
792                 newDocument.getDocumentHeader().setOrganizationDocumentNumber(currentDocument.getDocumentHeader().getOrganizationDocumentNumber());
793                 newDocument.setPurchaseOrderCurrentIndicator(true);
794                 newDocument.setPendingActionIndicator(false);
795 
796                 newDocument.setAccountDistributionMethod(currentDocument.getAccountDistributionMethod());
797                 // Add in and renumber the items that the new document should have.
798                 newDocument.setItems(newPOItems);
799                 purapService.addBelowLineItems(newDocument);
800                 newDocument.renumberItems(0);
801 
802                 newDocument.setPostingYear(currentDocument.getPostingYear());
803 
804                 if (copyNotes) {
805                     // Copy the old notes, except for the one that contains the split note text.
806                     List<Note> notes = currentDocument.getNotes();
807                     int noteLength = notes.size();
808                     if (noteLength > 0) {
809                         notes.subList(noteLength - 1, noteLength).clear();
810                         for (Note note : notes) {
811                             try {
812                                 Note copyingNote = documentService.createNoteFromDocument(newDocument, note.getNoteText());
813                                 newDocument.addNote(copyingNote);
814                                 noteService.save(copyingNote);
815                             } catch (Exception e) {
816                                 throw new RuntimeException(e);
817                             }
818                         }
819                     }
820                 }
821 
822                 newDocument.updateAndSaveAppDocStatus(PurapConstants.PurchaseOrderStatuses.APPDOC_IN_PROCESS);
823 
824                 // fix references before saving
825                 fixItemReferences(newDocument);
826 
827                 // need to save the document first before creating the note
828                 purapService.saveDocumentNoValidation(newDocument);
829 
830                 // Modify the split note text and add the note.
831                 splitNoteText = splitNoteText.substring(splitNoteText.indexOf(":") + 1);
832                 splitNoteText = PurapConstants.PODocumentsStrings.SPLIT_NOTE_PREFIX_NEW_DOC + currentDocument.getPurapDocumentIdentifier() + " : " + splitNoteText;
833                 try {
834                     Note splitNote = documentService.createNoteFromDocument(newDocument, splitNoteText);
835                     newDocument.addNote(splitNote);
836                     noteService.save(splitNote);
837                 } catch (Exception e) {
838                     throw new RuntimeException(e);
839                 }
840 
841                 return newDocument;
842             } else {
843                 String errorMsg = "Attempting to create new PO of type 'PurchaseOrderSplitDocument' from source PO doc id " + documentNumber + " returned null for new document";
844                 LOG.error(errorMsg);
845                 throw new RuntimeException(errorMsg);
846             }
847         } catch (WorkflowException we) {
848             String errorMsg = "Workflow Exception caught trying to create and save PO document of type PurchaseOrderSplitDocument using source document with doc id '" + documentNumber + "'";
849             LOG.error(errorMsg, we);
850             throw new RuntimeException(errorMsg, we);
851         }
852     }
853 
854     /**
855      * Gets a set of classes to exclude from those whose fields will be copied during a copy operation from one Document to another.
856      *
857      * @return A Set<Class>
858      */
859     protected Set<Class> getClassesToExcludeFromCopy() {
860         Set<Class> classesToExclude = new HashSet<Class>();
861         Class sourceObjectClass = DocumentBase.class;
862         classesToExclude.add(sourceObjectClass);
863         while (sourceObjectClass.getSuperclass() != null) {
864             sourceObjectClass = sourceObjectClass.getSuperclass();
865             classesToExclude.add(sourceObjectClass);
866         }
867         return classesToExclude;
868     }
869 
870     /**
871      * Returns the current route node name.
872      *
873      * @param wd The KualiWorkflowDocument object whose current route node we're trying to get.
874      * @return The current route node name.
875      * @throws WorkflowException
876      */
877     protected String getCurrentRouteNodeName(WorkflowDocument wd) throws WorkflowException {
878         String[] nodeNames = (String[]) wd.getNodeNames().toArray();
879         if ((nodeNames == null) || (nodeNames.length == 0)) {
880             return null;
881         } else {
882             return nodeNames[0];
883         }
884     }
885 
886     /**
887      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#completePurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
888      */
889     @Override
890     public void completePurchaseOrder(PurchaseOrderDocument po) {
891         LOG.debug("completePurchaseOrder() started");
892         setCurrentAndPendingIndicatorsForApprovedPODocuments(po);
893         setupDocumentForPendingFirstTransmission(po);
894 
895         // check thresholds to see if receiving is required for purchase order
896         if (!po.isReceivingDocumentRequiredIndicator()) {
897             setReceivingRequiredIndicatorForPurchaseOrder(po);
898         }
899 
900         // update the vendor record if the commodity code used on the PO is not already associated with the vendor.
901         updateVendorCommodityCode(po);
902 
903         // PERFORM ANY LOGIC THAT COULD POTENTIALLY CAUSE THE DOCUMENT TO FAIL BEFORE THIS LINE
904         // FOLLOWING LINES COULD INVOLVE TRANSMITTING THE PO TO THE VENDOR WHICH WILL NOT BE REVERSED IN A TRANSACTION ROLLBACK
905 
906         // if the document is set in a Pending Transmission status then don't OPEN the PO just leave it as is
907         if (!po.getRequisitionSourceCode().equalsIgnoreCase(PurapConstants.RequisitionSources.MANUAL_INGEST)) {
908             if (!(po.getOrderType().getPurchaseOrderType()).equals(OLEConstants.APPROVAL)) {
909                 List<PurApItem> items = po.getItems();
910                 fileNameList = new ArrayList();
911                 for (PurApItem item : items) {
912                     initiateTransmission(po, item);
913                 }
914                 sendEmail();
915             }
916         }
917         //initiateTransmission(po);
918 
919 
920         if (!PurchaseOrderStatuses.STATUSES_BY_TRANSMISSION_TYPE.values().contains(po.getApplicationDocumentStatus())) {
921             attemptSetupOfInitialOpenOfDocument(po);
922         } else if (PurchaseOrderStatuses.APPDOC_PENDING_CXML.equals(po.getApplicationDocumentStatus())) {
923             completeB2BPurchaseOrder(po);
924         } else if (PurchaseOrderStatuses.APPDOC_PENDING_PRINT.equals(po.getApplicationDocumentStatus())) {
925             // default to using user that routed PO
926             String userToRouteFyi = po.getDocumentHeader().getWorkflowDocument().getRoutedByPrincipalId();
927             if (po.getPurchaseOrderAutomaticIndicator()) {
928                 // if APO, use the user that initiated the requisition
929                 RequisitionDocument req = requisitionService.getRequisitionById(po.getRequisitionIdentifier());
930                 userToRouteFyi = req.getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId();
931             }
932 
933             po.getDocumentHeader().getWorkflowDocument().adHocToPrincipal(ActionRequestType.FYI, po.getDocumentHeader().getWorkflowDocument().getCurrentNodeNames().iterator().next(), "This PO is ready for printing and distribution.", userToRouteFyi, "", true, "PRINT");
934         }
935 
936     }
937 
938 
939     protected boolean completeB2BPurchaseOrder(PurchaseOrderDocument po) {
940         String errors = b2bPurchaseOrderService.sendPurchaseOrder(po);
941         if (StringUtils.isEmpty(errors)) {
942             // PO sent successfully; change status to OPEN
943             attemptSetupOfInitialOpenOfDocument(po);
944             po.setPurchaseOrderLastTransmitTimestamp(dateTimeService.getCurrentTimestamp());
945             return true;
946         } else {
947             // PO transmission failed; record errors and change status to "cxml failed"
948             try {
949                 String noteText = "Unable to transmit the PO for the following reasons:\n" + errors;
950                 int noteMaxSize = dataDictionaryService.getAttributeMaxLength("Note", "noteText");
951 
952                 // Break up the note into multiple pieces if the note is too large to fit in the database field.
953                 while (noteText.length() > noteMaxSize) {
954                     int fromIndex = 0;
955                     String noteText1 = noteText.substring(0, noteMaxSize);
956                     Note note1 = documentService.createNoteFromDocument(po, noteText1);
957                     po.addNote(note1);
958                     documentService.saveDocumentNotes(po);
959                     noteText = noteText.substring(noteMaxSize);
960                 }
961 
962                 Note note = documentService.createNoteFromDocument(po, noteText);
963                 po.addNote(note);
964                 documentService.saveDocumentNotes(po);
965             } catch (Exception e) {
966                 throw new RuntimeException(e);
967             }
968 
969             try {
970                 po.updateAndSaveAppDocStatus(PurchaseOrderStatuses.APPDOC_CXML_ERROR);
971             } catch (WorkflowException e) {
972                 throw new RuntimeException("Error saving routing data while saving document with id " + po.getDocumentNumber(), e);
973             }
974 
975             return false;
976         }
977     }
978 
979     @Override
980     public void retransmitB2BPurchaseOrder(PurchaseOrderDocument po) {
981         if (completeB2BPurchaseOrder(po)) {
982             KNSGlobalVariables.getMessageList().add(PurapKeyConstants.B2B_PO_RETRANSMIT_SUCCESS);
983         } else {
984             GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PurapKeyConstants.B2B_PO_RETRANSMIT_FAILED);
985         }
986         purapService.saveDocumentNoValidation(po);
987     }
988 
989     @Override
990     public void completePurchaseOrderAmendment(PurchaseOrderDocument poa) {
991         LOG.debug("completePurchaseOrderAmendment() started");
992 
993         setCurrentAndPendingIndicatorsForApprovedPODocuments(poa);
994 
995         if (SpringContext.getBean(PaymentRequestService.class).hasActivePaymentRequestsForPurchaseOrder(poa.getPurapDocumentIdentifier())) {
996             poa.setPaymentRequestPositiveApprovalIndicator(true);
997             poa.setReceivingDocumentRequiredIndicator(false);
998         }
999         // check thresholds to see if receiving is required for purchase order amendment
1000         if (!poa.isReceivingDocumentRequiredIndicator() &&
1001                 !SpringContext.getBean(PaymentRequestService.class).hasActivePaymentRequestsForPurchaseOrder(poa.getPurapDocumentIdentifier())) {
1002             setReceivingRequiredIndicatorForPurchaseOrder(poa);
1003         }
1004 
1005         // if unordered items have been added to the PO then send an FYI to all fiscal officers
1006         if (hasNewUnorderedItem(poa)) {
1007             sendFyiForNewUnorderedItems(poa);
1008         }
1009         DocumentRouteHeaderValue routeHeader = ((RouteHeaderService) KEWServiceLocator.getService(KEWServiceLocator.DOC_ROUTE_HEADER_SRV)).getRouteHeader(poa.getDocumentNumber());
1010         String status = routeHeader.getDocRouteStatus();
1011         if (status.equals(KewApiConstants.ROUTE_HEADER_PROCESSED_CD)) {
1012             List<PurApItem> items = poa.getItems();
1013             for (PurApItem item : items) {
1014                 initiateTransmission(poa, item);
1015             }
1016             //initiateTransmission(poa);
1017         }
1018 
1019     }
1020 
1021     /**
1022      * If there are commodity codes on the items on the PurchaseOrderDocument that haven't existed yet on the vendor that the
1023      * PurchaseOrderDocument is using, then we will spawn a new VendorDetailMaintenanceDocument automatically to update the vendor
1024      * with the commodity codes that aren't already existing on the vendor.
1025      *
1026      * @param po The PurchaseOrderDocument containing the vendor that we want to update.
1027      */
1028     @Override
1029     public void updateVendorCommodityCode(PurchaseOrderDocument po) {
1030         String noteText = "";
1031         VendorDetail oldVendorDetail = po.getVendorDetail();
1032         VendorDetail newVendorDetail = updateVendorWithMissingCommodityCodesIfNecessary(po);
1033         if (newVendorDetail != null) {
1034             try {
1035                 // spawn a new vendor maintenance document to add the note
1036                 MaintenanceDocument vendorMaintDoc = null;
1037                 try {
1038                     vendorMaintDoc = (MaintenanceDocument) documentService.getNewDocument("PVEN");
1039                     vendorMaintDoc.getDocumentHeader().setDocumentDescription("Automatically spawned from PO");
1040                     vendorMaintDoc.getOldMaintainableObject().setBusinessObject(oldVendorDetail);
1041                     vendorMaintDoc.getNewMaintainableObject().setBusinessObject(newVendorDetail);
1042                     vendorMaintDoc.getNewMaintainableObject().setMaintenanceAction(OLEConstants.MAINTENANCE_EDIT_ACTION);
1043                     vendorMaintDoc.getNewMaintainableObject().setDocumentNumber(vendorMaintDoc.getDocumentNumber());
1044                     boolean isVendorLocked = checkForLockingDocument(vendorMaintDoc);
1045                     if (!isVendorLocked) {
1046                         // validating vendor doc to capture exception before trying to route which if exception happens in
1047                         // docService, then PO will fail too
1048                         vendorMaintDoc.validateBusinessRules(new RouteDocumentEvent(vendorMaintDoc));
1049                         addNoteForCommodityCodeToVendor(vendorMaintDoc.getNewMaintainableObject(), vendorMaintDoc.getDocumentNumber(), po.getPurapDocumentIdentifier());
1050                         documentService.routeDocument(vendorMaintDoc, null, null);
1051                     } else {
1052                         // Add a note to the PO to tell the users that we can't automatically update the vendor because it's locked.
1053                         noteText = "Unable to automatically update vendor because it is locked";
1054                     }
1055                 } catch (Exception e) {
1056                     if (ObjectUtils.isNull(vendorMaintDoc)) {
1057                         noteText = "Unable to create a new VendorDetailMaintenanceDocument to update the vendor with new commodity codes";
1058                     } else {
1059                         noteText = "Unable to route a new VendorDetailMaintenanceDocument to update the vendor with new commodity codes";
1060                     }
1061                 } finally {
1062                     if (StringUtils.isNotBlank(noteText)) {
1063                         // update on purchase order notes
1064                         Note note = documentService.createNoteFromDocument(po, noteText);
1065                         po.addNote(note);
1066                         noteService.save(note);
1067                     }
1068                 }
1069             } catch (Exception e) {
1070                 LOG.error("updateVendorCommodityCode() unable to add a note(" + noteText + ") to PO document " + po.getDocumentNumber());
1071                 throw new RuntimeException(e);
1072             }
1073         }
1074     }
1075 
1076     /**
1077      * Creates a note to be added to the Vendor Maintenance Document which is spawned from the PurchaseOrderDocument.
1078      *
1079      * @param maintainable
1080      * @param documentNumber
1081      * @param poID
1082      */
1083     protected void addNoteForCommodityCodeToVendor(Maintainable maintainable, String documentNumber, Integer poID) {
1084         Note newBONote = new Note();
1085         newBONote.setNoteText("Change vendor document ID <" + documentNumber + ">. Document was automatically created from PO <" + poID + "> to add commodity codes used on this PO that were not yet assigned to this vendor.");
1086         try {
1087 
1088             newBONote = noteService.createNote(newBONote, maintainable.getBusinessObject(), GlobalVariables.getUserSession().getPrincipalId());
1089             newBONote.setNotePostedTimestampToCurrent();
1090         } catch (Exception e) {
1091             throw new RuntimeException("Caught Exception While Trying To Add Note to Vendor", e);
1092         }
1093         List<Note> noteList = noteService.getByRemoteObjectId(maintainable.getBusinessObject().getObjectId());
1094         noteList.add(newBONote);
1095         noteService.saveNoteList(noteList);
1096     }
1097 
1098     /**
1099      * Checks whether the vendor is currently locked.
1100      *
1101      * @param document The MaintenanceDocument containing the vendor.
1102      * @return boolean true if the vendor is currently locked and false otherwise.
1103      */
1104     protected boolean checkForLockingDocument(MaintenanceDocument document) {
1105         String blockingDocId = maintenanceDocumentService.getLockingDocumentId(document);
1106         if (StringUtils.isBlank(blockingDocId)) {
1107             return false;
1108         } else {
1109             return true;
1110         }
1111     }
1112 
1113     /**
1114      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#updateVendorWithMissingCommodityCodesIfNecessary(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1115      */
1116     @Override
1117     public VendorDetail updateVendorWithMissingCommodityCodesIfNecessary(PurchaseOrderDocument po) {
1118         List<CommodityCode> result = new ArrayList<CommodityCode>();
1119         boolean foundDefault = false;
1120         VendorDetail vendor = (VendorDetail) ObjectUtils.deepCopy(po.getVendorDetail());
1121         for (PurchaseOrderItem item : (List<PurchaseOrderItem>) po.getItems()) {
1122             // Only check on commodity codes if the item is active and is above the line item type.
1123             if (item.getItemType().isLineItemIndicator() && item.isItemActiveIndicator()) {
1124                 CommodityCode cc = item.getCommodityCode();
1125                 if (cc != null && !result.contains(cc)) {
1126                     List<VendorCommodityCode> vendorCommodityCodes = po.getVendorDetail().getVendorCommodities();
1127                     boolean foundMatching = false;
1128                     for (VendorCommodityCode vcc : vendorCommodityCodes) {
1129                         if (vcc.getCommodityCode().getPurchasingCommodityCode().equals(cc.getPurchasingCommodityCode())) {
1130                             foundMatching = true;
1131                         }
1132                         if (!foundDefault && vcc.isCommodityDefaultIndicator()) {
1133                             foundDefault = true;
1134                         }
1135                     }
1136                     if (!foundMatching) {
1137                         result.add(cc);
1138                         VendorCommodityCode vcc = new VendorCommodityCode(vendor.getVendorHeaderGeneratedIdentifier(), vendor.getVendorDetailAssignedIdentifier(), cc, true);
1139                         vcc.setActive(true);
1140                         if (!foundDefault) {
1141                             vcc.setCommodityDefaultIndicator(true);
1142                             foundDefault = true;
1143                         }
1144                         vendor.getVendorCommodities().add(vcc);
1145                     }
1146                 }
1147             }
1148         }
1149         if (result.size() > 0) {
1150             // We also have to add to the old vendor detail's vendorCommodities if we're adding to the new
1151             // vendor detail's vendorCommodities.
1152             for (int i = 0; i < result.size(); i++) {
1153                 po.getVendorDetail().getVendorCommodities().add(new VendorCommodityCode());
1154             }
1155             return vendor;
1156         } else {
1157             return null;
1158         }
1159     }
1160 
1161     /**
1162      * Update the purchase order document with the appropriate status for pending first transmission based on the transmission type.
1163      *
1164      * @param po The purchase order document whose status to be updated.
1165      */
1166     protected void setupDocumentForPendingFirstTransmission(PurchaseOrderDocument po) {
1167         if (POTransmissionMethods.PRINT.equals(po.getPurchaseOrderTransmissionMethodCode()) || POTransmissionMethods.FAX.equals(po.getPurchaseOrderTransmissionMethodCode()) || POTransmissionMethods.ELECTRONIC.equals(po.getPurchaseOrderTransmissionMethodCode())) {
1168             String newStatusCode = PurchaseOrderStatuses.STATUSES_BY_TRANSMISSION_TYPE.get(po.getPurchaseOrderTransmissionMethodCode());
1169             if (LOG.isDebugEnabled()) {
1170                 LOG.debug("setupDocumentForPendingFirstTransmission() Purchase Order Transmission Type is '" + po.getPurchaseOrderTransmissionMethodCode() + "' setting status to '" + newStatusCode + "'");
1171             }
1172             try {
1173                 po.updateAndSaveAppDocStatus(newStatusCode);
1174             } catch (WorkflowException e) {
1175                 throw new RuntimeException("Error saving routing data while saving document with id " + po.getDocumentNumber(), e);
1176             }
1177         }
1178     }
1179 
1180     /**
1181      * If the status of the purchase order is not OPEN and the initial open date is null, sets the initial open date to current date
1182      * and update the status to OPEN, then save the purchase order.
1183      *
1184      * @param po The purchase order document whose initial open date and status we want to update.
1185      */
1186     protected void attemptSetupOfInitialOpenOfDocument(PurchaseOrderDocument po) {
1187         if (LOG.isInfoEnabled()) {
1188             LOG.info("attemptSetupOfInitialOpenOfDocument() started using document with doc id " + po.getDocumentNumber());
1189         }
1190 
1191         if (!PurchaseOrderStatuses.APPDOC_OPEN.equals(po.getApplicationDocumentStatus())) {
1192             if (ObjectUtils.isNull(po.getPurchaseOrderInitialOpenTimestamp())) {
1193                 LOG.debug("attemptSetupOfInitialOpenOfDocument() setting initial open date on document");
1194                 po.setPurchaseOrderInitialOpenTimestamp(dateTimeService.getCurrentTimestamp());
1195             } else {
1196                 throw new RuntimeException("Document does not have status code '" + PurchaseOrderStatuses.APPDOC_OPEN + "' on it but value of initial open date is " + po.getPurchaseOrderInitialOpenTimestamp());
1197             }
1198             LOG.info("attemptSetupOfInitialOpenOfDocument() Setting po document id " + po.getDocumentNumber() + " status from '" + po.getApplicationDocumentStatus() + "' to '" + PurchaseOrderStatuses.APPDOC_OPEN + "'");
1199             try {
1200                 po.updateAndSaveAppDocStatus(PurchaseOrderStatuses.APPDOC_OPEN);
1201             } catch (WorkflowException we) {
1202                 throw new RuntimeException("Unable to load a WorkflowDocument object for " + po.getDocumentNumber(), we);
1203             }
1204             po.setApplicationDocumentStatus(PurchaseOrderStatuses.APPDOC_OPEN);
1205             // no need to save here because calling class should handle the save if needed
1206         }
1207 
1208         // Modified for jira OLE-2478
1209         /*else {
1210             LOG.error("attemptSetupOfInitialOpenOfDocument() Found document already in '" + PurchaseOrderStatuses.OPEN + "' status for PO#" + po.getPurapDocumentIdentifier() + "; will not change or update");
1211         }*/
1212     }
1213 
1214     /**
1215      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#getCurrentPurchaseOrder(java.lang.Integer)
1216      */
1217     @Override
1218     public PurchaseOrderDocument getCurrentPurchaseOrder(Integer id) {
1219         return getPurchaseOrderByDocumentNumber(purchaseOrderDao.getDocumentNumberForCurrentPurchaseOrder(id));
1220         // TODO hjs: code review (why is this DB call so complicated? wouldn't this method be cleaner and less db calls?)
1221         // return purchaseOrderDao.getCurrentPurchaseOrder(id);
1222     }
1223 
1224     /**
1225      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#getPurchaseOrderByDocumentNumber(java.lang.String)
1226      */
1227     @Override
1228     public PurchaseOrderDocument getPurchaseOrderByDocumentNumber(String documentNumber) {
1229         if (ObjectUtils.isNotNull(documentNumber)) {
1230             try {
1231                 PurchaseOrderDocument doc = (PurchaseOrderDocument) documentService.getByDocumentHeaderId(documentNumber);
1232                 if (ObjectUtils.isNotNull(doc)) {
1233                     WorkflowDocument workflowDocument = doc.getDocumentHeader().getWorkflowDocument();
1234                     doc.refreshReferenceObject(OLEPropertyConstants.DOCUMENT_HEADER);
1235                     doc.getDocumentHeader().setWorkflowDocument(workflowDocument);
1236                 }
1237                 return doc;
1238             } catch (WorkflowException e) {
1239                 String errorMessage = "Error getting purchase order document from document service";
1240                 LOG.error("getPurchaseOrderByDocumentNumber() " + errorMessage, e);
1241                 throw new RuntimeException(errorMessage, e);
1242             }
1243         }
1244         return null;
1245     }
1246 
1247     /**
1248      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#getOldestPurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument,
1249      * org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1250      */
1251     @Override
1252     public PurchaseOrderDocument getOldestPurchaseOrder(PurchaseOrderDocument po, PurchaseOrderDocument documentBusinessObject) {
1253         LOG.debug("entering getOldestPO(PurchaseOrderDocument)");
1254         if (ObjectUtils.isNotNull(po)) {
1255             String oldestDocumentNumber = purchaseOrderDao.getOldestPurchaseOrderDocumentNumber(po.getPurapDocumentIdentifier());
1256             // OLEMI-9746 -- See Harsha's comments...
1257             if (StringUtils.isBlank(oldestDocumentNumber)) {
1258                 return null;
1259             }
1260             if (StringUtils.equals(oldestDocumentNumber, po.getDocumentNumber())) {
1261                 // manually set bo notes - this is mainly done for performance reasons (preferably we could call
1262                 // retrieve doc notes in PersistableBusinessObjectBase but that is protected)
1263                 updateNotes(po, documentBusinessObject);
1264                 LOG.debug("exiting getOldestPO(PurchaseOrderDocument)");
1265                 return po;
1266             } else {
1267                 PurchaseOrderDocument oldestPurchaseOrder = getPurchaseOrderByDocumentNumber(oldestDocumentNumber);
1268                 updateNotes(oldestPurchaseOrder, documentBusinessObject);
1269                 LOG.debug("exiting getOldestPO(PurchaseOrderDocument)");
1270                 return oldestPurchaseOrder;
1271             }
1272         }
1273         return null;
1274     }
1275 
1276     /**
1277      * If the purchase order's object id is not null (I think this means if it's an existing purchase order that had already been
1278      * saved to the db previously), get the notes of the purchase order from the database, fix the notes' fields by calling the
1279      * fixDbNoteFields, then set the notes to the purchase order. Otherwise (I think this means if it's a new purchase order), set
1280      * the notes of this purchase order to be the notes of the documentBusinessObject.
1281      *
1282      * @param po                     The current purchase order.
1283      * @param documentBusinessObject The oldest purchase order whose purapDocumentIdentifier is the same as the po's
1284      *                               purapDocumentIdentifier.
1285      */
1286     protected void updateNotes(PurchaseOrderDocument po, PurchaseOrderDocument documentBusinessObject) {
1287         if (ObjectUtils.isNotNull(documentBusinessObject)) {
1288             if (ObjectUtils.isNotNull(po.getObjectId())) {
1289                 List<Note> dbNotes = noteService.getByRemoteObjectId(po.getObjectId());
1290                 // need to set fields that are not ojb managed (i.e. the notes on the documentBusinessObject may have been modified
1291                 // independently of the ones in the db)
1292                 fixDbNoteFields(documentBusinessObject, dbNotes);
1293                 po.setNotes(dbNotes);
1294             } else {
1295                 po.setNotes(documentBusinessObject.getNotes());
1296             }
1297         }
1298     }
1299 
1300     /**
1301      * This method fixes non ojb managed missing fields from the db
1302      *
1303      * @param documentBusinessObject The oldest purchase order whose purapDocumentIdentifier is the same as the po's
1304      *                               purapDocumentIdentifier.
1305      * @param dbNotes                The notes of the purchase order obtained from the database.
1306      */
1307     protected void fixDbNoteFields(PurchaseOrderDocument documentBusinessObject, List<Note> dbNotes) {
1308         for (int i = 0; i < dbNotes.size(); i++) {
1309             Note dbNote = dbNotes.get(i);
1310             List<Note> currentNotes = documentBusinessObject.getNotes();
1311             if (i < currentNotes.size()) {
1312                 Note currentNote = (currentNotes).get(i);
1313                 // set the fyi from the current note if not empty
1314                 AdHocRouteRecipient fyiNoteRecipient = currentNote.getAdHocRouteRecipient();
1315                 if (ObjectUtils.isNotNull(fyiNoteRecipient)) {
1316                     dbNote.setAdHocRouteRecipient(fyiNoteRecipient);
1317                 }
1318             }
1319         }
1320     }
1321 
1322     /**
1323      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#getPurchaseOrderNotes(java.lang.Integer)
1324      */
1325     @Override
1326     public List<Note> getPurchaseOrderNotes(Integer id) {
1327         List<Note> notes = new ArrayList<Note>();
1328 
1329         PurchaseOrderDocument po = getPurchaseOrderByDocumentNumber(purchaseOrderDao.getOldestPurchaseOrderDocumentNumber(id));
1330         if (ObjectUtils.isNotNull(po)) {
1331             notes = noteService.getByRemoteObjectId(po.getObjectId());
1332         }
1333         return notes;
1334     }
1335 
1336     /**
1337      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#setCurrentAndPendingIndicatorsForApprovedPODocuments(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1338      */
1339     @Override
1340     public void setCurrentAndPendingIndicatorsForApprovedPODocuments(PurchaseOrderDocument newPO) {
1341 
1342         // if(newPO.getPurapDocumentIdentifier() == null)
1343         // return;
1344 
1345         // Get the "current PO" that's in the database, i.e. the PO row that contains current indicator = Y
1346         PurchaseOrderDocument oldPO = getCurrentPurchaseOrder(newPO.getPurapDocumentIdentifier());
1347 
1348         if (oldPO == null) {
1349             return;
1350         }
1351 
1352         // If the document numbers between the oldPO and the newPO are different, then this is a PO change document.
1353         if (!oldPO.getDocumentNumber().equals(newPO.getDocumentNumber())) {
1354             // First, we set the indicators for the oldPO to : Current = N and Pending = N
1355             oldPO.setPurchaseOrderCurrentIndicator(false);
1356             oldPO.setPendingActionIndicator(false);
1357 
1358             // set the status and status history of the oldPO to retired version
1359             try {
1360                 oldPO.updateAndSaveAppDocStatus(PurapConstants.PurchaseOrderStatuses.APPDOC_RETIRED_VERSION);
1361             } catch (WorkflowException e) {
1362                 throw new RuntimeException("Error saving routing data while saving document with id " + oldPO.getDocumentNumber(), e);
1363             }
1364 
1365             saveDocumentNoValidationUsingClearMessageMap(oldPO);
1366         }
1367         if (!oldPO.getVendorDetail().getVendorHeaderGeneratedIdentifier().equals(newPO.getVendorDetail().getVendorHeaderGeneratedIdentifier())) {
1368             List<PurApItem> items = oldPO.getItems();
1369             for (PurApItem item : items) {
1370                 initiateTransmission(oldPO, item);
1371             }
1372             // initiateTransmission(oldPO);
1373         }
1374         // Now, we set the "new PO" indicators so that Current = Y and Pending = N
1375         newPO.setPurchaseOrderCurrentIndicator(true);
1376         newPO.setPendingActionIndicator(false);
1377 
1378         // this was never being saved. Should call the method to save the newPO.
1379         // saveDocumentNoValidationUsingClearMessageMap(newPO);
1380     }
1381 
1382     /**
1383      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#setCurrentAndPendingIndicatorsForDisapprovedChangePODocuments(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1384      */
1385     @Override
1386     public void setCurrentAndPendingIndicatorsForDisapprovedChangePODocuments(PurchaseOrderDocument newPO) {
1387         updateCurrentDocumentForNoPendingAction(newPO, PurapConstants.PurchaseOrderStatuses.APPDOC_DISAPPROVED_CHANGE, PurapConstants.PurchaseOrderStatuses.APPDOC_OPEN);
1388     }
1389 
1390     /**
1391      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#setCurrentAndPendingIndicatorsForCancelledChangePODocuments(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1392      */
1393     @Override
1394     public void setCurrentAndPendingIndicatorsForCancelledChangePODocuments(PurchaseOrderDocument newPO) {
1395         updateCurrentDocumentForNoPendingAction(newPO, PurapConstants.PurchaseOrderStatuses.APPDOC_CANCELLED_CHANGE, PurapConstants.PurchaseOrderStatuses.APPDOC_OPEN);
1396     }
1397 
1398     /**
1399      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#setCurrentAndPendingIndicatorsForCancelledReopenPODocuments(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1400      */
1401     @Override
1402     public void setCurrentAndPendingIndicatorsForCancelledReopenPODocuments(PurchaseOrderDocument newPO) {
1403         updateCurrentDocumentForNoPendingAction(newPO, PurapConstants.PurchaseOrderStatuses.APPDOC_CANCELLED_CHANGE, PurapConstants.PurchaseOrderStatuses.APPDOC_CLOSED);
1404     }
1405 
1406     /**
1407      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#setCurrentAndPendingIndicatorsForDisapprovedReopenPODocuments(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1408      */
1409     @Override
1410     public void setCurrentAndPendingIndicatorsForDisapprovedReopenPODocuments(PurchaseOrderDocument newPO) {
1411         updateCurrentDocumentForNoPendingAction(newPO, PurapConstants.PurchaseOrderStatuses.APPDOC_DISAPPROVED_CHANGE, PurapConstants.PurchaseOrderStatuses.APPDOC_CLOSED);
1412     }
1413 
1414     /**
1415      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#setCurrentAndPendingIndicatorsForCancelledRemoveHoldPODocuments(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1416      */
1417     @Override
1418     public void setCurrentAndPendingIndicatorsForCancelledRemoveHoldPODocuments(PurchaseOrderDocument newPO) {
1419         updateCurrentDocumentForNoPendingAction(newPO, PurapConstants.PurchaseOrderStatuses.APPDOC_CANCELLED_CHANGE, PurapConstants.PurchaseOrderStatuses.APPDOC_PAYMENT_HOLD);
1420     }
1421 
1422     /**
1423      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#setCurrentAndPendingIndicatorsForDisapprovedRemoveHoldPODocuments(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1424      */
1425     @Override
1426     public void setCurrentAndPendingIndicatorsForDisapprovedRemoveHoldPODocuments(PurchaseOrderDocument newPO) {
1427         updateCurrentDocumentForNoPendingAction(newPO, PurapConstants.PurchaseOrderStatuses.APPDOC_DISAPPROVED_CHANGE, PurapConstants.PurchaseOrderStatuses.APPDOC_PAYMENT_HOLD);
1428     }
1429 
1430     /**
1431      * Update the statuses of both the old purchase order and the new purchase orders, then save the old and the new purchase
1432      * orders.
1433      *
1434      * @param newPO       The new change purchase order document (e.g. the PurchaseOrderAmendmentDocument that was resulted from the user
1435      *                    clicking on the amend button).
1436      * @param newPOStatus The status to be set on the new change purchase order document.
1437      * @param oldPOStatus The status to be set on the existing (old) purchase order document.
1438      */
1439     protected void updateCurrentDocumentForNoPendingAction(PurchaseOrderDocument newPO, String newPOStatus, String oldPOStatus) {
1440         // Get the "current PO" that's in the database, i.e. the PO row that contains current indicator = Y
1441         PurchaseOrderDocument oldPO = getCurrentPurchaseOrder(newPO.getPurapDocumentIdentifier());
1442         // Set the Pending indicator for the oldPO to N
1443         oldPO.setPendingActionIndicator(false);
1444         try {
1445             oldPO.updateAndSaveAppDocStatus(oldPOStatus);
1446             newPO.updateAndSaveAppDocStatus(newPOStatus);
1447         } catch (WorkflowException e) {
1448             throw new RuntimeException("Error saving routing data while saving document", e);
1449         }
1450 
1451         // savePurchaseOrderData(oldPO);
1452         saveDocumentNoValidationUsingClearMessageMap(oldPO);
1453         saveDocumentNoValidationUsingClearMessageMap(newPO);
1454     }
1455 
1456     @Override
1457     public List<PurchaseOrderQuoteStatus> getPurchaseOrderQuoteStatusCodes() {
1458         List<PurchaseOrderQuoteStatus> poQuoteStatuses = new ArrayList<PurchaseOrderQuoteStatus>();
1459         poQuoteStatuses = (List<PurchaseOrderQuoteStatus>) businessObjectService.findAll(PurchaseOrderQuoteStatus.class);
1460         return poQuoteStatuses;
1461     }
1462 
1463     @Override
1464     public void setReceivingRequiredIndicatorForPurchaseOrder(PurchaseOrderDocument po) {
1465         ThresholdHelper thresholdHelper = new ThresholdHelper(po);
1466         boolean result = thresholdHelper.isReceivingDocumentRequired();
1467         if (result) {
1468             ThresholdSummary thresholdSummary = thresholdHelper.getThresholdSummary();
1469             ReceivingThreshold receivingThreshold = thresholdHelper.getReceivingThreshold();
1470             po.setReceivingDocumentRequiredIndicator(true);
1471 
1472             String notetxt = "Receiving is set to be required because the threshold summary with a total amount of " + thresholdSummary.getTotalAmount();
1473             notetxt += " exceeds the receiving threshold of " + receivingThreshold.getThresholdAmount();
1474             notetxt += " with respect to the threshold criteria ";
1475 
1476             if (thresholdSummary.getThresholdCriteria() == ThresholdHelper.CHART) {
1477                 notetxt += " Chart " + receivingThreshold.getChartOfAccountsCode();
1478             } else if (thresholdSummary.getThresholdCriteria() == ThresholdHelper.CHART_AND_ACCOUNTTYPE) {
1479                 notetxt += " Chart " + receivingThreshold.getChartOfAccountsCode();
1480                 notetxt += " - Account Type " + receivingThreshold.getAccountTypeCode();
1481             } else if (thresholdSummary.getThresholdCriteria() == ThresholdHelper.CHART_AND_SUBFUND) {
1482                 notetxt += " Chart " + receivingThreshold.getChartOfAccountsCode();
1483                 notetxt += " - Sub-Fund " + receivingThreshold.getSubFundGroupCode();
1484             } else if (thresholdSummary.getThresholdCriteria() == ThresholdHelper.CHART_AND_COMMODITYCODE) {
1485                 notetxt += " Chart " + receivingThreshold.getChartOfAccountsCode();
1486                 notetxt += " - Commodity Code " + receivingThreshold.getPurchasingCommodityCode();
1487             } else if (thresholdSummary.getThresholdCriteria() == ThresholdHelper.CHART_AND_OBJECTCODE) {
1488                 notetxt += " Chart " + receivingThreshold.getChartOfAccountsCode();
1489                 notetxt += " - Object code " + receivingThreshold.getFinancialObjectCode();
1490             } else if (thresholdSummary.getThresholdCriteria() == ThresholdHelper.CHART_AND_ORGANIZATIONCODE) {
1491                 notetxt += " Chart " + receivingThreshold.getChartOfAccountsCode();
1492                 notetxt += " - Organization " + receivingThreshold.getOrganizationCode();
1493             } else if (thresholdSummary.getThresholdCriteria() == ThresholdHelper.CHART_AND_VENDOR) {
1494                 notetxt += " Chart " + receivingThreshold.getChartOfAccountsCode();
1495                 notetxt += " - Vendor " + receivingThreshold.getVendorNumber();
1496             }
1497 
1498             try {
1499                 Note note = documentService.createNoteFromDocument(po, notetxt);
1500 //                documentService.addNoteToDocument(po, note);
1501                 noteService.save(note);
1502             } catch (Exception e) {
1503                 throw new RuntimeException(e);
1504             }
1505         }
1506     }
1507 
1508     /**
1509      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#hasNewUnorderedItem(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
1510      */
1511     @Override
1512     public boolean hasNewUnorderedItem(PurchaseOrderDocument po) {
1513 
1514         boolean itemAdded = false;
1515 
1516         for (PurchaseOrderItem poItem : (List<PurchaseOrderItem>) po.getItems()) {
1517             // only check, active, above the line, unordered items
1518             if (poItem.isItemActiveIndicator() && poItem.getItemType().isLineItemIndicator() && PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE.equals(poItem.getItemTypeCode())) {
1519 
1520                 // if the item identifier is null its new, or if the item doesn't exist on the current purchase order it's new
1521                 if (poItem.getItemIdentifier() == null || !purchaseOrderDao.itemExistsOnPurchaseOrder(poItem.getItemLineNumber(), purchaseOrderDao.getDocumentNumberForCurrentPurchaseOrder(po.getPurapDocumentIdentifier()))) {
1522                     itemAdded = true;
1523                     break;
1524                 }
1525             }
1526         }
1527 
1528         return itemAdded;
1529     }
1530 
1531     @Override
1532     public boolean isNewUnorderedItem(PurchaseOrderItem poItem) {
1533 
1534         boolean itemAdded = false;
1535 
1536         // only check, active, above the line, unordered items
1537         if (poItem.isItemActiveIndicator() && poItem.getItemType().isLineItemIndicator() && PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE.equals(poItem.getItemTypeCode())) {
1538 
1539             // if the item identifier is null its new, or if the item doesn't exist on the current purchase order it's new
1540             if (poItem.getItemIdentifier() == null || !purchaseOrderDao.itemExistsOnPurchaseOrder(poItem.getItemLineNumber(), purchaseOrderDao.getDocumentNumberForCurrentPurchaseOrder(poItem.getPurchaseOrder().getPurapDocumentIdentifier()))) {
1541                 itemAdded = true;
1542             }
1543         }
1544 
1545         return itemAdded;
1546     }
1547 
1548     @Override
1549     public boolean isNewItemForAmendment(PurchaseOrderItem poItem) {
1550 
1551         boolean itemAdded = false;
1552 
1553         // only check, active, above the line, unordered items
1554         if (poItem.isItemActiveIndicator() && poItem.getItemType().isLineItemIndicator()) {
1555 
1556             // if the item identifier is null its new, or if the item doesn't exist on the current purchase order it's new
1557             if (poItem.getItemIdentifier() == null || !purchaseOrderDao.itemExistsOnPurchaseOrder(poItem.getItemLineNumber(), purchaseOrderDao.getDocumentNumberForCurrentPurchaseOrder(poItem.getPurchaseOrder().getPurapDocumentIdentifier()))) {
1558                 itemAdded = true;
1559             }
1560         }
1561 
1562         return itemAdded;
1563     }
1564 
1565     /**
1566      * Sends an FYI to fiscal officers for new unordered items.
1567      *
1568      * @param po
1569      */
1570     protected void sendFyiForNewUnorderedItems(PurchaseOrderDocument po) {
1571 
1572         List<AdHocRoutePerson> fyiList = createFyiFiscalOfficerListForNewUnorderedItems(po);
1573         String annotation = "Notification of New Unordered Items for Purchase Order" + po.getPurapDocumentIdentifier() + "(document id " + po.getDocumentNumber() + ")";
1574         String responsibilityNote = "Purchase Order Amendment Routed By User";
1575 
1576         for (AdHocRoutePerson adHocPerson : fyiList) {
1577             try {
1578                 po.appSpecificRouteDocumentToUser(
1579                         po.getDocumentHeader().getWorkflowDocument(),
1580                         adHocPerson.getPerson().getPrincipalId(),
1581                         annotation,
1582                         responsibilityNote);
1583             } catch (WorkflowException e) {
1584                 throw new RuntimeException("Error routing fyi for document with id " + po.getDocumentNumber(), e);
1585             }
1586 
1587         }
1588     }
1589 
1590     /**
1591      * Creates a list of fiscal officers for new unordered items added to a purchase order.
1592      *
1593      * @param po
1594      * @return
1595      */
1596     protected List<AdHocRoutePerson> createFyiFiscalOfficerListForNewUnorderedItems(PurchaseOrderDocument po) {
1597 
1598         List<AdHocRoutePerson> adHocRoutePersons = new ArrayList<AdHocRoutePerson>();
1599         Map fiscalOfficers = new HashMap();
1600         AdHocRoutePerson adHocRoutePerson = null;
1601 
1602         for (PurchaseOrderItem poItem : (List<PurchaseOrderItem>) po.getItems()) {
1603             // only check, active, above the line, unordered items
1604             if (poItem.isItemActiveIndicator() && poItem.getItemType().isLineItemIndicator() && PurapConstants.ItemTypeCodes.ITEM_TYPE_UNORDERED_ITEM_CODE.equals(poItem.getItemTypeCode())) {
1605 
1606                 // if the item identifier is null its new, or if the item doesn't exist on the current purchase order it's new
1607                 if (poItem.getItemIdentifier() == null || !purchaseOrderDao.itemExistsOnPurchaseOrder(poItem.getItemLineNumber(), purchaseOrderDao.getDocumentNumberForCurrentPurchaseOrder(po.getPurapDocumentIdentifier()))) {
1608 
1609                     // loop through accounts and pull off fiscal officer
1610                     for (PurApAccountingLine account : poItem.getSourceAccountingLines()) {
1611 
1612                         // check for dupes of fiscal officer
1613                         if (fiscalOfficers.containsKey(account.getAccount().getAccountFiscalOfficerUser().getPrincipalName()) == false) {
1614 
1615                             // add fiscal officer to list
1616                             fiscalOfficers.put(account.getAccount().getAccountFiscalOfficerUser().getPrincipalName(), account.getAccount().getAccountFiscalOfficerUser().getPrincipalName());
1617 
1618                             // create AdHocRoutePerson object and add to list
1619                             adHocRoutePerson = new AdHocRoutePerson();
1620                             adHocRoutePerson.setId(account.getAccount().getAccountFiscalOfficerUser().getPrincipalName());
1621                             adHocRoutePerson.setActionRequested(OLEConstants.WORKFLOW_FYI_REQUEST);
1622                             adHocRoutePersons.add(adHocRoutePerson);
1623                         }
1624                     }
1625                 }
1626             }
1627         }
1628 
1629         return adHocRoutePersons;
1630     }
1631 
1632     /**
1633      * Sends an FYI to fiscal officers for general ledger entries created for amend purchase order
1634      *
1635      * @param po
1636      */
1637     @Override
1638     public void sendFyiForGLEntries(PurchaseOrderDocument po) {
1639 
1640         List<AdHocRoutePerson> fyiList = createFyiFiscalOfficerListForAmendGlEntries(po);
1641         String annotation = "Amendment to Purchase Order " + po.getPurapDocumentIdentifier() + "( Document id " + po.getDocumentNumber() + ")" +
1642                 " resulted in the generation of Pending General Ledger Entries.";
1643         String responsibilityNote = "Purchase Order Amendment Routed By User";
1644 
1645         for (AdHocRoutePerson adHocPerson : fyiList) {
1646             try {
1647                 po.appSpecificRouteDocumentToUser(
1648                         po.getDocumentHeader().getWorkflowDocument(),
1649                         adHocPerson.getPerson().getPrincipalId(),
1650                         annotation,
1651                         responsibilityNote);
1652             } catch (WorkflowException e) {
1653                 throw new RuntimeException("Error routing fyi for document with id " + po.getDocumentNumber(), e);
1654             }
1655 
1656         }
1657     }
1658 
1659     /**
1660      * Creates a list of fiscal officers for amend genera
1661      *
1662      * @param po
1663      * @return
1664      */
1665     protected List<AdHocRoutePerson> createFyiFiscalOfficerListForAmendGlEntries(PurchaseOrderDocument po) {
1666 
1667         List<AdHocRoutePerson> adHocRoutePersons = new ArrayList<AdHocRoutePerson>();
1668         Map fiscalOfficers = new HashMap();
1669         AdHocRoutePerson adHocRoutePerson = null;
1670 
1671         for (SourceAccountingLine account : po.getGlOnlySourceAccountingLines()) {
1672             // loop through accounts and pull off fiscal officer
1673             // for(PurApAccountingLine account : poItem.getSourceAccountingLines()){
1674             // check for dupes of fiscal officer
1675             Account acct = SpringContext.getBean(AccountService.class).getByPrimaryId(account.getChartOfAccountsCode(),
1676                     account.getAccountNumber());
1677             String principalName = acct.getAccountFiscalOfficerUser().getPrincipalName();
1678             // String principalName = account.getAccount().getAccountFiscalOfficerUser().getPrincipalName();
1679             if (fiscalOfficers.containsKey(principalName) == false) {
1680                 // add fiscal officer to list
1681                 fiscalOfficers.put(principalName, principalName);
1682                 // create AdHocRoutePerson object and add to list
1683                 adHocRoutePerson = new AdHocRoutePerson();
1684                 adHocRoutePerson.setId(principalName);
1685                 adHocRoutePerson.setActionRequested(KewApiConstants.ACTION_REQUEST_FYI_REQ);
1686                 adHocRoutePersons.add(adHocRoutePerson);
1687             }
1688             // }
1689         }
1690 
1691         return adHocRoutePersons;
1692     }
1693 
1694     /**
1695      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#categorizeItemsForSplit(java.util.List)
1696      */
1697     @Override
1698     public HashMap<String, List<PurchaseOrderItem>> categorizeItemsForSplit(List<PurchaseOrderItem> items) {
1699         HashMap<String, List<PurchaseOrderItem>> movingOrNot = new HashMap<String, List<PurchaseOrderItem>>(3);
1700         List<PurchaseOrderItem> movingPOItems = new ArrayList<PurchaseOrderItem>();
1701         List<PurchaseOrderItem> remainingPOItems = new ArrayList<PurchaseOrderItem>();
1702         List<PurchaseOrderItem> remainingPOLineItems = new ArrayList<PurchaseOrderItem>();
1703         for (PurchaseOrderItem item : items) {
1704             if (item.isMovingToSplit()) {
1705                 movingPOItems.add(item);
1706             } else {
1707                 remainingPOItems.add(item);
1708                 if (item.getItemType().isLineItemIndicator()) {
1709                     remainingPOLineItems.add(item);
1710                 }
1711             }
1712         }
1713         movingOrNot.put(PODocumentsStrings.ITEMS_MOVING_TO_SPLIT, movingPOItems);
1714         movingOrNot.put(PODocumentsStrings.ITEMS_REMAINING, remainingPOItems);
1715         movingOrNot.put(PODocumentsStrings.LINE_ITEMS_REMAINING, remainingPOLineItems);
1716         return movingOrNot;
1717     }
1718 
1719     /**
1720      * @see org.kuali.module.purap.service.PurchaseOrderService#populateQuoteWithVendor(java.lang.Integer, java.lang.Integer,
1721      * java.lang.String)
1722      */
1723     @Override
1724     public PurchaseOrderVendorQuote populateQuoteWithVendor(Integer headerId, Integer detailId, String documentNumber) {
1725         VendorDetail vendor = vendorService.getVendorDetail(headerId, detailId);
1726         updateDefaultVendorAddress(vendor);
1727         PurchaseOrderVendorQuote newPOVendorQuote = populateAddressForPOVendorQuote(vendor, documentNumber);
1728 
1729         // Set the vendorPhoneNumber on the quote to be the first "phone number" type phone
1730         // found on the list. If there's no "phone number" type found, the quote's
1731         // vendorPhoneNumber will be blank regardless of any other types of phone found on the list.
1732         for (VendorPhoneNumber phone : vendor.getVendorPhoneNumbers()) {
1733             if (VendorConstants.PhoneTypes.PHONE.equals(phone.getVendorPhoneTypeCode())) {
1734                 newPOVendorQuote.setVendorPhoneNumber(phone.getVendorPhoneNumber());
1735                 break;
1736             }
1737         }
1738 
1739         return newPOVendorQuote;
1740     }
1741 
1742     /**
1743      * Creates the new PurchaseOrderVendorQuote and populate the address fields for it.
1744      *
1745      * @param newVendor      The VendorDetail object from which we obtain the values for the address fields.
1746      * @param documentNumber The documentNumber of the PurchaseOrderDocument containing the PurchaseOrderVendorQuote.
1747      * @return
1748      */
1749     protected PurchaseOrderVendorQuote populateAddressForPOVendorQuote(VendorDetail newVendor, String documentNumber) {
1750         PurchaseOrderVendorQuote newPOVendorQuote = new PurchaseOrderVendorQuote();
1751         newPOVendorQuote.setVendorName(newVendor.getVendorName());
1752         newPOVendorQuote.setVendorHeaderGeneratedIdentifier(newVendor.getVendorHeaderGeneratedIdentifier());
1753         newPOVendorQuote.setVendorDetailAssignedIdentifier(newVendor.getVendorDetailAssignedIdentifier());
1754         newPOVendorQuote.setDocumentNumber(documentNumber);
1755         boolean foundAddress = false;
1756         for (VendorAddress address : newVendor.getVendorAddresses()) {
1757             if (AddressTypes.QUOTE.equals(address.getVendorAddressTypeCode())) {
1758                 newPOVendorQuote.setVendorCityName(address.getVendorCityName());
1759                 newPOVendorQuote.setVendorCountryCode(address.getVendorCountryCode());
1760                 newPOVendorQuote.setVendorLine1Address(address.getVendorLine1Address());
1761                 newPOVendorQuote.setVendorLine2Address(address.getVendorLine2Address());
1762                 newPOVendorQuote.setVendorPostalCode(address.getVendorZipCode());
1763                 newPOVendorQuote.setVendorStateCode(address.getVendorStateCode());
1764                 newPOVendorQuote.setVendorFaxNumber(address.getVendorFaxNumber());
1765                 foundAddress = true;
1766                 break;
1767             }
1768         }
1769         if (!foundAddress) {
1770             newPOVendorQuote.setVendorCityName(newVendor.getDefaultAddressCity());
1771             newPOVendorQuote.setVendorCountryCode(newVendor.getDefaultAddressCountryCode());
1772             newPOVendorQuote.setVendorLine1Address(newVendor.getDefaultAddressLine1());
1773             newPOVendorQuote.setVendorLine2Address(newVendor.getDefaultAddressLine2());
1774             newPOVendorQuote.setVendorPostalCode(newVendor.getDefaultAddressPostalCode());
1775             newPOVendorQuote.setVendorStateCode(newVendor.getDefaultAddressStateCode());
1776             newPOVendorQuote.setVendorFaxNumber(newVendor.getDefaultFaxNumber());
1777         }
1778         return newPOVendorQuote;
1779     }
1780 
1781     /**
1782      * Obtains the defaultAddress of the vendor and setting the default address fields on the vendor.
1783      *
1784      * @param vendor The VendorDetail object whose default address we'll obtain and set the fields.
1785      */
1786     protected void updateDefaultVendorAddress(VendorDetail vendor) {
1787         VendorAddress defaultAddress = null;
1788         if(vendor.getVendorAddresses()!=null && vendor.getVendorHeader()!=null && vendor.getVendorHeader().getVendorType()!=null && vendor.getVendorHeader().getVendorType().getAddressType()!=null && vendor.getVendorHeader().getVendorType().getAddressType().getVendorAddressTypeCode()!=null){
1789             defaultAddress = vendorService.getVendorDefaultAddress(vendor.getVendorAddresses(), vendor.getVendorHeader().getVendorType().getAddressType().getVendorAddressTypeCode(), "");
1790         }
1791         if (defaultAddress != null) {
1792             if (defaultAddress.getVendorState() != null) {
1793                 vendor.setVendorStateForLookup(defaultAddress.getVendorState().getName());
1794             }
1795             vendor.setDefaultAddressLine1(defaultAddress.getVendorLine1Address());
1796             vendor.setDefaultAddressLine2(defaultAddress.getVendorLine2Address());
1797             vendor.setDefaultAddressCity(defaultAddress.getVendorCityName());
1798             vendor.setDefaultAddressPostalCode(defaultAddress.getVendorZipCode());
1799             vendor.setDefaultAddressStateCode(defaultAddress.getVendorStateCode());
1800             vendor.setDefaultAddressInternationalProvince(defaultAddress.getVendorAddressInternationalProvinceName());
1801             vendor.setDefaultAddressCountryCode(defaultAddress.getVendorCountryCode());
1802             vendor.setDefaultFaxNumber(defaultAddress.getVendorFaxNumber());
1803         }
1804     }
1805 
1806     /**
1807      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#processACMReq(org.kuali.ole.module.purap.document.ContractManagerAssignmentDocument)
1808      */
1809     @Override
1810     public void processACMReq(ContractManagerAssignmentDocument acmDoc) {
1811         List<ContractManagerAssignmentDetail> acmDetails = acmDoc.getContractManagerAssignmentDetails();
1812         for (Object element : acmDetails) {
1813             ContractManagerAssignmentDetail detail = (ContractManagerAssignmentDetail) element;
1814 
1815             if (ObjectUtils.isNotNull(detail.getContractManagerCode())) {
1816                 // Get the requisition for this ContractManagerAssignmentDetail.
1817                 RequisitionDocument req = requisitionService.getRequisitionById(detail.getRequisitionIdentifier());
1818 
1819                 if (PurapConstants.RequisitionStatuses.APPDOC_AWAIT_CONTRACT_MANAGER_ASSGN.equals(req.getApplicationDocumentStatus())) {
1820                     // only update REQ if code is empty and status is correct
1821                     try {
1822                         req.updateAndSaveAppDocStatus(PurapConstants.RequisitionStatuses.APPDOC_CLOSED);
1823                     } catch (WorkflowException e) {
1824                         throw new RuntimeException("Error saving routing data while saving document with id " + req.getDocumentNumber(), e);
1825                     }
1826 
1827                     purapService.saveDocumentNoValidation(req);
1828                     createPurchaseOrderDocument(req, getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER), detail.getContractManagerCode());
1829                 }
1830             }
1831 
1832         }// endfor
1833     }
1834 
1835     /**
1836      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#autoCloseFullyDisencumberedOrders()
1837      */
1838     @Override
1839     public boolean autoCloseFullyDisencumberedOrders() {
1840         LOG.debug("autoCloseFullyDisencumberedOrders() started");
1841         List<AutoClosePurchaseOrderView> autoCloseList = new ArrayList<AutoClosePurchaseOrderView>();
1842 
1843         String autoCloseOrderFromDateString = parameterService.getParameterValueAsString(AutoClosePurchaseOrdersStep.class, PurapParameterConstants.AUTO_CLOSE_PO_FROM_DATE);
1844         String autoCloseOrderToDateString = parameterService.getParameterValueAsString(AutoClosePurchaseOrdersStep.class, PurapParameterConstants.AUTO_CLOSE_PO_TO_DATE);
1845 
1846         boolean validFromDate = true;
1847         java.sql.Date autoCloseOrderFromDate = null;
1848         try {
1849             autoCloseOrderFromDate = dateTimeService.convertToSqlDate(autoCloseOrderFromDateString);
1850         } catch (Exception e) {
1851             autoCloseOrderFromDate = null;
1852         }
1853 
1854         boolean validToDate = true;
1855         java.sql.Date autoCloseOrderToDate = null;
1856         try {
1857             autoCloseOrderToDate = dateTimeService.convertToSqlDate(autoCloseOrderToDateString);
1858 
1859         } catch (Exception e) {
1860             autoCloseOrderToDate = null;
1861         }
1862 
1863 
1864         autoCloseList = purchaseOrderDao.getAllOpenPurchaseOrders(getExcludedVendorChoiceCodes(), autoCloseOrderFromDate, autoCloseOrderToDate);
1865 
1866         //we need to eliminate the AutoClosePurchaseOrderView whose workflowdocument status is not OPEN..
1867         //KFSMI-7533
1868          List<AutoClosePurchaseOrderView> purchaseOrderAutoCloseList = filterDocumentsForAppDocStatusOpen
1869          (autoCloseList);
1870 
1871         for (AutoClosePurchaseOrderView poAutoClose : purchaseOrderAutoCloseList) {
1872             if ((poAutoClose.getTotalAmount() != null) && ((KualiDecimal.ZERO.compareTo(poAutoClose.getTotalAmount())) != 0)) {
1873             if (LOG.isDebugEnabled()) {
1874                 LOG.debug("autoCloseFullyDisencumberedOrders() PO ID " + poAutoClose.getPurapDocumentIdentifier() + " with total " + poAutoClose.getTotalAmount().doubleValue() + " will be closed");
1875             }
1876             String newStatus = PurapConstants.PurchaseOrderStatuses.APPDOC_PENDING_CLOSE;
1877             String annotation = "This PO was automatically closed in batch.";
1878             String documentType = PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_CLOSE_DOCUMENT;
1879             PurchaseOrderDocument document = getPurchaseOrderByDocumentNumber(poAutoClose.getDocumentNumber());
1880             createNoteForAutoCloseOrders(document, annotation);
1881             createAndRoutePotentialChangeDocument(poAutoClose.getDocumentNumber(), documentType, annotation, null, newStatus);
1882             }
1883 
1884         }
1885         LOG.debug("autoCloseFullyDisencumberedOrders() ended");
1886 
1887         resetAutoClosePurchaseOrderDateParameter();
1888         return true;
1889     }
1890 
1891     /**
1892      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#autoCloseRecurringOrders()
1893      */
1894     @Override
1895     public boolean autoCloseRecurringOrders() {
1896         LOG.debug("autoCloseRecurringOrders() started");
1897         boolean shouldSendEmail = true;
1898         MailMessage message = new MailMessage();
1899         String parameterEmail = parameterService.getParameterValueAsString(AutoCloseRecurringOrdersStep.class, PurapParameterConstants.AUTO_CLOSE_RECURRING_PO_TO_EMAIL_ADDRESSES);
1900 
1901         if (StringUtils.isEmpty(parameterEmail)) {
1902             // Don't stop the show if the email address is wrong, log it and continue.
1903             LOG.warn("autoCloseRecurringOrders(): parameterEmail is missing, we'll not send out any emails for this job.");
1904             shouldSendEmail = false;
1905         }
1906         if (shouldSendEmail) {
1907             message = setMessageAddressesAndSubject(message, parameterEmail);
1908         }
1909         StringBuffer emailBody = new StringBuffer();
1910         // There should always be a "AUTO_CLOSE_RECURRING_ORDER_DT"
1911         // row in the table, this method sets it to "mm/dd/yyyy" after processing.
1912         String recurringOrderDateString = parameterService.getParameterValueAsString(AutoCloseRecurringOrdersStep.class, PurapParameterConstants.AUTO_CLOSE_RECURRING_PO_DATE);
1913         boolean validDate = true;
1914         java.util.Date recurringOrderDate = null;
1915         try {
1916             recurringOrderDate = dateTimeService.convertToDate(recurringOrderDateString);
1917         } catch (ParseException pe) {
1918             validDate = false;
1919         }
1920         if (StringUtils.isEmpty(recurringOrderDateString) || recurringOrderDateString.equalsIgnoreCase("mm/dd/yyyy") || (!validDate)) {
1921             if (recurringOrderDateString.equalsIgnoreCase("mm/dd/yyyy")) {
1922                 LOG.debug("autoCloseRecurringOrders(): mm/dd/yyyy " + "was found in the Application Settings table. No orders will be closed, method will end.");
1923                 if (shouldSendEmail) {
1924                     emailBody.append("The AUTO_CLOSE_RECURRING_ORDER_DT found in the Application Settings table " + "was mm/dd/yyyy. No recurring PO's were closed.");
1925                 }
1926             } else {
1927                 if (LOG.isDebugEnabled()) {
1928                     LOG.debug("autoCloseRecurringOrders(): An invalid autoCloseRecurringOrdersDate " + "was found in the Application Settings table: " + recurringOrderDateString + ". Method will end.");
1929                 }
1930                 if (shouldSendEmail) {
1931                     emailBody.append("An invalid AUTO_CLOSE_RECURRING_ORDER_DT was found in the Application Settings table: " + recurringOrderDateString + ". No recurring PO's were closed.");
1932                 }
1933             }
1934             if (shouldSendEmail) {
1935                 sendMessage(message, emailBody.toString());
1936             }
1937             LOG.debug("autoCloseRecurringOrders() ended");
1938 
1939             return false;
1940         }
1941         if (LOG.isDebugEnabled()) {
1942             LOG.debug("autoCloseRecurringOrders() The autoCloseRecurringOrdersDate found in the Application Settings table was " + recurringOrderDateString);
1943         }
1944         if (shouldSendEmail) {
1945             emailBody.append("The autoCloseRecurringOrdersDate found in the Application Settings table was " + recurringOrderDateString + ".");
1946         }
1947         Calendar appSettingsDate = dateTimeService.getCalendar(recurringOrderDate);
1948         Timestamp appSettingsDay = new Timestamp(appSettingsDate.getTime().getTime());
1949 
1950         Calendar todayMinusThreeMonths = getTodayMinusThreeMonths();
1951         Timestamp threeMonthsAgo = new Timestamp(todayMinusThreeMonths.getTime().getTime());
1952 
1953         if (appSettingsDate.after(todayMinusThreeMonths)) {
1954             if (LOG.isDebugEnabled()) {
1955                 LOG.debug("autoCloseRecurringOrders() The appSettingsDate: " + appSettingsDay + " is after todayMinusThreeMonths: " + threeMonthsAgo + ". The program will end.");
1956             }
1957             if (shouldSendEmail) {
1958                 emailBody.append("\n\nThe autoCloseRecurringOrdersDate: " + appSettingsDay + " is after todayMinusThreeMonths: " + threeMonthsAgo + ". The program will end.");
1959                 sendMessage(message, emailBody.toString());
1960             }
1961             LOG.debug("autoCloseRecurringOrders() ended");
1962 
1963             return false;
1964         }
1965 
1966         List<AutoClosePurchaseOrderView> closeList = purchaseOrderDao.getAutoCloseRecurringPurchaseOrders(getExcludedVendorChoiceCodes());
1967 
1968         //we need to eliminate the AutoClosePurchaseOrderView whose workflowdocument status is not OPEN..
1969         //KFSMI-7533
1970         List<AutoClosePurchaseOrderView> purchaseOrderAutoCloseList = filterDocumentsForAppDocStatusOpen(closeList);
1971 
1972         LOG.info("autoCloseRecurringOrders(): " + purchaseOrderAutoCloseList.size() + " PO's were returned for processing.");
1973         int counter = 0;
1974         for (AutoClosePurchaseOrderView poAutoClose : purchaseOrderAutoCloseList) {
1975             if (LOG.isDebugEnabled()) {
1976                 LOG.debug("autoCloseRecurringOrders(): Testing PO ID " + poAutoClose.getPurapDocumentIdentifier() + ". recurringPaymentEndDate: " + poAutoClose.getRecurringPaymentEndDate());
1977             }
1978             if (poAutoClose.getRecurringPaymentEndDate().before(threeMonthsAgo)) {
1979                 String newStatus = PurapConstants.PurchaseOrderStatuses.APPDOC_PENDING_CLOSE;
1980                 String annotation = "This recurring PO was automatically closed in batch.";
1981                 String documentType = PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_CLOSE_DOCUMENT;
1982                 PurchaseOrderDocument document = getPurchaseOrderByDocumentNumber(poAutoClose.getDocumentNumber());
1983                 boolean rulePassed = kualiRuleService.applyRules(new AttributedRouteDocumentEvent("", document));
1984 
1985                 boolean success = true;
1986                 if (success) {
1987                     ++counter;
1988                     if (counter == 1) {
1989                         emailBody.append("\n\nThe following recurring Purchase Orders will be closed by auto close recurring batch job \n");
1990                     }
1991                     if (LOG.isDebugEnabled()) {
1992                         LOG.debug("autoCloseRecurringOrders() PO ID " + poAutoClose.getPurapDocumentIdentifier() + " will be closed.");
1993                     }
1994                     createNoteForAutoCloseOrders(document, annotation);
1995                     createAndRoutePotentialChangeDocument(poAutoClose.getDocumentNumber(), documentType, annotation, null, newStatus);
1996                     if (shouldSendEmail) {
1997                         emailBody.append("\n\n" + counter + " PO ID: " + poAutoClose.getPurapDocumentIdentifier() + ", End Date: " + poAutoClose.getRecurringPaymentEndDate() + ", Status: " + poAutoClose.getApplicationDocumentStatus() + ", VendorChoice: " + poAutoClose.getVendorChoiceCode() + ", RecurringPaymentType: " + poAutoClose.getRecurringPaymentTypeCode());
1998                     }
1999                 } else {
2000                     // If it was unsuccessful, we have to clear the error map in the GlobalVariables so that the previous
2001                     // error would not still be lingering around and the next PO in the list can be validated.
2002                     GlobalVariables.getMessageMap().clearErrorMessages();
2003                 }
2004             }
2005         }
2006         if (counter == 0) {
2007             LOG.debug("\n\nNo recurring PO's fit the conditions for closing.");
2008             if (shouldSendEmail) {
2009                 emailBody.append("\n\nNo recurring PO's fit the conditions for closing.");
2010             }
2011         }
2012         if (shouldSendEmail) {
2013             sendMessage(message, emailBody.toString());
2014         }
2015         resetAutoCloseRecurringOrderDateParameter();
2016         LOG.debug("autoCloseRecurringOrders() ended");
2017 
2018         return true;
2019     }
2020 
2021     /**
2022      * Filter out the auto close purchase order view documents for the appDocStatus with status open
2023      * For each document in the list, check if there is workflowdocument whose appdocstatus is open
2024      * add add to the return list.
2025      *
2026      * @param List<AutoClosePurchaseOrderView>
2027      * @param appDocStatus
2028      * @return filteredAutoClosePOView filtered auto close po view documents where appdocstatus is open
2029      */
2030     protected List<AutoClosePurchaseOrderView> filterDocumentsForAppDocStatusOpen(List<AutoClosePurchaseOrderView> autoClosePurchaseOrderViews) {
2031         List<AutoClosePurchaseOrderView> filteredAutoClosePOView = new ArrayList<AutoClosePurchaseOrderView>();
2032 
2033         for (AutoClosePurchaseOrderView autoClosePurchaseOrderView : autoClosePurchaseOrderViews) {
2034             Document document = findDocument(autoClosePurchaseOrderView.getDocumentNumber());
2035 
2036             if (document != null) {
2037                 if (PurapConstants.PurchaseOrderStatuses.APPDOC_OPEN.equalsIgnoreCase(
2038                         document.getDocumentHeader().getWorkflowDocument().getApplicationDocumentStatus())) {
2039                     //found the matched Awaiting Contract Manager Assignment status, retrieve the routeHeaderId and add to the list
2040                     filteredAutoClosePOView.add(autoClosePurchaseOrderView);
2041                 }
2042             }
2043         }
2044 
2045         return filteredAutoClosePOView;
2046     }
2047 
2048     /**
2049      * This method finds the document for the given document header id
2050      *
2051      * @param documentHeaderId
2052      * @return document The document in the workflow that matches the document header id.
2053      */
2054     protected Document findDocument(String documentHeaderId) {
2055         Document document = null;
2056 
2057         try {
2058             document = documentService.getByDocumentHeaderId(documentHeaderId);
2059         } catch (WorkflowException ex) {
2060             LOG.error("Exception encountered on finding the document: " + documentHeaderId, ex);
2061         } catch (UnknownDocumentTypeException ex) {
2062             // don't blow up just because a document type is not installed (but don't return it either)
2063             LOG.error("Exception encountered on finding the document: " + documentHeaderId, ex);
2064         }
2065 
2066         return document;
2067     }
2068 
2069 
2070     /**
2071      * Creates and returns a Calendar object of today minus three months.
2072      *
2073      * @return Calendar object of today minus three months.
2074      */
2075     protected Calendar getTodayMinusThreeMonths() {
2076         Calendar todayMinusThreeMonths = Calendar.getInstance(); // Set to today.
2077         todayMinusThreeMonths.add(Calendar.MONTH, -3); // Back up 3 months.
2078         todayMinusThreeMonths.set(Calendar.HOUR, 12);
2079         todayMinusThreeMonths.set(Calendar.MINUTE, 0);
2080         todayMinusThreeMonths.set(Calendar.SECOND, 0);
2081         todayMinusThreeMonths.set(Calendar.MILLISECOND, 0);
2082         todayMinusThreeMonths.set(Calendar.AM_PM, Calendar.AM);
2083         return todayMinusThreeMonths;
2084     }
2085 
2086     /**
2087      * Sets the to addresses, from address and the subject of the email.
2088      *
2089      * @param message        The MailMessage object of the email to be sent.
2090      * @param parameterEmail The String of email addresses with delimiters of ";" obtained from the system parameter.
2091      * @return The MailMessage object after the to addresses, from address and the subject have been set.
2092      */
2093     protected MailMessage setMessageAddressesAndSubject(MailMessage message, String parameterEmail) {
2094         String toAddressList[] = parameterEmail.split(";");
2095 
2096         if (toAddressList.length > 0) {
2097             for (String element : toAddressList) {
2098                 if (element != null) {
2099                     message.addToAddress(element.trim());
2100                 }
2101             }
2102         }
2103 
2104         message.setFromAddress(toAddressList[0]);
2105         message.setSubject("Auto Close Recurring Purchase Orders");
2106         return message;
2107     }
2108 
2109     /**
2110      * Sends the email by calling the sendMessage method in mailService and log error if exception occurs during the attempt to send
2111      * the message.
2112      *
2113      * @param message   The MailMessage object containing information to be sent.
2114      * @param emailBody The String containing the body of the email to be sent.
2115      */
2116     protected void sendMessage(MailMessage message, String emailBody) {
2117         message.setMessage(emailBody);
2118         try {
2119             mailService.sendMessage(message);
2120         } catch (Exception e) {
2121             // Don't stop the show if the email has problem, log it and continue.
2122             LOG.error("autoCloseRecurringOrders(): email problem. Message not sent.", e);
2123             throw new RuntimeException(e);
2124         }
2125     }
2126 
2127     /**
2128      * Resets the AUTO_CLOSE_RECURRING_ORDER_DT system parameter to "mm/dd/yyyy".
2129      */
2130     protected void resetAutoCloseRecurringOrderDateParameter() {
2131         Parameter autoCloseRecurringPODate = parameterService.getParameter(AutoCloseRecurringOrdersStep.class, PurapParameterConstants.AUTO_CLOSE_RECURRING_PO_DATE);
2132         if (autoCloseRecurringPODate != null) {
2133             Parameter.Builder updatedParameter = Parameter.Builder.create(autoCloseRecurringPODate);
2134             updatedParameter.setValue("mm/dd/yyyy");
2135             parameterService.updateParameter(updatedParameter.build());
2136         }
2137     }
2138 
2139     /**
2140      * Resets the AUTO_CLOSE_PO_FROM_DATE and AUTO_CLOSE_PO_TO_DATE system parameters to "mm/dd/yyyy".
2141      */
2142     protected void resetAutoClosePurchaseOrderDateParameter() {
2143         Parameter autoClosePOFromDate = parameterService.getParameter(AutoClosePurchaseOrdersStep.class, PurapParameterConstants.AUTO_CLOSE_PO_FROM_DATE);
2144         Parameter autoClosePOToDate = parameterService.getParameter(AutoClosePurchaseOrdersStep.class, PurapParameterConstants.AUTO_CLOSE_PO_TO_DATE);
2145 
2146         if (autoClosePOFromDate != null) {
2147             Parameter.Builder updatedParameter = Parameter.Builder.create(autoClosePOFromDate);
2148             updatedParameter.setValue("mm/dd/yyyy");
2149             parameterService.updateParameter(updatedParameter.build());
2150         }
2151         if (autoClosePOToDate != null) {
2152             Parameter.Builder updatedParameter = Parameter.Builder.create(autoClosePOToDate);
2153             updatedParameter.setValue("mm/dd/yyyy");
2154             parameterService.updateParameter(updatedParameter.build());
2155         }
2156     }
2157 
2158     /**
2159      * Gets a List of excluded vendor choice codes from PurapConstants.
2160      *
2161      * @return a List of excluded vendor choice codes
2162      */
2163     protected List<String> getExcludedVendorChoiceCodes() {
2164         List<String> excludedVendorChoiceCodes = new ArrayList<String>();
2165         for (String excludedCode : PurapConstants.AUTO_CLOSE_EXCLUSION_VNDR_CHOICE_CODES) {
2166             excludedVendorChoiceCodes.add(excludedCode);
2167         }
2168         return excludedVendorChoiceCodes;
2169     }
2170 
2171     /**
2172      * Creates and add a note to the purchase order document using the annotation String in the input parameter. This method is used
2173      * by the autoCloseRecurringOrders() and autoCloseFullyDisencumberedOrders to add a note to the purchase order to indicate that
2174      * the purchase order was closed by the batch job.
2175      *
2176      * @param purchaseOrderDocument The purchase order document that is being closed by the batch job.
2177      * @param annotation            The string to appear on the note to be attached to the purchase order.
2178      */
2179     protected void createNoteForAutoCloseOrders(PurchaseOrderDocument purchaseOrderDocument, String annotation) {
2180         try {
2181             Note noteObj = documentService.createNoteFromDocument(purchaseOrderDocument, annotation);
2182 //            documentService.addNoteToDocument(purchaseOrderDocument, noteObj);
2183             noteService.save(noteObj);
2184         } catch (Exception e) {
2185             String errorMessage = "Error creating and saving close note for purchase order with document service";
2186             LOG.error("createNoteForAutoCloseRecurringOrders " + errorMessage, e);
2187             throw new RuntimeException(errorMessage, e);
2188         }
2189     }
2190 
2191     /**
2192      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#retrieveCapitalAssetItemsForIndividual(java.lang.Integer)
2193      */
2194     @Override
2195     public List<PurchasingCapitalAssetItem> retrieveCapitalAssetItemsForIndividual(Integer poId) {
2196         PurchaseOrderDocument po = getCurrentPurchaseOrder(poId);
2197         if (ObjectUtils.isNotNull(po)) {
2198             return po.getPurchasingCapitalAssetItems();
2199         }
2200         return null;
2201     }
2202 
2203     /**
2204      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#retrieveCapitalAssetSystemForOneSystem(java.lang.Integer)
2205      */
2206     @Override
2207     public CapitalAssetSystem retrieveCapitalAssetSystemForOneSystem(Integer poId) {
2208         PurchaseOrderDocument po = getCurrentPurchaseOrder(poId);
2209         if (ObjectUtils.isNotNull(po)) {
2210             List<CapitalAssetSystem> systems = po.getPurchasingCapitalAssetSystems();
2211             if (ObjectUtils.isNotNull(systems)) {
2212                 // for one system, there should only ever be one system
2213                 return systems.get(0);
2214             }
2215         }
2216         return null;
2217     }
2218 
2219     /**
2220      * @see org.kuali.ole.module.purap.document.service.PurchaseOrderService#retrieveCapitalAssetSystemsForMultipleSystem(java.lang.Integer)
2221      */
2222     @Override
2223     public List<CapitalAssetSystem> retrieveCapitalAssetSystemsForMultipleSystem(Integer poId) {
2224         PurchaseOrderDocument po = getCurrentPurchaseOrder(poId);
2225         if (ObjectUtils.isNotNull(po)) {
2226             return po.getPurchasingCapitalAssetSystems();
2227         }
2228         return null;
2229     }
2230 
2231     /**
2232      * This method fixes the item references in this document
2233      */
2234     protected void fixItemReferences(PurchaseOrderDocument po) {
2235         // fix item and account references in case this is a new doc (since they will be lost)
2236         for (PurApItem item : (List<PurApItem>) po.getItems()) {
2237             item.setPurapDocument(po);
2238             item.fixAccountReferences();
2239         }
2240     }
2241 
2242     @Override
2243     public List getPendingPurchaseOrderFaxes() {
2244         List<PurchaseOrderDocument> purchaseOrderList = purchaseOrderDao.getPendingPurchaseOrdersForFaxing();
2245         return filterPurchaseOrderDocumentByAppDocStatus(purchaseOrderList,
2246                 PurapConstants.PurchaseOrderStatuses.APPDOC_PENDING_FAX);
2247     }
2248 
2249     /**
2250      * Wrapper class to the filterPaymentRequestByAppDocStatus
2251      * <p/>
2252      * This class first extract the payment request document numbers from the Payment Request Collections,
2253      * then perform the filterPaymentRequestByAppDocStatus function.  Base on the filtered payment request
2254      * doc number, reconstruct the filtered Payment Request Collection
2255      *
2256      * @param paymentRequestDocuments
2257      * @param appDocStatus
2258      * @return
2259      */
2260     protected List<PurchaseOrderDocument> filterPurchaseOrderDocumentByAppDocStatus(Collection<PurchaseOrderDocument> purchaseOrderDocuments, String... appDocStatus) {
2261         List<String> purchaseOrderDocNumbers = new ArrayList<String>();
2262         for (PurchaseOrderDocument purchaseOrder : purchaseOrderDocuments) {
2263             purchaseOrderDocNumbers.add(purchaseOrder.getDocumentNumber());
2264         }
2265 
2266         List<String> filteredPurchaseOrderDocNumbers = filterPurchaseOrderDocumentNumbersByAppDocStatus(purchaseOrderDocNumbers, appDocStatus);
2267 
2268         List<PurchaseOrderDocument> filteredPaymentRequestDocuments = new ArrayList<PurchaseOrderDocument>();
2269         //add to filtered collection if it is in the filtered payment request doc number list
2270         for (PurchaseOrderDocument po : purchaseOrderDocuments) {
2271             if (filteredPurchaseOrderDocNumbers.contains(po.getDocumentNumber())) {
2272                 filteredPaymentRequestDocuments.add(po);
2273             }
2274         }
2275         return filteredPaymentRequestDocuments;
2276     }
2277 
2278     /**
2279      * Since PaymentRequest does not have the app doc status, perform an additional lookup
2280      * through doc search by using list of PaymentRequest Doc numbers.  Query appDocStatus
2281      * from workflow document and filter against the provided status
2282      * <p/>
2283      * DocumentSearch allows for multiple docNumber lookup by docId|docId|docId conversion
2284      *
2285      * @param lookupDocNumbers
2286      * @param appDocStatus
2287      * @return List<String> purchaseOrderDocumentNumbers
2288      */
2289     protected List<String> filterPurchaseOrderDocumentNumbersByAppDocStatus(List<String> lookupDocNumbers, String... appDocStatus) {
2290         boolean valid = false;
2291 
2292         final String DOC_NUM_DELIM = "|";
2293         StrBuilder routerHeaderIdBuilder = new StrBuilder().appendWithSeparators(lookupDocNumbers, DOC_NUM_DELIM);
2294 
2295         List<String> purchaseOrderDocNumbers = new ArrayList<String>();
2296 
2297         DocumentSearchCriteria.Builder documentSearchCriteriaDTO = DocumentSearchCriteria.Builder.create();
2298         documentSearchCriteriaDTO.setDocumentId(routerHeaderIdBuilder.toString());
2299         documentSearchCriteriaDTO.setDocumentTypeName(PurapConstants.PurapDocTypeCodes.PO_DOCUMENT);
2300 
2301         DocumentSearchResults poDocumentsList = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(
2302                 GlobalVariables.getUserSession().getPrincipalId(), documentSearchCriteriaDTO.build());
2303 
2304         for (DocumentSearchResult poDocument : poDocumentsList.getSearchResults()) {
2305             ///use the appDocStatus from the KeyValueDTO result to look up custom status
2306             if (Arrays.asList(appDocStatus).contains(poDocument.getDocument().getApplicationDocumentStatus())) {
2307                 //found the matching status, retrieve the routeHeaderId and add to the list
2308                 purchaseOrderDocNumbers.add(poDocument.getDocument().getDocumentId());
2309             }
2310         }
2311 
2312         return purchaseOrderDocNumbers;
2313     }
2314 
2315     @Override
2316     public String getPurchaseOrderAppDocStatus(Integer poId) {
2317         //TODO: This could be kind of expensive for one field
2318         PurchaseOrderDocument po = getCurrentPurchaseOrder(poId);
2319         if (ObjectUtils.isNotNull(po)) {
2320             return po.getApplicationDocumentStatus();
2321         }
2322 
2323         return null;
2324     }
2325 
2326     /**
2327      * helper method to take the po and save it using businessObjectService so that only the po related data is saved since most
2328      * often we are only updating the flags on the document. It will then reindex the document.
2329      *
2330      * @param po
2331      */
2332     protected void savePurchaseOrderData(PurchaseOrderDocument po) {
2333         // saving old PO using the business object service because the documentService saveDocument
2334         // will try to save the notes again and will cause ojb lock exception.
2335         // since only values that is changed on PO is pendingActionIndicator, save on businessObjectService is used
2336         // OLEMI-9741
2337 
2338         businessObjectService.save(po);
2339 
2340         // reindex the document so that the app doc status gets updated in the results for the PO lookups.
2341         final DocumentAttributeIndexingQueue documentAttributeIndexingQueue = KewApiServiceLocator
2342                 .getDocumentAttributeIndexingQueue();
2343         documentAttributeIndexingQueue.indexDocument(po.getDocumentNumber());
2344 
2345     }
2346 
2347     /**
2348      * @return Returns the personService.
2349      */
2350     protected PersonService getPersonService() {
2351         if (personService == null) {
2352             personService = SpringContext.getBean(PersonService.class);
2353         }
2354         return personService;
2355     }
2356 
2357     public void setB2bPurchaseOrderService(B2BPurchaseOrderService purchaseOrderService) {
2358         this.b2bPurchaseOrderService = purchaseOrderService;
2359     }
2360 
2361     public void setBusinessObjectService(BusinessObjectService boService) {
2362         this.businessObjectService = boService;
2363     }
2364 
2365     public void setDateTimeService(DateTimeService dateTimeService) {
2366         this.dateTimeService = dateTimeService;
2367     }
2368 
2369     public void setDocumentService(DocumentService documentService) {
2370         this.documentService = documentService;
2371     }
2372 
2373     public void setNoteService(NoteService noteService) {
2374         this.noteService = noteService;
2375     }
2376 
2377     public void setPurapService(PurapService purapService) {
2378         this.purapService = purapService;
2379     }
2380 
2381     public void setPrintService(PrintService printService) {
2382         this.printService = printService;
2383     }
2384 
2385     public void setPurchaseOrderDao(PurchaseOrderDao purchaseOrderDao) {
2386         this.purchaseOrderDao = purchaseOrderDao;
2387     }
2388 
2389     public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) {
2390         this.workflowDocumentService = workflowDocumentService;
2391     }
2392 
2393     public void setConfigurationService(ConfigurationService kualiConfigurationService) {
2394         this.kualiConfigurationService = kualiConfigurationService;
2395     }
2396 
2397     public void setKualiRuleService(KualiRuleService kualiRuleService) {
2398         this.kualiRuleService = kualiRuleService;
2399     }
2400 
2401     public void setVendorService(VendorService vendorService) {
2402         this.vendorService = vendorService;
2403     }
2404 
2405     public void setRequisitionService(RequisitionService requisitionService) {
2406         this.requisitionService = requisitionService;
2407     }
2408 
2409     public void setPurapWorkflowIntegrationService(PurApWorkflowIntegrationService purapWorkflowIntegrationService) {
2410         this.purapWorkflowIntegrationService = purapWorkflowIntegrationService;
2411     }
2412 
2413     public void setMaintenanceDocumentService(MaintenanceDocumentService maintenanceDocumentService) {
2414         this.maintenanceDocumentService = maintenanceDocumentService;
2415     }
2416 
2417     public void setParameterService(ParameterService parameterService) {
2418         this.parameterService = parameterService;
2419     }
2420 
2421     public void setMailService(MailService mailService) {
2422         this.mailService = mailService;
2423     }
2424 
2425     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
2426         this.dataDictionaryService = dataDictionaryService;
2427     }
2428 
2429 
2430     /**
2431      * This method is the starting point of EDI File creation and transmission for a PO
2432      *
2433      * @param po
2434      */
2435     @Override
2436     public void initiateTransmission(PurchaseOrderDocument po, PurApItem item) {
2437         if (po.getRequestorPersonEmailAddress() != null) {
2438             fromEmailAddress = po.getRequestorPersonEmailAddress();
2439         }
2440 
2441         if (po != null && po.getVendorDetail() != null) {
2442             List<VendorTransmissionFormatDetail> vendorTxFormat = po.getVendorDetail().getVendorTransmissionFormat();
2443             boolean isSuccess = false;
2444             if (vendorTxFormat.size() > 0) {
2445                 for (int i = 0; i < vendorTxFormat.size(); i++) {
2446                     VendorTransmissionFormatDetail vendorTransmissionFormatDetail = vendorTxFormat.get(i);
2447                     boolean isPrefferedTransmissionFormat = vendorTransmissionFormatDetail.isVendorPreferredTransmissionFormat();
2448                     if (isPrefferedTransmissionFormat && item.getItemLineNumber() != null) {
2449                         String documentType = po.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
2450                         String ediFileName = documentType + "_" + po.getPurapDocumentIdentifier().toString() + "_" + PurapConstants.ItemTypeCodes.ITEM_TYPE_ITEM_CODE + item.getItemLineNumber() + "_" + System.currentTimeMillis() + ".edi";
2451                         String pdfFileName = documentType + "_" + po.getPurapDocumentIdentifier().toString() + "_" + System.currentTimeMillis() + ".pdf";
2452                         String directory = kualiConfigurationService.getPropertyValueAsString(OLEConstants.STAGING_DIRECTORY_KEY);
2453                         String fileLocation = directory + getOlePurapService().getParameter(OLEConstants.VENDOR_TRANSMISSION_FILE);
2454                         File fileLocationDir = new File(fileLocation);
2455                         if (!(fileLocationDir.exists())) {
2456                             fileLocationDir.mkdir();
2457                         }
2458                         String file = fileLocation.trim() + ediFileName.trim();
2459 
2460                         if (vendorTransmissionFormatDetail.getVendorTransmissionFormat() != null &&
2461                                 vendorTransmissionFormatDetail.getVendorTransmissionFormat().getVendorTransmissionFormat() != null &&
2462                                 vendorTransmissionFormatDetail.getVendorTransmissionFormat().getVendorTransmissionFormat().equalsIgnoreCase("EDI")) {
2463                             if (LOG.isDebugEnabled()) {
2464                                 LOG.debug("EDI File======================>" + file);
2465                             }
2466                             isSuccess = savePurchaseOrderEdi(po, file, item);
2467                         }
2468                         if (vendorTransmissionFormatDetail.getVendorTransmissionFormat() != null &&
2469                                 vendorTransmissionFormatDetail.getVendorTransmissionFormat().getVendorTransmissionFormat() != null &&
2470                                 vendorTransmissionFormatDetail.getVendorTransmissionFormat().getVendorTransmissionFormat().equalsIgnoreCase(OLEConstants.OLE_VENDOR_PDF_OPTION)) {
2471                             if (!(po.getDocumentNumber().equals(documentNumber))) {
2472                                 savePurchaseOrderPdf(po, pdfFileName, item);
2473                                 processFTPTransmission(vendorTransmissionFormatDetail, file, pdfFileName.trim());
2474                                 documentNumber = po.getDocumentNumber();
2475                             }
2476                         }
2477                         if (isSuccess && vendorTransmissionFormatDetail.getVendorTransmissionTypes().getVendorTransmissionType() != null) {
2478                             processFTPTransmission(vendorTransmissionFormatDetail, file, ediFileName.trim());
2479                         }
2480                     }
2481                 }
2482             }
2483 
2484         }
2485     }
2486 
2487     public String getEmailAddress(VendorTransmissionFormatDetail vendorTransmissionFormatDetail) {
2488         String toAddress = "";
2489         Integer vendorId = vendorTransmissionFormatDetail.getVendorHeaderGeneratedIdentifier();
2490         if (vendorId != null) {
2491             Map searchMap = new HashMap();
2492             searchMap.put("vendorHeaderGeneratedIdentifier", vendorId);
2493             List<VendorAddress> address = (List<VendorAddress>) SpringContext.getBean(BusinessObjectService.class).findMatching(VendorAddress.class, searchMap);
2494             if (address.size() > 0) {
2495                 for (VendorAddress vendorAddress : address) {
2496                     if (toAddress == null || (toAddress.isEmpty())) {
2497                         toAddress = vendorAddress.getVendorAddressEmailAddress();
2498                     }
2499                 }
2500 
2501             }
2502             if (toAddress == null || toAddress.isEmpty()) {
2503                 List<VendorContact> vendorContactList = (List<VendorContact>) SpringContext.getBean(BusinessObjectService.class).findMatching(VendorContact.class, searchMap);
2504                 if (vendorContactList.size() > 0) {
2505                     for (VendorContact vendorContact : vendorContactList) {
2506                         if (toAddress == null || (toAddress.isEmpty())) {
2507                             toAddress = vendorContact.getVendorContactEmailAddress();
2508                         }
2509                     }
2510                 }
2511             }
2512         }
2513 
2514         return toAddress;
2515     }
2516 
2517 
2518     /**
2519      * This method is to create and save the EDI file into the staging directory.
2520      *
2521      * @param po
2522      * @param file
2523      * @param isRetransmit
2524      * @param environment
2525      */
2526     public boolean savePurchaseOrderEdi(PurchaseOrderDocument po, String file, PurApItem item) {
2527         LOG.debug("****************savePurchaseOrderEdi() started*******************");
2528         boolean isSuccess = false;
2529         PurchaseOrderEdi purchaseOrderEdi = SpringContext.getBean(PurchaseOrderEdi.class, "purchaseOrderEdi");
2530         try {
2531             isSuccess = purchaseOrderEdi.saveEdi(po, item, file);
2532             LOG.debug("savePurchaseOrderEdi() completed");
2533         } catch (Exception e) {
2534             LOG.error("Caught exception ", e);
2535             throw new RuntimeException(e);
2536         }
2537         return isSuccess;
2538     }
2539 
2540     public boolean savePurchaseOrderPdf(PurchaseOrderDocument po, String file, PurApItem item) {
2541         LOG.debug("****************savePurchaseOrderPDF() started*******************");
2542         boolean isSuccess = false;
2543         PurchaseOrderParameters purchaseOrderParameters = getPurchaseOrderParameters();
2544         purchaseOrderParameters.setPurchaseOrderPdfAndFaxParameters(po);
2545         PurchaseOrderTransmitParameters purchaseOrderTransmitParameter = (PurchaseOrderTransmitParameters) purchaseOrderParameters;
2546         String pdfFileLocation = ConfigContext.getCurrentContextConfig().getProperty(org.kuali.ole.OLEConstants.VENDOR_TRANSMISSION_FILE_PATH);
2547         if (pdfFileLocation != null) {
2548             purchaseOrderTransmitParameter.setPdfFileLocation(pdfFileLocation);
2549             purchaseOrderTransmitParameter.setPdfFileName(file);
2550         }
2551         String environment = kualiConfigurationService.getPropertyValueAsString(OLEConstants.ENVIRONMENT_KEY);
2552         PurchaseOrderPdf purchaseOrderPdf = SpringContext.getBean(PurchaseOrderPdf.class, "purchaseOrderPdf");
2553         try {
2554             purchaseOrderPdf.savePdf(po, purchaseOrderParameters, isSuccess, environment);
2555             isSuccess = true;
2556             LOG.debug("savePurchaseOrderPdf() completed");
2557         } catch (Exception e) {
2558             LOG.error("Caught exception ", e);
2559             throw new RuntimeException(e);
2560         }
2561         return isSuccess;
2562     }
2563 
2564     public PurchaseOrderParameters getPurchaseOrderParameters() {
2565         return SpringContext.getBean(PurchaseOrderParameters.class);
2566     }
2567 
2568 
2569     /**
2570      * This method is for transmitting EDI file into FTP Server
2571      *
2572      * @param vendorTransmissionFormatDetail
2573      * @param file
2574      * @param fileName
2575      */
2576     @Override
2577     public boolean processFTPTransmission(VendorTransmissionFormatDetail vendorTransmissionFormatDetail, String file, String fileName) {
2578 
2579         if (vendorTransmissionFormatDetail != null &&
2580                 vendorTransmissionFormatDetail.getVendorEDIConnectionAddress() != null &&
2581                 vendorTransmissionFormatDetail.getVendorEDIConnectionUserName() != null &&
2582                 vendorTransmissionFormatDetail.getVendorEDIConnectionPassword() != null) {
2583             if (LOG.isDebugEnabled()) {
2584                 LOG.debug("Transmission Format==================>" + vendorTransmissionFormatDetail.getVendorTransmissionFormat().getVendorTransmissionFormat());
2585                 LOG.debug("Connection Type======================>" + vendorTransmissionFormatDetail.getVendorTransmissionTypes().getVendorTransmissionType());
2586                 LOG.debug("Connection Address===================>" + vendorTransmissionFormatDetail.getVendorEDIConnectionAddress());
2587                 LOG.debug("Connection User Name=================>" + vendorTransmissionFormatDetail.getVendorEDIConnectionUserName());
2588                 //            LOG.info("Connection Password==================>"+vendorTransmissionFormatDetail.getVendorEDIConnectionPassword());
2589                 LOG.debug("file=================================>" + file);
2590                 LOG.debug("ediFileName==========================>" + fileName);
2591             }
2592 
2593             OleTransmissionService transmissionService = (OleTransmissionService) SpringContext.getService("transmissionService");
2594             if (vendorTransmissionFormatDetail.getVendorTransmissionTypes().getVendorTransmissionType().equalsIgnoreCase("SFTP")) {
2595                 transmissionService.doSFTPUpload(vendorTransmissionFormatDetail, file, fileName);
2596             } else if (vendorTransmissionFormatDetail.getVendorTransmissionTypes().getVendorTransmissionType().equalsIgnoreCase("FTP")) {
2597                 transmissionService.doFTPUpload(vendorTransmissionFormatDetail, file, fileName);
2598             } else if (vendorTransmissionFormatDetail.getVendorTransmissionTypes().getVendorTransmissionType().equalsIgnoreCase(OLEConstants.OLE_VENDOR_EMAIL_OPTION)) {
2599                 String fileLocation = ConfigContext.getCurrentContextConfig().getProperty(org.kuali.ole.OLEConstants.VENDOR_TRANSMISSION_FILE_PATH) + fileName;
2600                 fileNameList.add(fileLocation);
2601                 toEmailAddress = getEmailAddress(vendorTransmissionFormatDetail);
2602             }
2603         } else if (vendorTransmissionFormatDetail != null &&
2604                 getVendorFormatType(vendorTransmissionFormatDetail.getVendorTransmissionFormatId()).equalsIgnoreCase(OLEConstants.OLE_VENDOR_PDF_OPTION) &&
2605                 vendorTransmissionFormatDetail.isVendorPreferredTransmissionFormat() &&
2606                 getVendorTransmissionType(vendorTransmissionFormatDetail.getVendorTransmissionTypeId()).equalsIgnoreCase(OLEConstants.OLE_VENDOR_EMAIL_OPTION)) {
2607             if (vendorTransmissionFormatDetail.getVendorTransmissionTypes().getVendorTransmissionType().equalsIgnoreCase(OLEConstants.OLE_VENDOR_EMAIL_OPTION) &&
2608                     vendorTransmissionFormatDetail.getVendorTransmissionFormat().getVendorTransmissionFormat().equalsIgnoreCase(OLEConstants.OLE_VENDOR_PDF_OPTION)) {
2609                 String fileLocation = ConfigContext.getCurrentContextConfig().getProperty(org.kuali.ole.OLEConstants.VENDOR_TRANSMISSION_FILE_PATH) + fileName;
2610                 fileNameList.add(fileLocation);
2611                 toEmailAddress = getEmailAddress(vendorTransmissionFormatDetail);
2612             }
2613         } else if (vendorTransmissionFormatDetail != null &&
2614                 getVendorFormatType(vendorTransmissionFormatDetail.getVendorTransmissionFormatId()).equalsIgnoreCase(OLEConstants.OLE_VENDOR_EDI_OPTION) &&
2615                 vendorTransmissionFormatDetail.isVendorPreferredTransmissionFormat() &&
2616                 getVendorTransmissionType(vendorTransmissionFormatDetail.getVendorTransmissionTypeId()).equalsIgnoreCase(OLEConstants.OLE_VENDOR_EMAIL_OPTION)) {
2617             String fileLocation = ConfigContext.getCurrentContextConfig().getProperty(org.kuali.ole.OLEConstants.VENDOR_TRANSMISSION_FILE_PATH) + fileName;
2618             fileNameList.add(fileLocation);
2619             toEmailAddress = getEmailAddress(vendorTransmissionFormatDetail);
2620         }
2621         return true;
2622     }
2623 
2624     public String getVendorFormatType(Long id) {
2625         String vendorFormatType = "";
2626         Map searchMap = new HashMap();
2627         searchMap.put(OLEConstants.VENDOR_TRANS_FORMAT_ID, id);
2628         OleVendorTransmissionFormat vendorTransmissionFormat = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(OleVendorTransmissionFormat.class, searchMap);
2629         if (vendorTransmissionFormat != null) {
2630             vendorFormatType = vendorTransmissionFormat.getVendorTransmissionFormat();
2631         }
2632         return vendorFormatType;
2633     }
2634 
2635     public String getVendorTransmissionType(Integer id) {
2636         String vendorTransmissionType = "";
2637         Map searchMap = new HashMap();
2638         searchMap.put(OLEConstants.VENDOR_TRANS_TYPE_ID, id);
2639         OleVendorTransmissionType transmissionType = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(OleVendorTransmissionType.class, searchMap);
2640         if (transmissionType != null) {
2641             vendorTransmissionType = transmissionType.getVendorTransmissionType();
2642         }
2643         return vendorTransmissionType;
2644     }
2645 
2646     public void sendEmail() {
2647         try {
2648             if (toEmailAddress != null && fromEmailAddress != null && fileNameList.size() > 0) {
2649                 String subject = OLEConstants.MAIL_SUBJECT;
2650                 String messageBody = OLEConstants.MAIL_MESSAGE_BODY;
2651                 OleMailer oleMail = GlobalResourceLoader.getService(OLEConstants.OLE_MAILER);
2652                 oleMail.SendEMail(toEmailAddress, fromEmailAddress, fileNameList, subject, messageBody);
2653             }
2654         } catch (Exception e) {
2655             LOG.info("Email Sending Failed for fromAddress [" + fromEmailAddress + "] and toAddress [ " + toEmailAddress + " ]");
2656             e.printStackTrace();
2657         }
2658     }
2659 
2660     public OleSelectDocumentService getOleSelectDocumentService() {
2661         if (oleSelectDocumentService == null) {
2662             oleSelectDocumentService = SpringContext.getBean(OleSelectDocumentService.class);
2663         }
2664         return oleSelectDocumentService;
2665     }
2666 
2667     public void setOleSelectDocumentService(OleSelectDocumentService oleSelectDocumentService) {
2668         this.oleSelectDocumentService = oleSelectDocumentService;
2669     }
2670 }