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  
17  package org.kuali.ole.module.purap.document;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.ole.coa.businessobject.Account;
21  import org.kuali.ole.gl.service.SufficientFundsService;
22  import org.kuali.ole.integration.purap.CapitalAssetSystem;
23  import org.kuali.ole.module.purap.*;
24  import org.kuali.ole.module.purap.PurapConstants.*;
25  import org.kuali.ole.module.purap.businessobject.*;
26  import org.kuali.ole.module.purap.document.dataaccess.PurchaseOrderDao;
27  import org.kuali.ole.module.purap.document.service.PurchaseOrderService;
28  import org.kuali.ole.module.purap.document.service.PurchasingDocumentSpecificService;
29  import org.kuali.ole.module.purap.document.service.RequisitionService;
30  import org.kuali.ole.module.purap.service.PurapAccountingService;
31  import org.kuali.ole.module.purap.service.PurapGeneralLedgerService;
32  import org.kuali.ole.module.purap.util.PurApItemUtils;
33  import org.kuali.ole.select.OleSelectConstant;
34  import org.kuali.ole.select.businessobject.OlePurchaseOrderItem;
35  import org.kuali.ole.select.businessobject.OleSufficientFundCheck;
36  import org.kuali.ole.select.document.OlePurchaseOrderDocument;
37  import org.kuali.ole.select.document.service.OleDocstoreHelperService;
38  import org.kuali.ole.select.document.service.OleRequisitionDocumentService;
39  import org.kuali.ole.sys.OLEConstants;
40  import org.kuali.ole.sys.OLEPropertyConstants;
41  import org.kuali.ole.sys.businessobject.*;
42  import org.kuali.ole.sys.context.SpringContext;
43  import org.kuali.ole.sys.document.MultiselectableDocSearchConversion;
44  import org.kuali.ole.sys.service.GeneralLedgerPendingEntryService;
45  import org.kuali.ole.sys.service.UniversityDateService;
46  import org.kuali.ole.vnd.VendorConstants;
47  import org.kuali.ole.vnd.businessobject.*;
48  import org.kuali.ole.vnd.document.service.VendorService;
49  import org.kuali.rice.core.api.datetime.DateTimeService;
50  import org.kuali.rice.core.api.parameter.ParameterEvaluatorService;
51  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
52  import org.kuali.rice.core.api.util.type.KualiDecimal;
53  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
54  import org.kuali.rice.kew.api.KewApiServiceLocator;
55  import org.kuali.rice.kew.api.WorkflowDocument;
56  import org.kuali.rice.kew.api.action.ActionRequestType;
57  import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
58  import org.kuali.rice.kew.api.exception.WorkflowException;
59  import org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent;
60  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
61  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
62  import org.kuali.rice.kim.api.identity.Person;
63  import org.kuali.rice.kim.api.identity.PersonService;
64  import org.kuali.rice.kns.service.DataDictionaryService;
65  import org.kuali.rice.krad.bo.Note;
66  import org.kuali.rice.krad.bo.PersistableBusinessObject;
67  import org.kuali.rice.krad.dao.DocumentDao;
68  import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent;
69  import org.kuali.rice.krad.service.BusinessObjectService;
70  import org.kuali.rice.krad.service.DocumentHeaderService;
71  import org.kuali.rice.krad.service.KRADServiceLocatorInternal;
72  import org.kuali.rice.krad.service.SequenceAccessorService;
73  import org.kuali.rice.krad.util.GlobalVariables;
74  import org.kuali.rice.krad.util.NoteType;
75  import org.kuali.rice.krad.util.ObjectUtils;
76  import org.kuali.rice.krad.workflow.service.WorkflowDocumentService;
77  
78  import java.math.BigDecimal;
79  import java.sql.Date;
80  import java.sql.Timestamp;
81  import java.util.*;
82  
83  import static org.kuali.ole.sys.OLEConstants.GL_CREDIT_CODE;
84  import static org.kuali.ole.sys.OLEConstants.GL_DEBIT_CODE;
85  
86  /**
87   * Purchase Order Document
88   */
89  public class PurchaseOrderDocument extends PurchasingDocumentBase implements MultiselectableDocSearchConversion {
90      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PurchaseOrderDocument.class);
91  
92      protected Timestamp purchaseOrderCreateTimestamp;
93      protected Integer requisitionIdentifier;
94      protected String purchaseOrderVendorChoiceCode;
95      protected String recurringPaymentFrequencyCode;
96      protected KualiDecimal recurringPaymentAmount;
97      protected Date recurringPaymentDate;
98      protected KualiDecimal initialPaymentAmount;
99      protected Date initialPaymentDate;
100     protected KualiDecimal finalPaymentAmount;
101     protected Date finalPaymentDate;
102     protected Timestamp purchaseOrderInitialOpenTimestamp;
103     protected Timestamp purchaseOrderLastTransmitTimestamp;
104     protected Date purchaseOrderQuoteDueDate;
105     protected String purchaseOrderQuoteTypeCode;
106     protected String purchaseOrderQuoteVendorNoteText;
107     protected boolean purchaseOrderConfirmedIndicator;
108     protected String purchaseOrderCommodityDescription;
109     protected Integer purchaseOrderPreviousIdentifier;
110     protected Integer alternateVendorHeaderGeneratedIdentifier;
111     protected Integer alternateVendorDetailAssignedIdentifier;
112     protected Integer newQuoteVendorHeaderGeneratedIdentifier;
113     protected Integer newQuoteVendorDetailAssignedIdentifier;
114     protected String alternateVendorName;
115     protected boolean purchaseOrderCurrentIndicator = false;
116     protected boolean pendingActionIndicator = false;
117     protected Timestamp purchaseOrderFirstTransmissionTimestamp;
118     protected Integer contractManagerCode;
119     protected Date purchaseOrderQuoteInitializationDate;
120     protected Date purchaseOrderQuoteAwardedDate;
121     protected String assignedUserPrincipalId;
122 
123     // COLLECTIONS
124     protected List<PurchaseOrderVendorStipulation> purchaseOrderVendorStipulations;
125     protected List<PurchaseOrderVendorQuote> purchaseOrderVendorQuotes;
126 
127     // NOT PERSISTED IN DB
128     protected String statusChange;
129     protected String alternateVendorNumber;
130     protected String purchaseOrderRetransmissionMethodCode;
131     protected String retransmitHeader;
132     protected Integer purchaseOrderQuoteListIdentifier;
133     protected KualiDecimal internalPurchasingLimit;
134     protected boolean pendingSplit = false;           // Needed for authorization
135     protected boolean copyingNotesWhenSplitting;      // Check box on Split PO tab
136     protected boolean assigningSensitiveData = false; // whether the form is currently used for assigning sensitive data to the PO
137     protected List<PurchaseOrderSensitiveData> purchaseOrderSensitiveData;
138     protected String assignedUserPrincipalName; // this serves as a temporary holder before validation is done
139 
140     //this is a holder for the accountinglines for GL purposes only; used only for PO change docs
141     protected List<SourceAccountingLine> glOnlySourceAccountingLines;
142 
143     // REFERENCE OBJECTS
144     protected PurchaseOrderVendorChoice purchaseOrderVendorChoice;
145     protected PaymentTermType vendorPaymentTerms;
146     protected ShippingTitle vendorShippingTitle;
147     protected ShippingPaymentTerms vendorShippingPaymentTerms;
148     protected RecurringPaymentFrequency recurringPaymentFrequency;
149     protected ContractManager contractManager;
150     private String vendorAliasName;
151 
152     public String getVendorAliasName() {
153         return vendorAliasName;
154     }
155 
156     public void setVendorAliasName(String vendorAliasName) {
157         this.vendorAliasName = vendorAliasName;
158     }
159 
160     /**
161      * Default constructor.
162      */
163     public PurchaseOrderDocument() {
164         super();
165         this.purchaseOrderVendorStipulations = new ArrayList<PurchaseOrderVendorStipulation>();
166         this.purchaseOrderVendorQuotes = new ArrayList<PurchaseOrderVendorQuote>();
167         this.purchaseOrderCreateTimestamp = new Timestamp(new java.util.Date().getTime());
168     }
169 
170     @Override
171     public PurchasingDocumentSpecificService getDocumentSpecificService() {
172         return SpringContext.getBean(PurchaseOrderService.class);
173     }
174 
175     /**
176      * Overrides the method in PurchasingAccountsPayableDocumentBase to add the criteria
177      * specific to Purchase Order Document.
178      *
179      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#isInquiryRendered()
180      */
181     @Override
182     public boolean isInquiryRendered() {
183         //FIXME : DocumentHeader set as it becomes null
184         if (this.getDocumentHeader().getDocumentNumber() == null) {
185             this.setDocumentHeader(SpringContext.getBean(DocumentHeaderService.class).getDocumentHeaderById(documentNumber));
186         }
187         String applicationDocumentStatus = getApplicationDocumentStatus();
188 
189         if (isPostingYearPrior() &&
190                 (PurapConstants.PurchaseOrderStatuses.APPDOC_CLOSED.equals(applicationDocumentStatus) ||
191                         PurapConstants.PurchaseOrderStatuses.APPDOC_CANCELLED.equals(applicationDocumentStatus) ||
192                         PurapConstants.PurchaseOrderStatuses.APPDOC_VOID.equals(applicationDocumentStatus))) {
193             return false;
194         } else {
195             return true;
196         }
197     }
198 
199     /**
200      * @see org.kuali.rice.krad.document.DocumentBase#getDocumentTitle()
201      */
202     @Override
203     public String getDocumentTitle() {
204         if (SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(PurchaseOrderDocument.class, PurapParameterConstants.PURAP_OVERRIDE_PO_DOC_TITLE)) {
205             return getCustomDocumentTitle();
206         }
207 
208         return this.buildDocumentTitle(super.getDocumentTitle());
209     }
210 
211     /**
212      * Returns a custom document title based on the workflow document title.
213      * Depending on what route level the document is currently in, various info may be added to the documents title.
214      *
215      * @return - Customized document title text dependent upon route level.
216      */
217     protected String getCustomDocumentTitle() {
218         String poNumber = getPurapDocumentIdentifier().toString();
219         String cmCode = getContractManagerCode().toString();
220         String vendorName = StringUtils.trimToEmpty(getVendorName());
221         String totalAmount = getTotalDollarAmount().toString();
222         PurApAccountingLine accountingLine = getFirstAccount();
223         String chartAcctCode = accountingLine != null ? accountingLine.getChartOfAccountsCode() : "";
224         String accountNumber = accountingLine != null ? accountingLine.getAccountNumber() : "";
225         String chartCode = getChartOfAccountsCode();
226         String orgCode = getOrganizationCode();
227         String deliveryCampus = getDeliveryCampus() != null ? getDeliveryCampus().getCampus().getShortName() : "";
228         String documentTitle = "";
229 
230         Set<String> nodeNames = this.getFinancialSystemDocumentHeader().getWorkflowDocument().getCurrentNodeNames();
231 
232         String routeLevel = "";
233         if (nodeNames.size() >= 1) {
234             routeLevel = nodeNames.iterator().next();
235         }
236 
237         if (StringUtils.equals(getApplicationDocumentStatus(), PurchaseOrderStatuses.APPDOC_OPEN)) {
238             documentTitle = super.getDocumentTitle();
239         } else if (routeLevel.equals(PurchaseOrderStatuses.NODE_BUDGET_OFFICE_REVIEW) || routeLevel.equals(PurchaseOrderStatuses.NODE_CONTRACTS_AND_GRANTS_REVIEW)) {
240             // Budget & C&G approval levels
241             documentTitle = "PO: " + poNumber + " Account Number: " + chartAcctCode + "-" + accountNumber + " Dept: " + chartCode + "-" + orgCode + " Delivery Campus: " + deliveryCampus;
242         } else if (routeLevel.equals(PurchaseOrderStatuses.NODE_VENDOR_TAX_REVIEW)) {
243             // Tax approval level
244             documentTitle = "Vendor: " + vendorName + " PO: " + poNumber + " Account Number: " + chartCode + "-" + accountNumber + " Dept: " + chartCode + "-" + orgCode + " Delivery Campus: " + deliveryCampus;
245         } else {
246             documentTitle += "PO: " + poNumber + " Contract Manager: " + cmCode + " Vendor: " + vendorName + " Amount: " + totalAmount;
247         }
248 
249         return documentTitle;
250     }
251 
252     /**
253      * @see org.kuali.ole.sys.document.AccountingDocument#getSourceAccountingLineClass()
254      */
255     @Override
256     public Class getSourceAccountingLineClass() {
257         //NOTE: do not do anything with this method as it is used by routing etc!
258         return super.getSourceAccountingLineClass();
259     }
260 
261     /**
262      * Returns the first PO item's first accounting line (assuming the item list is sequentially ordered).
263      *
264      * @return - The first accounting line of the first PO item.
265      */
266     protected PurApAccountingLine getFirstAccount() {
267         // loop through items, and pick the first item with non-empty accounting lines
268         if (getItems() != null && !getItems().isEmpty()) {
269             for (Iterator iter = getItems().iterator(); iter.hasNext(); ) {
270                 PurchaseOrderItem item = (PurchaseOrderItem) iter.next();
271                 if (item.isConsideredEntered() && item.getSourceAccountingLines() != null && !item.getSourceAccountingLines().isEmpty()) {
272                     // accounting lines are not empty so pick the first account
273                     PurApAccountingLine accountingLine = item.getSourceAccountingLine(0);
274                     accountingLine.refreshNonUpdateableReferences();
275                     return accountingLine;
276                 }
277             }
278         }
279         return null;
280     }
281 
282     public String getAssignedUserPrincipalId() {
283         return assignedUserPrincipalId;
284     }
285 
286     public void setAssignedUserPrincipalId(String assignedUserPrincipalId) {
287         this.assignedUserPrincipalId = assignedUserPrincipalId;
288     }
289 
290     public String getAssignedUserPrincipalName() {
291         // init this field when PO is first loaded and assigned user exists in PO
292         if (assignedUserPrincipalName == null && assignedUserPrincipalId != null) {
293             // extra caution in case ref obj didn't get refreshed
294             //if (assignedUser == null)
295             //    this.refreshReferenceObject("assignedUser");
296             Person assignedUser = SpringContext.getBean(PersonService.class).getPerson(assignedUserPrincipalId);
297             if (assignedUser != null) {
298                 this.assignedUserPrincipalName = assignedUser.getPrincipalName();
299             } else {
300                 assignedUserPrincipalName = null;
301             }
302 
303         }
304         // otherwise return its current value directly
305         return assignedUserPrincipalName;
306     }
307 
308     public void setAssignedUserPrincipalName(String assignedUserPrincipalName) {
309         this.assignedUserPrincipalName = assignedUserPrincipalName;
310         // each time this field changes we need to update the assigned user ID and ref obj to keep consistent
311         // this code can be moved to where PO is saved and with validation too, which may be more appropriate
312         Person assignedUser = null;
313         if (assignedUserPrincipalName != null) {
314             assignedUser = SpringContext.getBean(PersonService.class).getPersonByPrincipalName(assignedUserPrincipalName);
315         }
316         if (assignedUser != null) {
317             assignedUserPrincipalId = assignedUser.getPrincipalId();
318         } else {
319             assignedUserPrincipalId = null;
320         }
321     }
322 
323     public boolean getAssigningSensitiveData() {
324         return assigningSensitiveData;
325     }
326 
327     public void setAssigningSensitiveData(boolean assigningSensitiveData) {
328         this.assigningSensitiveData = assigningSensitiveData;
329     }
330 
331     public List<PurchaseOrderSensitiveData> getPurchaseOrderSensitiveData() {
332         Map fieldValues = new HashMap();
333         fieldValues.put(PurapPropertyConstants.PURAP_DOC_ID, getPurapDocumentIdentifier());
334         return new ArrayList<PurchaseOrderSensitiveData>(SpringContext.getBean(BusinessObjectService.class).findMatching(PurchaseOrderSensitiveData.class, fieldValues));
335     }
336 
337     public void setPurchaseOrderSensitiveData(List<PurchaseOrderSensitiveData> purchaseOrderSensitiveData) {
338         this.purchaseOrderSensitiveData = purchaseOrderSensitiveData;
339     }
340 
341     public ContractManager getContractManager() {
342         if (ObjectUtils.isNull(contractManager)) {
343             refreshReferenceObject(PurapPropertyConstants.CONTRACT_MANAGER);
344         }
345         return contractManager;
346     }
347 
348     public void setContractManager(ContractManager contractManager) {
349         this.contractManager = contractManager;
350     }
351 
352     public Integer getContractManagerCode() {
353         return contractManagerCode;
354     }
355 
356     public void setContractManagerCode(Integer contractManagerCode) {
357         this.contractManagerCode = contractManagerCode;
358     }
359 
360     /**
361      * @see org.kuali.ole.module.purap.document.PurchasingDocumentBase#buildListOfDeletionAwareLists()
362      */
363     @Override
364     public List buildListOfDeletionAwareLists() {
365         List managedLists = super.buildListOfDeletionAwareLists();
366         managedLists.add(this.getGeneralLedgerPendingEntries());
367         if (allowDeleteAwareCollection) {
368             managedLists.add(this.getPurchaseOrderVendorQuotes());
369             // MSU Contribution DTT-2960 OLEMI-8608 OLECNTRB-954
370             managedLists.add(this.getPurchaseOrderVendorStipulations());
371         }
372         return managedLists;
373     }
374 
375     /**
376      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getOverrideWorkflowButtons()
377      */
378     @Override
379     public Boolean getOverrideWorkflowButtons() {
380         if (ObjectUtils.isNull(super.getOverrideWorkflowButtons())) {
381             // should only be null on the first call... never after
382             setOverrideWorkflowButtons(Boolean.TRUE);
383         }
384         return super.getOverrideWorkflowButtons();
385     }
386 
387 
388     /**
389      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#customPrepareForSave()
390      */
391     @Override
392     public void customPrepareForSave(KualiDocumentEvent event) {
393         super.customPrepareForSave(event);
394         if (ObjectUtils.isNull(getPurapDocumentIdentifier())) {
395             // need retrieve the next available PO id to save in GL entries (only do if purap id is null which should be on first
396             // save)
397             SequenceAccessorService sas = SpringContext.getBean(SequenceAccessorService.class);
398             Long poSequenceNumber = sas.getNextAvailableSequenceNumber("PO_ID", this.getClass());
399             setPurapDocumentIdentifier(poSequenceNumber.intValue());
400         }
401 
402         // Set outstanding encumbered quantity/amount on items
403         for (Iterator items = this.getItems().iterator(); items.hasNext(); ) {
404             PurchaseOrderItem item = (PurchaseOrderItem) items.next();
405 
406             // Set quantities
407             item.setItemOutstandingEncumberedQuantity(item.getItemQuantity());
408             if (item.getItemInvoicedTotalQuantity() == null) {
409                 item.setItemInvoicedTotalQuantity(KualiDecimal.ZERO);
410             }
411             if (item.getItemInvoicedTotalAmount() == null) {
412                 item.setItemInvoicedTotalAmount(KualiDecimal.ZERO);
413             }
414 
415             // Set amount
416             item.setItemOutstandingEncumberedAmount(item.getTotalAmount() == null ? KualiDecimal.ZERO : item.getTotalAmount());
417 
418             List accounts = item.getSourceAccountingLines();
419             Collections.sort(accounts);
420 
421             for (Iterator iterator = accounts.iterator(); iterator.hasNext(); ) {
422                 PurchaseOrderAccount account = (PurchaseOrderAccount) iterator.next();
423                 if (!account.isEmpty()) {
424                     account.setItemAccountOutstandingEncumbranceAmount(account.getAmount());
425                 }
426             }// endfor accounts
427         }// endfor items
428 
429         this.setSourceAccountingLines(SpringContext.getBean(PurapAccountingService.class).generateSummaryWithNoZeroTotals(this.getItems()));
430     }// end customPrepareForSave(KualiDocumentEvent)
431 
432     /**
433      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#prepareForSave()
434      */
435     @Override
436     public void prepareForSave(KualiDocumentEvent event) {
437         WorkflowDocument workFlowDocument = getDocumentHeader().getWorkflowDocument();
438         String documentType = workFlowDocument.getDocumentTypeName();
439 
440 
441         if ((documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_DOCUMENT)) ||
442                 (documentType.equals(PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_SPLIT_DOCUMENT))) {
443             if (workFlowDocument.isCanceled()) {
444                 // if doc is FINAL or canceled, saving should not be creating GL entries
445                 setGeneralLedgerPendingEntries(new ArrayList());
446             } else if (workFlowDocument.isFinal()) {
447             } else {
448                 super.prepareForSave(event);
449             }
450         }
451     }
452 
453     /**
454      * Sets default values for APO.
455      */
456     public void setDefaultValuesForAPO() {
457         this.setPurchaseOrderAutomaticIndicator(Boolean.TRUE);
458         if (!RequisitionSources.B2B.equals(this.getRequisitionSourceCode())) {
459             String paramName = PurapParameterConstants.DEFAULT_APO_VENDOR_CHOICE;
460             String paramValue = SpringContext.getBean(ParameterService.class).getParameterValueAsString(PurchaseOrderDocument.class, paramName);
461             this.setPurchaseOrderVendorChoiceCode(paramValue);
462         }
463     }
464 
465     /**
466      * Populates this Purchase Order from the related Requisition Document.
467      *
468      * @param requisitionDocument the Requisition Document from which field values are copied.
469      */
470     public void populatePurchaseOrderFromRequisition(RequisitionDocument requisitionDocument) {
471         this.getDocumentHeader().setOrganizationDocumentNumber(requisitionDocument.getDocumentHeader().getOrganizationDocumentNumber());
472         this.getDocumentHeader().setDocumentDescription(requisitionDocument.getDocumentHeader().getDocumentDescription());
473         this.getDocumentHeader().setExplanation(requisitionDocument.getDocumentHeader().getExplanation());
474 
475         this.setBillingName(requisitionDocument.getBillingName());
476         this.setBillingLine1Address(requisitionDocument.getBillingLine1Address());
477         this.setBillingLine2Address(requisitionDocument.getBillingLine2Address());
478         this.setBillingCityName(requisitionDocument.getBillingCityName());
479         this.setBillingStateCode(requisitionDocument.getBillingStateCode());
480         this.setBillingPostalCode(requisitionDocument.getBillingPostalCode());
481         this.setBillingCountryCode(requisitionDocument.getBillingCountryCode());
482         this.setBillingPhoneNumber(requisitionDocument.getBillingPhoneNumber());
483         this.setBillingEmailAddress(requisitionDocument.getBillingEmailAddress());
484 
485         this.setReceivingName(requisitionDocument.getReceivingName());
486         this.setReceivingCityName(requisitionDocument.getReceivingCityName());
487         this.setReceivingLine1Address(requisitionDocument.getReceivingLine1Address());
488         this.setReceivingLine2Address(requisitionDocument.getReceivingLine2Address());
489         this.setReceivingStateCode(requisitionDocument.getReceivingStateCode());
490         this.setReceivingPostalCode(requisitionDocument.getReceivingPostalCode());
491         this.setReceivingCountryCode(requisitionDocument.getReceivingCountryCode());
492         this.setAddressToVendorIndicator(requisitionDocument.getAddressToVendorIndicator());
493 
494         this.setDeliveryBuildingCode(requisitionDocument.getDeliveryBuildingCode());
495         this.setDeliveryBuildingRoomNumber(requisitionDocument.getDeliveryBuildingRoomNumber());
496         this.setDeliveryBuildingName(requisitionDocument.getDeliveryBuildingName());
497         this.setDeliveryCampusCode(requisitionDocument.getDeliveryCampusCode());
498         this.setDeliveryCityName(requisitionDocument.getDeliveryCityName());
499         this.setDeliveryCountryCode(requisitionDocument.getDeliveryCountryCode());
500         this.setDeliveryInstructionText(requisitionDocument.getDeliveryInstructionText());
501         this.setDeliveryBuildingLine1Address(requisitionDocument.getDeliveryBuildingLine1Address());
502         this.setDeliveryBuildingLine2Address(requisitionDocument.getDeliveryBuildingLine2Address());
503         this.setDeliveryPostalCode(requisitionDocument.getDeliveryPostalCode());
504         this.setDeliveryRequiredDate(requisitionDocument.getDeliveryRequiredDate());
505         this.setDeliveryRequiredDateReasonCode(requisitionDocument.getDeliveryRequiredDateReasonCode());
506         this.setDeliveryStateCode(requisitionDocument.getDeliveryStateCode());
507         this.setDeliveryToEmailAddress(requisitionDocument.getDeliveryToEmailAddress());
508         this.setDeliveryToName(requisitionDocument.getDeliveryToName());
509         this.setDeliveryToPhoneNumber(requisitionDocument.getDeliveryToPhoneNumber());
510         this.setDeliveryBuildingOtherIndicator(requisitionDocument.isDeliveryBuildingOtherIndicator());
511 
512         this.setPurchaseOrderBeginDate(requisitionDocument.getPurchaseOrderBeginDate());
513         this.setPurchaseOrderCostSourceCode(requisitionDocument.getPurchaseOrderCostSourceCode());
514         this.setPostingYear(requisitionDocument.getPostingYear());
515         this.setPurchaseOrderEndDate(requisitionDocument.getPurchaseOrderEndDate());
516         this.setChartOfAccountsCode(requisitionDocument.getChartOfAccountsCode());
517         this.setDocumentFundingSourceCode(requisitionDocument.getDocumentFundingSourceCode());
518         this.setInstitutionContactEmailAddress(requisitionDocument.getInstitutionContactEmailAddress());
519         this.setInstitutionContactName(requisitionDocument.getInstitutionContactName());
520         this.setInstitutionContactPhoneNumber(requisitionDocument.getInstitutionContactPhoneNumber());
521         this.setNonInstitutionFundAccountNumber(requisitionDocument.getNonInstitutionFundAccountNumber());
522         this.setNonInstitutionFundChartOfAccountsCode(requisitionDocument.getNonInstitutionFundChartOfAccountsCode());
523         this.setNonInstitutionFundOrgChartOfAccountsCode(requisitionDocument.getNonInstitutionFundOrgChartOfAccountsCode());
524         this.setNonInstitutionFundOrganizationCode(requisitionDocument.getNonInstitutionFundOrganizationCode());
525         this.setOrganizationCode(requisitionDocument.getOrganizationCode());
526         this.setRecurringPaymentTypeCode(requisitionDocument.getRecurringPaymentTypeCode());
527         this.setRequestorPersonEmailAddress(requisitionDocument.getRequestorPersonEmailAddress());
528         this.setRequestorPersonName(requisitionDocument.getRequestorPersonName());
529         this.setRequestorPersonPhoneNumber(requisitionDocument.getRequestorPersonPhoneNumber());
530         this.setRequisitionIdentifier(requisitionDocument.getPurapDocumentIdentifier());
531         this.setPurchaseOrderTotalLimit(requisitionDocument.getPurchaseOrderTotalLimit());
532         this.setPurchaseOrderTransmissionMethodCode(requisitionDocument.getPurchaseOrderTransmissionMethodCode());
533         this.setUseTaxIndicator(requisitionDocument.isUseTaxIndicator());
534         this.setPurchaseOrderTypeId(requisitionDocument.getPurchaseOrderTypeId());
535         this.setVendorCityName(requisitionDocument.getVendorCityName());
536         this.setVendorContractGeneratedIdentifier(requisitionDocument.getVendorContractGeneratedIdentifier());
537         this.setVendorCountryCode(requisitionDocument.getVendorCountryCode());
538         this.setVendorCustomerNumber(requisitionDocument.getVendorCustomerNumber());
539         this.setVendorAttentionName(requisitionDocument.getVendorAttentionName());
540         this.setVendorDetailAssignedIdentifier(requisitionDocument.getVendorDetailAssignedIdentifier());
541         this.setVendorFaxNumber(requisitionDocument.getVendorFaxNumber());
542         this.setVendorHeaderGeneratedIdentifier(requisitionDocument.getVendorHeaderGeneratedIdentifier());
543         this.setVendorLine1Address(requisitionDocument.getVendorLine1Address());
544         this.setVendorLine2Address(requisitionDocument.getVendorLine2Address());
545         this.setVendorAddressInternationalProvinceName(requisitionDocument.getVendorAddressInternationalProvinceName());
546         this.setVendorName(requisitionDocument.getVendorName());
547         this.setVendorNoteText(requisitionDocument.getVendorNoteText());
548         this.setVendorPhoneNumber(requisitionDocument.getVendorPhoneNumber());
549         this.setVendorPostalCode(requisitionDocument.getVendorPostalCode());
550         this.setVendorStateCode(requisitionDocument.getVendorStateCode());
551         this.setVendorRestrictedIndicator(requisitionDocument.getVendorRestrictedIndicator());
552         this.setJustification(requisitionDocument.getJustification());
553 
554         this.setExternalOrganizationB2bSupplierIdentifier(requisitionDocument.getExternalOrganizationB2bSupplierIdentifier());
555         this.setRequisitionSourceCode(requisitionDocument.getRequisitionSourceCode());
556         this.setAccountsPayablePurchasingDocumentLinkIdentifier(requisitionDocument.getAccountsPayablePurchasingDocumentLinkIdentifier());
557         this.setReceivingDocumentRequiredIndicator(requisitionDocument.isReceivingDocumentRequiredIndicator());
558         this.setPaymentRequestPositiveApprovalIndicator(requisitionDocument.isPaymentRequestPositiveApprovalIndicator());
559         /*this.setLicensingRequirementCode(requisitionDocument.getLicensingRequirementCode());*/
560         /*this.setLicensingRequirementIndicator(requisitionDocument.isLicensingRequirementIndicator());*/
561 
562         setApplicationDocumentStatus(PurapConstants.PurchaseOrderStatuses.APPDOC_IN_PROCESS);
563         this.setAccountDistributionMethod(requisitionDocument.getAccountDistributionMethod());
564         // Copy items from requisition (which will copy the item's accounts and capital assets)
565         List<PurchaseOrderItem> items = new ArrayList();
566         for (PurApItem reqItem : ((PurchasingAccountsPayableDocument) requisitionDocument).getItems()) {
567             RequisitionCapitalAssetItem reqCamsItem = (RequisitionCapitalAssetItem) requisitionDocument.getPurchasingCapitalAssetItemByItemIdentifier(reqItem.getItemIdentifier().intValue());
568             items.add(new PurchaseOrderItem((RequisitionItem) reqItem, this, reqCamsItem));
569         }
570         this.setItems(items);
571 
572         // Copy capital asset information that is directly off the document.
573         this.setCapitalAssetSystemTypeCode(requisitionDocument.getCapitalAssetSystemTypeCode());
574         this.setCapitalAssetSystemStateCode(requisitionDocument.getCapitalAssetSystemStateCode());
575         for (CapitalAssetSystem capitalAssetSystem : requisitionDocument.getPurchasingCapitalAssetSystems()) {
576             this.getPurchasingCapitalAssetSystems().add(new PurchaseOrderCapitalAssetSystem(capitalAssetSystem));
577         }
578 
579         this.fixItemReferences();
580     }
581 
582     /**
583      * Returns the Vendor Stipulation at the specified index in this Purchase Order.
584      *
585      * @param index the specified index.
586      * @return the Vendor Stipulation at the specified index.
587      */
588     public PurchaseOrderVendorStipulation getPurchaseOrderVendorStipulation(int index) {
589         while (getPurchaseOrderVendorStipulations().size() <= index) {
590             getPurchaseOrderVendorStipulations().add(new PurchaseOrderVendorStipulation());
591         }
592         return purchaseOrderVendorStipulations.get(index);
593     }
594 
595     @Override
596     public List<String> getWorkflowEngineDocumentIdsToLock() {
597         List<String> docIdStrings = new ArrayList<String>();
598         docIdStrings.add(getDocumentNumber());
599         String currentDocumentTypeName = this.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
600 
601         List<PurchaseOrderView> relatedPoViews = getRelatedViews().getRelatedPurchaseOrderViews();
602         for (PurchaseOrderView poView : relatedPoViews) {
603             //don't lock related PO's if this is a split PO that's in process
604             if (!(PurapConstants.PurchaseOrderStatuses.APPDOC_IN_PROCESS.equals(this.getApplicationDocumentStatus()) && PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_SPLIT_DOCUMENT.equals(currentDocumentTypeName))) {
605                 docIdStrings.add(poView.getDocumentNumber());
606             }
607         }
608 
609         return docIdStrings;
610     }
611 
612     /**
613      * @see org.kuali.ole.sys.document.GeneralLedgerPostingDocumentBase#doRouteStatusChange()
614      */
615     @Override
616     public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) {
617         LOG.debug("doRouteStatusChange() started");
618         super.doRouteStatusChange(statusChangeEvent);
619         String currentDocumentTypeName = this.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
620         // child classes need to call super, but we don't want to inherit the post-processing done by this PO class other than to the Split
621         if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isFinal() && !(currentDocumentTypeName.equals(OLEConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_RETRANSMIT))) {
622 
623             OleDocstoreHelperService oleDocstoreHelperService = SpringContext
624                     .getBean(OleDocstoreHelperService.class);
625             List<OlePurchaseOrderItem> items = this.getItems();
626             StringBuffer cancellationNote = new StringBuffer();
627             List<Note> noteList = new ArrayList<>();
628             for (OlePurchaseOrderItem item : items) {
629                 if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
630                     if (currentDocumentTypeName.equalsIgnoreCase(PurchaseOrderDocTypes.PURCHASE_ORDER_VOID_DOCUMENT)) {
631                         for (Note noteObj :this.getNotes()) {
632                             if (noteObj.getNoteText().contains(PODocumentsStrings.VOID_NOTE_PREFIX)) {
633                                 noteList.add(noteObj);
634                             }
635                         }
636                         //Both Cancellation reason and free text are saved in Docstore's item record.
637                         if (noteList.size()>1) {
638                             for(int noteObj=0; noteObj<noteList.size(); noteObj++) {
639                                 String[] attachedNote = noteList.get(noteObj).getNoteText().split(PODocumentsStrings.VOID_NOTE_PREFIX);
640                                 cancellationNote = cancellationNote.append(attachedNote[1].trim());
641                                 if (noteObj==0) {
642                                     cancellationNote = cancellationNote.append(OLEConstants.COMMA);
643                                 }
644                             }
645                         } else {
646                             String[] attachedNote = noteList.get(0).getNoteText().split(PODocumentsStrings.VOID_NOTE_PREFIX);
647                             cancellationNote = cancellationNote.append(attachedNote[1].trim());
648                         }
649                     }
650                     if(currentDocumentTypeName.equals(OLEConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER)) {
651                         oleDocstoreHelperService.createOrUpdateDocStoreBasedOnLocation(this, item, currentDocumentTypeName, cancellationNote.toString());
652                     }
653                     cancellationNote.delete(0,cancellationNote.length());
654                     noteList.clear();
655                 }
656             }
657         }
658         if (PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_DOCUMENT.equals(currentDocumentTypeName) || PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_SPLIT_DOCUMENT.equals(currentDocumentTypeName)) {
659             try {
660                 // DOCUMENT PROCESSED
661                 if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isProcessed()) {
662                     setPurchaseOrderLastTransmitTimestamp(SpringContext.getBean(DateTimeService.class).getCurrentTimestamp());
663                     SpringContext.getBean(PurchaseOrderService.class).completePurchaseOrder(this);
664                     if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isProcessed() && !this.getFinancialSystemDocumentHeader().getWorkflowDocument().isFinal()) {
665                         SpringContext.getBean(WorkflowDocumentService.class).saveRoutingData(this.getFinancialSystemDocumentHeader().getWorkflowDocument());
666                     }
667                 }
668                 // DOCUMENT DISAPPROVED
669                 else if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isDisapproved()) {
670                     String nodeName = SpringContext.getBean(WorkflowDocumentService.class).getCurrentRouteLevelName(this.getFinancialSystemDocumentHeader().getWorkflowDocument());
671                     String disapprovalStatus = PurapConstants.PurchaseOrderStatuses.getPurchaseOrderAppDocDisapproveStatuses().get(nodeName);
672 
673                     if (ObjectUtils.isNotNull(disapprovalStatus)) {
674                         //update the appDocStatus and save the workflow data
675                         updateAndSaveAppDocStatus(disapprovalStatus);
676 
677                         RequisitionDocument req = getPurApSourceDocumentIfPossible();
678                         String principalId = req.getFinancialSystemDocumentHeader().getWorkflowDocument()
679                                 .getRoutedByPrincipalId();
680                         appSpecificRouteDocumentToUser(this.getFinancialSystemDocumentHeader().getWorkflowDocument(),
681                                 principalId,
682                                 "Notification of Order Disapproval for Requisition " + req.getPurapDocumentIdentifier()
683                                         + "(document id " + req.getDocumentNumber() + ")", "Requisition Routed By User");
684                         return;
685                     }
686                     logAndThrowRuntimeException("No status found to set for document being disapproved in node '" + nodeName + "'");
687                 }
688                 // DOCUMENT CANCELED
689                 else if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isCanceled()) {
690                     updateAndSaveAppDocStatus(PurchaseOrderStatuses.APPDOC_CANCELLED);
691                 }
692             } catch (WorkflowException e) {
693                 logAndThrowRuntimeException("Error saving routing data while saving document with id " + getDocumentNumber(), e);
694             }
695         }
696     }
697 
698     /**
699      * Returns the name of the current route node.
700      *
701      * @param wd the current workflow document.
702      * @return the name of the current route node.
703      * @throws WorkflowException
704      */
705     protected String getCurrentRouteNodeName(WorkflowDocument wd) throws WorkflowException {
706         ArrayList<String> nodeNames = new ArrayList(wd.getCurrentNodeNames());
707         if ((nodeNames == null) || (nodeNames.size() == 0)) {
708             return null;
709         } else {
710             return nodeNames.get(0);
711         }
712     }
713 
714     /**
715      * Sends FYI workflow request to the given user on this document.
716      *
717      * @param workflowDocument the associated workflow document.
718      * @param userNetworkId    the network ID of the user to be sent to.
719      * @param annotation       the annotation notes contained in this document.
720      * @param responsibility   the responsibility specified in the request.
721      * @throws WorkflowException
722      */
723     public void appSpecificRouteDocumentToUser(WorkflowDocument workflowDocument, String routePrincipalName,
724                                                String annotation, String responsibility) throws WorkflowException {
725         if (ObjectUtils.isNotNull(workflowDocument)) {
726             String annotationNote = (ObjectUtils.isNull(annotation)) ? "" : annotation;
727             String responsibilityNote = (ObjectUtils.isNull(responsibility)) ? "" : responsibility;
728             String currentNodeName = getCurrentRouteNodeName(workflowDocument);
729             // Principal principal = SpringContext.getBean(IdentityManagementService.class).getPrincipalByPrincipalName(userNetworkId);
730             workflowDocument.adHocToPrincipal(ActionRequestType.FYI, currentNodeName, annotationNote,
731                     routePrincipalName, responsibilityNote, true);
732         }
733     }
734 
735     /**
736      * @see org.kuali.rice.kns.document.DocumentBase#handleRouteLevelChange(org.kuali.rice.kew.clientapp.vo.DocumentRouteLevelChangeDTO)
737      */
738     @Override
739     public void doRouteLevelChange(DocumentRouteLevelChange levelChangeEvent) {
740         /*LOG.debug("handleRouteLevelChange() started");*/
741         super.doRouteLevelChange(levelChangeEvent);
742 
743         // JHK : This has been commented out in KFS 5.0 - standard app doc status logic in KEW handles this
744 
745 //        String newNodeName = levelChangeEvent.getNewNodeName();
746 //        if (StringUtils.isNotBlank(newNodeName)) {
747 //            RoutingReportCriteria.Builder reportCriteriaDTO = RoutingReportCriteria.Builder.createByDocumentId(getDocumentNumber());
748 //            reportCriteriaDTO.setTargetNodeName(newNodeName);
749 //            try {
750 //                NodeDetails newNodeDetails = NodeDetailEnum.getNodeDetailEnumByName(newNodeName);
751 //                if (ObjectUtils.isNotNull(newNodeDetails)) {
752 //                    String newStatusCode = newNodeDetails.getAwaitingStatusCode();
753 //                    if (StringUtils.isNotBlank(newStatusCode)) {
754 //                        if (SpringContext.getBean(WorkflowDocumentActionsService.class).documentWillHaveAtLeastOneActionRequest(reportCriteriaDTO, new String[] { KewApiConstants.ACTION_REQUEST_APPROVE_REQ, KewApiConstants.ACTION_REQUEST_COMPLETE_REQ }, false)) {
755 //                            // if an approve or complete request will be created then we need to set the status as awaiting for
756 //                            // the new node
757 //                            this.setApplicationDocumentStatus(newStatusCode);
758 //
759 //                            SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
760 //                        }
761 //                    }
762 //                }
763 //            }
764 //            catch (WorkflowException e) {
765 //                String errorMsg = "Workflow Error found checking actions requests on document with id " + getDocumentNumber() + ". *** WILL NOT UPDATE PURAP STATUS ***";
766 //                LOG.warn(errorMsg, e);
767 //            }
768 //        }
769     }
770 
771     /**
772      * @see org.kuali.rice.krad.document.DocumentBase#doActionTaken(org.kuali.rice.kew.clientapp.vo.ActionTakenEventDTO)
773      */
774     @Override
775     public void doActionTaken(ActionTakenEvent event) {
776         super.doActionTaken(event);
777         // additional processing
778     }
779 
780     /**
781      * Gets the active items in this Purchase Order.
782      *
783      * @return the list of all active items in this Purchase Order.
784      */
785     public List getItemsActiveOnly() {
786         List returnList = new ArrayList();
787         for (Iterator iter = getItems().iterator(); iter.hasNext(); ) {
788             PurchaseOrderItem item = (PurchaseOrderItem) iter.next();
789             if (item.isItemActiveIndicator()) {
790                 returnList.add(item);
791             }
792         }
793         return returnList;
794     }
795 
796     /**
797      * Gets the active items in this Purchase Order, and sets up the alternate amount for GL entry creation.
798      *
799      * @return the list of all active items in this Purchase Order.
800      */
801     public List getItemsActiveOnlySetupAlternateAmount() {
802         List returnList = new ArrayList();
803         for (Iterator iter = getItems().iterator(); iter.hasNext(); ) {
804             PurchaseOrderItem item = (PurchaseOrderItem) iter.next();
805             if (item.isItemActiveIndicator()) {
806                 for (Object element : item.getSourceAccountingLines()) {
807                     PurchaseOrderAccount account = (PurchaseOrderAccount) element;
808                     account.setAlternateAmountForGLEntryCreation(account.getItemAccountOutstandingEncumbranceAmount());
809                 }
810                 returnList.add(item);
811             }
812         }
813         return returnList;
814     }
815 
816     public Integer getAlternateVendorDetailAssignedIdentifier() {
817         return alternateVendorDetailAssignedIdentifier;
818     }
819 
820     public void setAlternateVendorDetailAssignedIdentifier(Integer alternateVendorDetailAssignedIdentifier) {
821         this.alternateVendorDetailAssignedIdentifier = alternateVendorDetailAssignedIdentifier;
822     }
823 
824     public Integer getAlternateVendorHeaderGeneratedIdentifier() {
825         return alternateVendorHeaderGeneratedIdentifier;
826     }
827 
828     public void setAlternateVendorHeaderGeneratedIdentifier(Integer alternateVendorHeaderGeneratedIdentifier) {
829         this.alternateVendorHeaderGeneratedIdentifier = alternateVendorHeaderGeneratedIdentifier;
830     }
831 
832     public String getAlternateVendorName() {
833         return alternateVendorName;
834     }
835 
836     public void setAlternateVendorName(String alternateVendorName) {
837         this.alternateVendorName = alternateVendorName;
838     }
839 
840     public KualiDecimal getFinalPaymentAmount() {
841         return finalPaymentAmount;
842     }
843 
844     public void setFinalPaymentAmount(KualiDecimal finalPaymentAmount) {
845         this.finalPaymentAmount = finalPaymentAmount;
846     }
847 
848     public Date getFinalPaymentDate() {
849         return finalPaymentDate;
850     }
851 
852     public void setFinalPaymentDate(Date finalPaymentDate) {
853         this.finalPaymentDate = finalPaymentDate;
854     }
855 
856     public KualiDecimal getInitialPaymentAmount() {
857         return initialPaymentAmount;
858     }
859 
860     public void setInitialPaymentAmount(KualiDecimal initialPaymentAmount) {
861         this.initialPaymentAmount = initialPaymentAmount;
862     }
863 
864     public Date getInitialPaymentDate() {
865         return initialPaymentDate;
866     }
867 
868     public void setInitialPaymentDate(Date initialPaymentDate) {
869         this.initialPaymentDate = initialPaymentDate;
870     }
871 
872     public String getPurchaseOrderCommodityDescription() {
873         return purchaseOrderCommodityDescription;
874     }
875 
876     public void setPurchaseOrderCommodityDescription(String purchaseOrderCommodityDescription) {
877         this.purchaseOrderCommodityDescription = purchaseOrderCommodityDescription;
878     }
879 
880     public boolean isPurchaseOrderConfirmedIndicator() {
881         return purchaseOrderConfirmedIndicator;
882     }
883 
884     public void setPurchaseOrderConfirmedIndicator(boolean purchaseOrderConfirmedIndicator) {
885         this.purchaseOrderConfirmedIndicator = purchaseOrderConfirmedIndicator;
886     }
887 
888     public Timestamp getPurchaseOrderCreateTimestamp() {
889         return purchaseOrderCreateTimestamp;
890     }
891 
892     public void setPurchaseOrderCreateTimestamp(Timestamp purchaseOrderCreateTimestamp) {
893         this.purchaseOrderCreateTimestamp = purchaseOrderCreateTimestamp;
894     }
895 
896     public Timestamp getPurchaseOrderInitialOpenTimestamp() {
897         return purchaseOrderInitialOpenTimestamp;
898     }
899 
900     public void setPurchaseOrderInitialOpenTimestamp(Timestamp purchaseOrderInitialOpenDate) {
901         this.purchaseOrderInitialOpenTimestamp = purchaseOrderInitialOpenDate;
902     }
903 
904     public Timestamp getPurchaseOrderLastTransmitTimestamp() {
905         return purchaseOrderLastTransmitTimestamp;
906     }
907 
908     public void setPurchaseOrderLastTransmitTimestamp(Timestamp PurchaseOrderLastTransmitTimestamp) {
909         this.purchaseOrderLastTransmitTimestamp = PurchaseOrderLastTransmitTimestamp;
910     }
911 
912     public Integer getPurchaseOrderPreviousIdentifier() {
913         return purchaseOrderPreviousIdentifier;
914     }
915 
916     public void setPurchaseOrderPreviousIdentifier(Integer purchaseOrderPreviousIdentifier) {
917         this.purchaseOrderPreviousIdentifier = purchaseOrderPreviousIdentifier;
918     }
919 
920     public Date getPurchaseOrderQuoteDueDate() {
921         return purchaseOrderQuoteDueDate;
922     }
923 
924     public void setPurchaseOrderQuoteDueDate(Date purchaseOrderQuoteDueDate) {
925         this.purchaseOrderQuoteDueDate = purchaseOrderQuoteDueDate;
926     }
927 
928     public String getPurchaseOrderQuoteTypeDescription() {
929         String descript = purchaseOrderQuoteTypeCode;
930         if (PurapConstants.QuoteTypes.COMPETITIVE.equals(purchaseOrderQuoteTypeCode)) {
931             descript = QuoteTypeDescriptions.COMPETITIVE;
932         } else if (PurapConstants.QuoteTypes.PRICE_CONFIRMATION.equals(purchaseOrderQuoteTypeCode)) {
933             descript = QuoteTypeDescriptions.PRICE_CONFIRMATION;
934         }
935         return descript;
936     }
937 
938     public String getPurchaseOrderQuoteTypeCode() {
939         return purchaseOrderQuoteTypeCode;
940     }
941 
942     public void setPurchaseOrderQuoteTypeCode(String purchaseOrderQuoteTypeCode) {
943         this.purchaseOrderQuoteTypeCode = purchaseOrderQuoteTypeCode;
944     }
945 
946     public String getPurchaseOrderQuoteVendorNoteText() {
947         return purchaseOrderQuoteVendorNoteText;
948     }
949 
950     public void setPurchaseOrderQuoteVendorNoteText(String purchaseOrderQuoteVendorNoteText) {
951         this.purchaseOrderQuoteVendorNoteText = purchaseOrderQuoteVendorNoteText;
952     }
953 
954     public String getPurchaseOrderVendorChoiceCode() {
955         return purchaseOrderVendorChoiceCode;
956     }
957 
958     public void setPurchaseOrderVendorChoiceCode(String purchaseOrderVendorChoiceCode) {
959         this.purchaseOrderVendorChoiceCode = purchaseOrderVendorChoiceCode;
960     }
961 
962     public KualiDecimal getRecurringPaymentAmount() {
963         return recurringPaymentAmount;
964     }
965 
966     public void setRecurringPaymentAmount(KualiDecimal recurringPaymentAmount) {
967         this.recurringPaymentAmount = recurringPaymentAmount;
968     }
969 
970     public Date getRecurringPaymentDate() {
971         return recurringPaymentDate;
972     }
973 
974     public void setRecurringPaymentDate(Date recurringPaymentDate) {
975         this.recurringPaymentDate = recurringPaymentDate;
976     }
977 
978     public String getRecurringPaymentFrequencyCode() {
979         return recurringPaymentFrequencyCode;
980     }
981 
982     public void setRecurringPaymentFrequencyCode(String recurringPaymentFrequencyCode) {
983         this.recurringPaymentFrequencyCode = recurringPaymentFrequencyCode;
984     }
985 
986     public Integer getRequisitionIdentifier() {
987         return requisitionIdentifier;
988     }
989 
990     public void setRequisitionIdentifier(Integer requisitionIdentifier) {
991         this.requisitionIdentifier = requisitionIdentifier;
992     }
993 
994     public PurchaseOrderVendorChoice getPurchaseOrderVendorChoice() {
995         return purchaseOrderVendorChoice;
996     }
997 
998     public void setPurchaseOrderVendorChoice(PurchaseOrderVendorChoice purchaseOrderVendorChoice) {
999         this.purchaseOrderVendorChoice = purchaseOrderVendorChoice;
1000     }
1001 
1002     public RecurringPaymentFrequency getRecurringPaymentFrequency() {
1003         return recurringPaymentFrequency;
1004     }
1005 
1006     public void setRecurringPaymentFrequency(RecurringPaymentFrequency recurringPaymentFrequency) {
1007         this.recurringPaymentFrequency = recurringPaymentFrequency;
1008     }
1009 
1010     public PaymentTermType getVendorPaymentTerms() {
1011         return vendorPaymentTerms;
1012     }
1013 
1014     public void setVendorPaymentTerms(PaymentTermType vendorPaymentTerms) {
1015         this.vendorPaymentTerms = vendorPaymentTerms;
1016     }
1017 
1018     public ShippingPaymentTerms getVendorShippingPaymentTerms() {
1019         return vendorShippingPaymentTerms;
1020     }
1021 
1022     public void setVendorShippingPaymentTerms(ShippingPaymentTerms vendorShippingPaymentTerms) {
1023         this.vendorShippingPaymentTerms = vendorShippingPaymentTerms;
1024     }
1025 
1026     public ShippingTitle getVendorShippingTitle() {
1027 
1028         if (ObjectUtils.isNull(vendorShippingTitle)) {
1029             this.refreshReferenceObject("vendorShippingTitle");
1030         }
1031 
1032         return vendorShippingTitle;
1033     }
1034 
1035     public void setVendorShippingTitle(ShippingTitle vendorShippingTitle) {
1036         this.vendorShippingTitle = vendorShippingTitle;
1037     }
1038 
1039     public List getPurchaseOrderVendorStipulations() {
1040         return purchaseOrderVendorStipulations;
1041     }
1042 
1043     public String getStatusChange() {
1044         return statusChange;
1045     }
1046 
1047     public void setPurchaseOrderVendorStipulations(List purchaseOrderVendorStipulations) {
1048         this.purchaseOrderVendorStipulations = purchaseOrderVendorStipulations;
1049     }
1050 
1051     public List<PurchaseOrderVendorQuote> getPurchaseOrderVendorQuotes() {
1052         return purchaseOrderVendorQuotes;
1053     }
1054 
1055     public void setPurchaseOrderVendorQuotes(List<PurchaseOrderVendorQuote> purchaseOrderVendorQuotes) {
1056         this.purchaseOrderVendorQuotes = purchaseOrderVendorQuotes;
1057     }
1058 
1059     public PurchaseOrderVendorQuote getPurchaseOrderVendorQuote(int index) {
1060         while (getPurchaseOrderVendorQuotes().size() <= index) {
1061             getPurchaseOrderVendorQuotes().add(new PurchaseOrderVendorQuote());
1062         }
1063         return purchaseOrderVendorQuotes.get(index);
1064     }
1065 
1066     public void setStatusChange(String statusChange) {
1067         this.statusChange = statusChange;
1068     }
1069 
1070     public String getPurchaseOrderRetransmissionMethodCode() {
1071         return purchaseOrderRetransmissionMethodCode;
1072     }
1073 
1074     public void setPurchaseOrderRetransmissionMethodCode(String purchaseOrderRetransmissionMethodCode) {
1075         this.purchaseOrderRetransmissionMethodCode = purchaseOrderRetransmissionMethodCode;
1076     }
1077 
1078     public String getRetransmitHeader() {
1079         return retransmitHeader;
1080     }
1081 
1082     public void setRetransmitHeader(String retransmitHeader) {
1083         this.retransmitHeader = retransmitHeader;
1084     }
1085 
1086     public boolean isPendingActionIndicator() {
1087         return pendingActionIndicator;
1088     }
1089 
1090     public void setPendingActionIndicator(boolean pendingActionIndicator) {
1091         this.pendingActionIndicator = pendingActionIndicator;
1092     }
1093 
1094     public boolean isPurchaseOrderCurrentIndicator() {
1095         return purchaseOrderCurrentIndicator;
1096     }
1097 
1098     public void setPurchaseOrderCurrentIndicator(boolean purchaseOrderCurrentIndicator) {
1099         this.purchaseOrderCurrentIndicator = purchaseOrderCurrentIndicator;
1100     }
1101 
1102     public Timestamp getPurchaseOrderFirstTransmissionTimestamp() {
1103         return purchaseOrderFirstTransmissionTimestamp;
1104     }
1105 
1106     public void setPurchaseOrderFirstTransmissionTimestamp(Timestamp purchaseOrderFirstTransmissionTimestamp) {
1107         this.purchaseOrderFirstTransmissionTimestamp = purchaseOrderFirstTransmissionTimestamp;
1108     }
1109 
1110     /**
1111      * Gets the purchaseOrderQuoteAwardedDate attribute.
1112      *
1113      * @return Returns the purchaseOrderQuoteAwardedDate.
1114      */
1115     public Date getPurchaseOrderQuoteAwardedDate() {
1116         return purchaseOrderQuoteAwardedDate;
1117     }
1118 
1119     /**
1120      * Sets the purchaseOrderQuoteAwardedDate attribute value.
1121      *
1122      * @param purchaseOrderQuoteAwardedDate The purchaseOrderQuoteAwardedDate to set.
1123      */
1124     public void setPurchaseOrderQuoteAwardedDate(Date purchaseOrderQuoteAwardedDate) {
1125         this.purchaseOrderQuoteAwardedDate = purchaseOrderQuoteAwardedDate;
1126     }
1127 
1128     /**
1129      * Gets the purchaseOrderQuoteInitializationDate attribute.
1130      *
1131      * @return Returns the purchaseOrderQuoteInitializationDate.
1132      */
1133     public Date getPurchaseOrderQuoteInitializationDate() {
1134         return purchaseOrderQuoteInitializationDate;
1135     }
1136 
1137     /**
1138      * Sets the purchaseOrderQuoteInitializationDate attribute value.
1139      *
1140      * @param purchaseOrderQuoteInitializationDate
1141      *         The purchaseOrderQuoteInitializationDate to set.
1142      */
1143     public void setPurchaseOrderQuoteInitializationDate(Date purchaseOrderQuoteInitializationDate) {
1144         this.purchaseOrderQuoteInitializationDate = purchaseOrderQuoteInitializationDate;
1145     }
1146 
1147     /**
1148      * Gets the alternateVendorNumber attribute.
1149      *
1150      * @return Returns the alternateVendorNumber.
1151      */
1152     public String getAlternateVendorNumber() {
1153         String hdrGenId = "";
1154         String detAssgndId = "";
1155         String vendorNumber = "";
1156         if (this.alternateVendorHeaderGeneratedIdentifier != null) {
1157             hdrGenId = this.alternateVendorHeaderGeneratedIdentifier.toString();
1158         }
1159         if (this.alternateVendorDetailAssignedIdentifier != null) {
1160             detAssgndId = this.alternateVendorDetailAssignedIdentifier.toString();
1161         }
1162         if (!StringUtils.isEmpty(hdrGenId) && !StringUtils.isEmpty(detAssgndId)) {
1163             vendorNumber = hdrGenId + VendorConstants.DASH + detAssgndId;
1164         }
1165         return vendorNumber;
1166     }
1167 
1168     /**
1169      * Sets the alternateVendorNumber attribute value.
1170      *
1171      * @param alternateVendorNumber The vendorNumber to set.
1172      */
1173     public void setAlternateVendorNumber(String vendorNumber) {
1174         if (!StringUtils.isEmpty(vendorNumber)) {
1175             int dashInd = vendorNumber.indexOf(VendorConstants.DASH);
1176             if (vendorNumber.length() >= dashInd) {
1177                 String vndrHdrGenId = vendorNumber.substring(0, dashInd);
1178                 String vndrDetailAssgnedId = vendorNumber.substring(dashInd + 1);
1179                 if (!StringUtils.isEmpty(vndrHdrGenId) && !StringUtils.isEmpty(vndrDetailAssgnedId)) {
1180                     this.alternateVendorHeaderGeneratedIdentifier = new Integer(vndrHdrGenId);
1181                     this.alternateVendorDetailAssignedIdentifier = new Integer(vndrDetailAssgnedId);
1182                 }
1183             }
1184         } else {
1185             this.alternateVendorNumber = vendorNumber;
1186         }
1187     }
1188 
1189     /**
1190      * Sets alternate vendor fields based on a given VendorDetail.
1191      *
1192      * @param vendorDetail the vendor detail used to set vendor fields.
1193      */
1194     public void templateAlternateVendor(VendorDetail vendorDetail) {
1195         if (vendorDetail == null) {
1196             return;
1197         }
1198         this.setAlternateVendorNumber(vendorDetail.getVendorHeaderGeneratedIdentifier() + VendorConstants.DASH + vendorDetail.getVendorDetailAssignedIdentifier());
1199         this.setAlternateVendorName(vendorDetail.getVendorName());
1200     }
1201 
1202     /**
1203      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getItemClass()
1204      */
1205     @Override
1206     public Class getItemClass() {
1207         return PurchaseOrderItem.class;
1208     }
1209 
1210     @Override
1211     public Class getItemUseTaxClass() {
1212         return PurchaseOrderItemUseTax.class;
1213     }
1214 
1215     /**
1216      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentIfPossible()
1217      */
1218     @Override
1219     public RequisitionDocument getPurApSourceDocumentIfPossible() {
1220         RequisitionDocument sourceDoc = null;
1221         if (ObjectUtils.isNotNull(getRequisitionIdentifier())) {
1222             sourceDoc = SpringContext.getBean(RequisitionService.class).getRequisitionById(getRequisitionIdentifier());
1223         }
1224         return sourceDoc;
1225     }
1226 
1227     /**
1228      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentLabelIfPossible()
1229      */
1230     @Override
1231     public String getPurApSourceDocumentLabelIfPossible() {
1232         return SpringContext.getBean(DataDictionaryService.class).getDocumentLabelByTypeName(OLEConstants.FinancialDocumentTypeCodes.REQUISITION);
1233     }
1234 
1235     public Integer getNewQuoteVendorDetailAssignedIdentifier() {
1236         return newQuoteVendorDetailAssignedIdentifier;
1237     }
1238 
1239     public void setNewQuoteVendorDetailAssignedIdentifier(Integer newQuoteVendorDetailAssignedIdentifier) {
1240         this.newQuoteVendorDetailAssignedIdentifier = newQuoteVendorDetailAssignedIdentifier;
1241     }
1242 
1243     public Integer getNewQuoteVendorHeaderGeneratedIdentifier() {
1244         return newQuoteVendorHeaderGeneratedIdentifier;
1245     }
1246 
1247     public void setNewQuoteVendorHeaderGeneratedIdentifier(Integer newQuoteVendorHeaderGeneratedIdentifier) {
1248         this.newQuoteVendorHeaderGeneratedIdentifier = newQuoteVendorHeaderGeneratedIdentifier;
1249     }
1250 
1251     public Integer getPurchaseOrderQuoteListIdentifier() {
1252         return purchaseOrderQuoteListIdentifier;
1253     }
1254 
1255     public void setPurchaseOrderQuoteListIdentifier(Integer purchaseOrderQuoteListIdentifier) {
1256         this.purchaseOrderQuoteListIdentifier = purchaseOrderQuoteListIdentifier;
1257     }
1258 
1259     /**
1260      * Returns true if a vendor has been awarded for this Purchase Order.
1261      *
1262      * @return true if a vendor has been awarded for this Purchase Order.
1263      */
1264     public boolean isPurchaseOrderAwarded() {
1265         return (getAwardedVendorQuote() != null);
1266     }
1267 
1268     /**
1269      * Returns the quote from the awarded vendor.
1270      *
1271      * @return the quote from the awarded vendor.
1272      */
1273     public PurchaseOrderVendorQuote getAwardedVendorQuote() {
1274         for (PurchaseOrderVendorQuote vendorQuote : purchaseOrderVendorQuotes) {
1275             if (vendorQuote.getPurchaseOrderQuoteAwardTimestamp() != null) {
1276                 return vendorQuote;
1277             }
1278         }
1279         return null;
1280     }
1281 
1282     /**
1283      * @see org.kuali.ole.module.purap.document.PurchasingDocumentBase#getTotalDollarAmount()
1284      */
1285     @Override
1286     public KualiDecimal getTotalDollarAmount() {
1287         // return total without inactive and with below the line
1288         return getTotalDollarAmount(false, true);
1289     }
1290 
1291     /**
1292      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getTotalDollarAmountAboveLineItems()
1293      */
1294     @Override
1295     public KualiDecimal getTotalDollarAmountAboveLineItems() {
1296         return getTotalDollarAmount(false, false);
1297     }
1298 
1299     /**
1300      * Gets the total dollar amount for this Purchase Order.
1301      *
1302      * @param includeInactive     indicates whether inactive items shall be included.
1303      * @param includeBelowTheLine indicates whether below the line items shall be included.
1304      * @return the total dollar amount for this Purchase Order.
1305      */
1306     public KualiDecimal getTotalDollarAmount(boolean includeInactive, boolean includeBelowTheLine) {
1307         KualiDecimal total = new KualiDecimal(BigDecimal.ZERO);
1308         for (PurApItem item : (List<PurApItem>) getItems()) {
1309 
1310             if (item.getPurapDocument() == null) {
1311                 item.setPurapDocument(this);
1312             }
1313             ItemType it = item.getItemType();
1314             if ((includeBelowTheLine || it.isLineItemIndicator()) && (includeInactive || PurApItemUtils.checkItemActive(item))) {
1315                 KualiDecimal totalAmount = item.getTotalAmount();
1316                 KualiDecimal itemTotal = (totalAmount != null) ? totalAmount : KualiDecimal.ZERO;
1317                 total = total.add(itemTotal);
1318             }
1319         }
1320         return total;
1321     }
1322 
1323     /**
1324      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getTotalPreTaxDollarAmount()
1325      */
1326     @Override
1327     public KualiDecimal getTotalPreTaxDollarAmount() {
1328         // return total without inactive and with below the line
1329         return getTotalPreTaxDollarAmount(false, true);
1330     }
1331 
1332     /**
1333      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getTotalPreTaxDollarAmountAboveLineItems()
1334      */
1335     @Override
1336     public KualiDecimal getTotalPreTaxDollarAmountAboveLineItems() {
1337         return getTotalPreTaxDollarAmount(false, false);
1338     }
1339 
1340     /**
1341      * Gets the pre tax total dollar amount for this Purchase Order.
1342      *
1343      * @param includeInactive     indicates whether inactive items shall be included.
1344      * @param includeBelowTheLine indicates whether below the line items shall be included.
1345      * @return the total dollar amount for this Purchase Order.
1346      */
1347     public KualiDecimal getTotalPreTaxDollarAmount(boolean includeInactive, boolean includeBelowTheLine) {
1348         KualiDecimal total = new KualiDecimal(BigDecimal.ZERO);
1349         for (PurchaseOrderItem item : (List<PurchaseOrderItem>) getItems()) {
1350             ItemType it = item.getItemType();
1351             if ((includeBelowTheLine || it.isLineItemIndicator()) && (includeInactive || item.isItemActiveIndicator())) {
1352                 KualiDecimal extendedPrice = item.getExtendedPrice();
1353                 KualiDecimal itemTotal = (extendedPrice != null) ? extendedPrice : KualiDecimal.ZERO;
1354                 total = total.add(itemTotal);
1355             }
1356         }
1357         return total;
1358     }
1359 
1360 
1361     @Override
1362     public KualiDecimal getTotalTaxAmount() {
1363         // return total without inactive and with below the line
1364         return getTotalTaxAmount(false, true);
1365     }
1366 
1367     @Override
1368     public KualiDecimal getTotalTaxAmountAboveLineItems() {
1369         return getTotalTaxAmount(false, false);
1370     }
1371 
1372     /**
1373      * Gets the tax total amount for this Purchase Order.
1374      *
1375      * @param includeInactive     indicates whether inactive items shall be included.
1376      * @param includeBelowTheLine indicates whether below the line items shall be included.
1377      * @return the total dollar amount for this Purchase Order.
1378      */
1379     public KualiDecimal getTotalTaxAmount(boolean includeInactive, boolean includeBelowTheLine) {
1380         KualiDecimal total = new KualiDecimal(BigDecimal.ZERO);
1381         for (PurchaseOrderItem item : (List<PurchaseOrderItem>) getItems()) {
1382             ItemType it = item.getItemType();
1383             if ((includeBelowTheLine || it.isLineItemIndicator()) && (includeInactive || item.isItemActiveIndicator())) {
1384                 KualiDecimal taxAmount = item.getItemTaxAmount();
1385                 KualiDecimal itemTotal = (taxAmount != null) ? taxAmount : KualiDecimal.ZERO;
1386                 total = total.add(itemTotal);
1387             }
1388         }
1389         return total;
1390     }
1391 
1392     /**
1393      * Returns true if this Purchase Order contains unpaid items in the Payment Request or Credit Memo.
1394      *
1395      * @return true if this Purchase Order contains unpaid items in the Payment Request or Credit Memo.
1396      */
1397     public boolean getContainsUnpaidPaymentRequestsOrCreditMemos() {
1398         if (getRelatedViews().getRelatedPaymentRequestViews() != null) {
1399             for (PaymentRequestView element : getRelatedViews().getRelatedPaymentRequestViews()) {
1400                 // If the PREQ is neither cancelled nor voided, check whether the PREQ has been paid.
1401                 // If it has not been paid, then this method will return true.
1402                 if (!PurapConstants.PaymentRequestStatuses.CANCELLED_STATUSES.contains(element.getApplicationDocumentStatus())) {
1403                     if (element.getPaymentPaidTimestamp() == null) {
1404                         return true;
1405                     }
1406                 }
1407             }// endfor
1408         }
1409         if (getRelatedViews().getRelatedCreditMemoViews() != null) {
1410             for (CreditMemoView element : getRelatedViews().getRelatedCreditMemoViews()) {
1411                 // If the CM is cancelled, check whether the CM has been paid.
1412                 // If it has not been paid, then this method will return true.
1413                 if (!CreditMemoStatuses.CANCELLED_STATUSES.contains(element.getApplicationDocumentStatus())) {
1414                     if (element.getCreditMemoPaidTimestamp() == null) {
1415                         return true;
1416                     }
1417                 }
1418             }// endfor
1419         }
1420         if (getRelatedViews().getRelatedInvoiceViews() != null) {
1421             for (InvoiceView element : getRelatedViews().getRelatedInvoiceViews()) {
1422                 // If the invoice is neither cancelled nor voided, check whether the invoice has been paid.
1423                 // If it has not been paid, then this method will return true.
1424                 if (!PurapConstants.InvoiceStatuses.CANCELLED_STATUSES.contains(element.getApplicationDocumentStatus())) {
1425                     if (element.getPaymentPaidTimestamp() == null) {
1426                         return true;
1427                     }
1428                 }
1429             }// endfor
1430         }
1431 
1432         return false;
1433     }
1434 
1435     public boolean getAdditionalChargesExist() {
1436         List<PurchaseOrderItem> items = this.getItems();
1437         for (PurchaseOrderItem item : items) {
1438             if ((item != null) &&
1439                     (item.getItemType() != null) &&
1440                     (item.getItemType().isAdditionalChargeIndicator()) &&
1441                     (item.getExtendedPrice() != null) &&
1442                     (!KualiDecimal.ZERO.equals(item.getExtendedPrice()))) {
1443                 return true;
1444             }
1445         }
1446         return false;
1447     }
1448 
1449     /**
1450      * Used for routing only.
1451      *
1452      * @deprecated
1453      */
1454     @Deprecated
1455     public String getContractManagerName() {
1456         return "";
1457     }
1458 
1459     /**
1460      * Used for routing only.
1461      *
1462      * @deprecated
1463      */
1464     @Deprecated
1465     public void setContractManagerName(String contractManagerName) {
1466     }
1467 
1468     public KualiDecimal getInternalPurchasingLimit() {
1469         //FIXME need the following because at places this field remains null because contract manager is not refreshed and null
1470 
1471         if (internalPurchasingLimit == null) {
1472             setInternalPurchasingLimit(SpringContext.getBean(PurchaseOrderService.class).getInternalPurchasingDollarLimit(this));
1473         }
1474         return internalPurchasingLimit;
1475     }
1476 
1477     public void setInternalPurchasingLimit(KualiDecimal internalPurchasingLimit) {
1478         this.internalPurchasingLimit = internalPurchasingLimit;
1479     }
1480 
1481     public boolean isPendingSplit() {
1482         return pendingSplit;
1483     }
1484 
1485     public void setPendingSplit(boolean pendingSplit) {
1486         this.pendingSplit = pendingSplit;
1487     }
1488 
1489     public boolean isCopyingNotesWhenSplitting() {
1490         return copyingNotesWhenSplitting;
1491     }
1492 
1493     public void setCopyingNotesWhenSplitting(boolean copyingNotesWhenSplitting) {
1494         this.copyingNotesWhenSplitting = copyingNotesWhenSplitting;
1495     }
1496 
1497     /**
1498      * @see org.kuali.module.purap.rules.PurapAccountingDocumentRuleBase#customizeExplicitGeneralLedgerPendingEntry(org.kuali.ole.sys.document.AccountingDocument,
1499      *      org.kuali.ole.sys.businessobject.AccountingLine, org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry)
1500      */
1501     @Override
1502     public void customizeExplicitGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySourceDetail postable, GeneralLedgerPendingEntry explicitEntry) {
1503         super.customizeExplicitGeneralLedgerPendingEntry(postable, explicitEntry);
1504 
1505         SpringContext.getBean(PurapGeneralLedgerService.class).customizeGeneralLedgerPendingEntry(this, (AccountingLine) postable, explicitEntry, getPurapDocumentIdentifier(), GL_DEBIT_CODE, PurapDocTypeCodes.PO_DOCUMENT, true);
1506 
1507         KualiDecimal accountTotalGLEntryAmount = this.getAccountTotalGLEntryAmount((AccountingLine) postable);
1508         explicitEntry.setTransactionLedgerEntryAmount(accountTotalGLEntryAmount);
1509         String debitCreditCode = GL_DEBIT_CODE;
1510 
1511         // if the amount is negative, flip the D/C indicator
1512         if (accountTotalGLEntryAmount.doubleValue() < 0) {
1513             if (GL_CREDIT_CODE.equals(debitCreditCode)) {
1514                 if (GL_CREDIT_CODE.equals(debitCreditCode)) {
1515                     explicitEntry.setTransactionDebitCreditCode(GL_DEBIT_CODE);
1516                 }
1517             } else {
1518                 explicitEntry.setTransactionDebitCreditCode(GL_CREDIT_CODE);
1519             }
1520         } else {
1521             explicitEntry.setTransactionDebitCreditCode(debitCreditCode);
1522         }
1523 
1524         // don't think i should have to override this, but default isn't getting the right PO doc
1525         explicitEntry.setFinancialDocumentTypeCode(PurapDocTypeCodes.PO_DOCUMENT);
1526     }
1527 
1528     @Override
1529     public Class getPurchasingCapitalAssetItemClass() {
1530         return PurchaseOrderCapitalAssetItem.class;
1531     }
1532 
1533     @Override
1534     public Class getPurchasingCapitalAssetSystemClass() {
1535         return PurchaseOrderCapitalAssetSystem.class;
1536     }
1537 
1538     /**
1539      * Validates whether we can indeed close the PO. Return false and give error if
1540      * the outstanding encumbrance amount of the trade in item is less than 0.
1541      *
1542      * @param po
1543      * @return
1544      */
1545     public boolean canClosePOForTradeIn() {
1546         for (PurchaseOrderItem item : (List<PurchaseOrderItem>) getItems()) {
1547             if (item.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE) && item.getItemOutstandingEncumberedAmount().isLessThan(new KualiDecimal(0))) {
1548                 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_ITEM_TRADE_IN_OUTSTANDING_ENCUMBERED_AMOUNT_NEGATIVE, "amend the PO");
1549                 return false;
1550             }
1551         }
1552         return true;
1553     }
1554 
1555     /**
1556      * Provides answers to the following splits:
1557      * RequiresContractManagementReview
1558      * RequiresBudgetReview
1559      * VendorIsEmployeeOrNonResidentAlien
1560      * TransmissionMethodIsPrint
1561      *
1562      * @see org.kuali.ole.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String)
1563      */
1564     @Override
1565     public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
1566         if (nodeName.equals(PurapWorkflowConstants.CONTRACT_MANAGEMENT_REVIEW_REQUIRED)) {
1567             return isContractManagementReviewRequired();
1568         }
1569         if (nodeName.equals(PurapWorkflowConstants.AWARD_REVIEW_REQUIRED)) {
1570             return isAwardReviewRequired();
1571         }
1572         if (nodeName.equals(PurapWorkflowConstants.BUDGET_REVIEW_REQUIRED)) {
1573             return isBudgetReviewRequired();
1574         }
1575         if (nodeName.equals(PurapWorkflowConstants.VENDOR_IS_EMPLOYEE_OR_NON_RESIDENT_ALIEN)) {
1576             return isVendorEmployeeOrNonResidentAlien();
1577         }
1578 
1579         if (nodeName.equals(PurapWorkflowConstants.NOTIFY_BUDGET_REVIEW)) {
1580             return isNotificationRequired();
1581         }
1582         return super.answerSplitNodeQuestion(nodeName);
1583     }
1584 
1585     protected boolean isContractManagementReviewRequired() {
1586         KualiDecimal internalPurchasingLimit = SpringContext.getBean(PurchaseOrderService.class).getInternalPurchasingDollarLimit(this);
1587         return ((ObjectUtils.isNull(internalPurchasingLimit)) || (internalPurchasingLimit.compareTo(this.getTotalDollarAmount()) < 0));
1588 
1589     }
1590 
1591     protected boolean isAwardReviewRequired() {
1592         ParameterService parameterService = SpringContext.getBean(ParameterService.class);
1593         boolean objectCodeAllowed = true;
1594 
1595         for (PurApItem item : (List<PurApItem>) this.getItems()) {
1596             for (PurApAccountingLine accountingLine : item.getSourceAccountingLines()) {
1597 
1598                 objectCodeAllowed = isObjectCodeAllowedForAwardRouting(accountingLine, parameterService);
1599                 // We should return true as soon as we have at least one objectCodeAllowed=true so that the PO will stop at Award
1600                 // level.
1601                 if (objectCodeAllowed) {
1602                     return objectCodeAllowed;
1603                 }
1604 
1605             }
1606         }
1607         return objectCodeAllowed;
1608     }
1609 
1610     protected boolean isObjectCodeAllowedForAwardRouting(PurApAccountingLine accountingLine, ParameterService parameterService) {
1611         if (ObjectUtils.isNull(accountingLine.getObjectCode())) {
1612             return false;
1613         }
1614 
1615         // make sure object code is active
1616         if (!accountingLine.getObjectCode().isFinancialObjectActiveCode()) {
1617             return false;
1618         }
1619 
1620         String chartCode = accountingLine.getChartOfAccountsCode();
1621         // check object level is in permitted list for award routing
1622         boolean objectCodeAllowed = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(PurchaseOrderDocument.class, PurapParameterConstants.CG_ROUTE_OBJECT_LEVELS_BY_CHART, PurapParameterConstants.NO_CG_ROUTE_OBJECT_LEVELS_BY_CHART, chartCode, accountingLine.getObjectCode().getFinancialObjectLevelCode()).evaluationSucceeds();
1623 
1624         if (!objectCodeAllowed) {
1625             // If the object level is not permitting for award routing, then we need to also
1626             // check object code is in permitted list for award routing
1627             objectCodeAllowed = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(PurchaseOrderDocument.class, PurapParameterConstants.CG_ROUTE_OBJECT_CODES_BY_CHART, PurapParameterConstants.NO_CG_ROUTE_OBJECT_CODES_BY_CHART, chartCode, accountingLine.getFinancialObjectCode()).evaluationSucceeds();
1628         }
1629         return objectCodeAllowed;
1630     }
1631 
1632     protected boolean isBudgetReviewRequired() {
1633         // if document's fiscal year is less than or equal to the current fiscal year
1634         if (SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear().compareTo(getPostingYear()) >= 0) {
1635 
1636             List<SourceAccountingLine> sourceAccountingLineList = this.getSourceAccountingLines();
1637             boolean sufficientFundCheck = false;
1638             for (SourceAccountingLine accLine : sourceAccountingLineList) {
1639                 Map searchMap = new HashMap();
1640                 String notificationOption = null;
1641                 Map<String, Object> key = new HashMap<String, Object>();
1642                 String chartCode = accLine.getChartOfAccountsCode();
1643                 String accNo = accLine.getAccountNumber();
1644                 String objectCd = accLine.getFinancialObjectCode();
1645                 key.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartCode);
1646                 key.put(OLEPropertyConstants.ACCOUNT_NUMBER, accNo);
1647                 OleSufficientFundCheck account = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(
1648                         OleSufficientFundCheck.class, key);
1649                 if (account != null) {
1650                     notificationOption = account.getNotificationOption();
1651                 }
1652                 if (notificationOption != null
1653                         && (notificationOption.equals(OLEPropertyConstants.BUD_REVIEW) )) {
1654             // get list of sufficientfundItems
1655 
1656             // delete and recreate the GL entries for this document so they do not get included in the SF check
1657             // This is *NOT* ideal.  The SF service needs to be updated to allow it to provide the current
1658             // document number so that it can be exlcuded from pending entry checks.
1659             List<GeneralLedgerPendingEntry> pendingEntries = getPendingLedgerEntriesForSufficientFundsChecking();
1660             // dumb loop to just force OJB to load the objects.  Otherwise, the proxy object above
1661             // only gets resolved *after* the delete below and no SF check happens.
1662             for (GeneralLedgerPendingEntry glpe : pendingEntries) {
1663                 glpe.getChartOfAccountsCode();
1664             }
1665             SpringContext.getBean(GeneralLedgerPendingEntryService.class).delete(getDocumentNumber());
1666             List<SufficientFundsItem> fundsItems = SpringContext.getBean(SufficientFundsService.class).checkSufficientFunds(pendingEntries);
1667             SpringContext.getBean(GeneralLedgerPendingEntryService.class).generateGeneralLedgerPendingEntries(this);
1668             SpringContext.getBean(BusinessObjectService.class).save(getGeneralLedgerPendingEntries());
1669             if (fundsItems.size() > 0) {
1670                 return true;
1671             }
1672                 }
1673                 /*Commented for jira OLE-2359
1674                  * for (SufficientFundsItem fundsItem : fundsItems) {
1675                     if (this.getChartOfAccountsCode().equalsIgnoreCase(fundsItem.getAccount().getChartOfAccountsCode())) {
1676                     LOG.debug("Chart code of rule extension matches chart code of at least one Sufficient Funds Item");
1677                     return true;
1678                 }
1679             }*/
1680         }
1681         }
1682 
1683         return false;
1684     }
1685 
1686     private boolean isNotificationRequired() {
1687         OleRequisitionDocumentService oleRequisitionDocumentService = (OleRequisitionDocumentService) SpringContext
1688                 .getBean("oleRequisitionDocumentService");
1689         List<SourceAccountingLine> sourceAccountingLineList = this.getSourceAccountingLines();
1690         boolean sufficientFundCheck = false;
1691         for (SourceAccountingLine accLine : sourceAccountingLineList) {
1692             Map searchMap = new HashMap();
1693             String notificationOption = null;
1694             Map<String, Object> key = new HashMap<String, Object>();
1695             String chartCode = accLine.getChartOfAccountsCode();
1696             String accNo = accLine.getAccountNumber();
1697             String objectCd = accLine.getFinancialObjectCode();
1698             key.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartCode);
1699             key.put(OLEPropertyConstants.ACCOUNT_NUMBER, accNo);
1700             OleSufficientFundCheck account = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(
1701                     OleSufficientFundCheck.class, key);
1702             if (account != null) {
1703                 notificationOption = account.getNotificationOption();
1704             }
1705             if (notificationOption != null && notificationOption.equals(OLEPropertyConstants.NOTIFICATION)) {
1706                 sufficientFundCheck = oleRequisitionDocumentService.hasSufficientFundsOnRequisition(accLine);
1707                 if (sufficientFundCheck) {
1708                     return sufficientFundCheck;
1709                 }
1710             }
1711         }
1712         return sufficientFundCheck;
1713     }
1714 
1715 
1716     protected boolean isVendorEmployeeOrNonResidentAlien() {
1717         if (ObjectUtils.isNull(this.getVendorHeaderGeneratedIdentifier())) {
1718             // no vendor header id so can't check for proper tax routing
1719             return false;
1720         }
1721         String currencytype=new String();
1722         String vendorHeaderGeneratedId = this.getVendorHeaderGeneratedIdentifier().toString();
1723         VendorService vendorService = SpringContext.getBean(VendorService.class);
1724         boolean routeDocumentAsEmployeeVendor = vendorService.isVendorInstitutionEmployee(Integer.valueOf(vendorHeaderGeneratedId));
1725       //  boolean routeDocumentAsForeignVendor = vendorService.isVendorForeign(Integer.valueOf(vendorHeaderGeneratedId));
1726         Map fieldValues = new HashMap();
1727         fieldValues.put(OleSelectConstant.VENDOR_HEADER_GENERATED_ID, vendorHeaderGeneratedId);
1728         ArrayList<VendorDetail> vendorDetail=new  ArrayList<>(SpringContext.getBean(BusinessObjectService.class).findMatching(VendorDetail.class, fieldValues)) ;
1729         if(vendorDetail!=null && vendorDetail.size()>0 ) {
1730             if (vendorDetail.get(0).getCurrencyType()!= null){
1731                 currencytype=vendorDetail.get(0).getCurrencyType().getCurrencyType();
1732             }
1733         }
1734         if ((!routeDocumentAsEmployeeVendor) && ((currencytype.equalsIgnoreCase(OleSelectConstant.CURRENCY_TYPE_NAME) || (vendorDetail.get(0).getCurrencyType() == null)) )) {
1735             // no need to route
1736             return false;
1737         }
1738 
1739         return true;
1740     }
1741 
1742     public List<Account> getAccountsForAwardRouting() {
1743         List<Account> accounts = new ArrayList<Account>();
1744 
1745         ParameterService parameterService = SpringContext.getBean(ParameterService.class);
1746         for (PurApItem item : (List<PurApItem>) this.getItems()) {
1747             for (PurApAccountingLine accountingLine : item.getSourceAccountingLines()) {
1748                 if (isObjectCodeAllowedForAwardRouting(accountingLine, parameterService)) {
1749                     if (ObjectUtils.isNull(accountingLine.getAccount())) {
1750                         accountingLine.refreshReferenceObject("account");
1751                     }
1752                     if (accountingLine.getAccount() != null && !accounts.contains(accountingLine.getAccount())) {
1753                         accounts.add(accountingLine.getAccount());
1754                     }
1755                 }
1756             }
1757         }
1758         return accounts;
1759     }
1760 
1761     @Override
1762     public DocumentSearchCriteria convertSelections(DocumentSearchCriteria searchCriteria) {
1763         // RICE 20 : No longer applicable with Rice 2.0 functionality
1764 //        for (DocumentTypeAttributeBo comp : searchCriteria.getSearchableAttributes()) {
1765 //            if (comp.getLookupableFieldType().equals(Field.MULTISELECT)) {
1766 //                List<String> values = comp.getValues();
1767 //                List<String> newVals = new ArrayList<String>();
1768 //                if (values.contains("INCOMPLETE")) {
1769 //                    for (String str : PurchaseOrderStatuses.INCOMPLETE_STATUSES) {
1770 //                        newVals.add(str);
1771 //                    }
1772 //                } if (values.contains("COMPLETE")) {
1773 //                    for (String str : PurchaseOrderStatuses.COMPLETE_STATUSES) {
1774 //                        newVals.add(str);
1775 //                    }
1776 //                }
1777 //
1778 //                for (String str : values) {
1779 //                    newVals.add(str);
1780 //                }
1781 //
1782 //                comp.setValues(newVals);
1783 //            }
1784 //        }
1785         return searchCriteria;
1786     }
1787 
1788     /**
1789      * @return the purchase order current indicator
1790      */
1791     public boolean getPurchaseOrderCurrentIndicatorForSearching() {
1792         return purchaseOrderCurrentIndicator;
1793     }
1794 
1795     public String getDocumentTitleForResult() throws WorkflowException {
1796         return KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(this.getFinancialSystemDocumentHeader().getWorkflowDocument().getDocumentTypeName()).getLabel();
1797     }
1798 
1799     /**
1800      * Checks whether the purchase order needs a warning to be displayed, i.e. it never has been opened.
1801      *
1802      * @return true if the purchase order needs a warning; false otherwise.
1803      */
1804     public boolean getNeedWarning() {
1805         return getPurchaseOrderInitialOpenTimestamp() == null;
1806     }
1807 
1808     public List<SourceAccountingLine> getGlOnlySourceAccountingLines() {
1809         return glOnlySourceAccountingLines;
1810     }
1811 
1812     public void setGlOnlySourceAccountingLines(List<SourceAccountingLine> glOnlySourceAccountingLines) {
1813         this.glOnlySourceAccountingLines = glOnlySourceAccountingLines;
1814     }
1815 
1816     @Override
1817     public PersistableBusinessObject getNoteTarget() {
1818         PurchaseOrderDao purchaseOrderDao = SpringContext.getBean(PurchaseOrderDao.class);
1819         DocumentDao docDao = GlobalResourceLoader.getService( "documentDao"  );
1820 
1821         PurchaseOrderDocument oldest = docDao.findByDocumentHeaderId(PurchaseOrderDocument.class,
1822                 purchaseOrderDao.getOldestPurchaseOrderDocumentNumber(this.getPurapDocumentIdentifier()));
1823 
1824         // OLEMI-9746: added this for null safe checking.
1825         if (oldest != null) {
1826             return oldest.getDocumentHeader();
1827         }
1828 
1829         return this.getDocumentHeader();
1830     }
1831 
1832     @Override
1833     public NoteType getNoteType() {
1834         return NoteType.BUSINESS_OBJECT;
1835     }
1836 
1837     public boolean isCreatedFromRequisition() {
1838         return this.getRequisitionIdentifier() != null;
1839     }
1840 
1841 }