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                     oleDocstoreHelperService.createOrUpdateDocStoreBasedOnLocation(this, item, currentDocumentTypeName,cancellationNote.toString());
651                     cancellationNote.delete(0,cancellationNote.length());
652                     noteList.clear();
653                 }
654             }
655         }
656         if (PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_DOCUMENT.equals(currentDocumentTypeName) || PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_SPLIT_DOCUMENT.equals(currentDocumentTypeName)) {
657             try {
658                 // DOCUMENT PROCESSED
659                 if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isProcessed()) {
660                     setPurchaseOrderLastTransmitTimestamp(SpringContext.getBean(DateTimeService.class).getCurrentTimestamp());
661                     SpringContext.getBean(PurchaseOrderService.class).completePurchaseOrder(this);
662                     if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isProcessed() && !this.getFinancialSystemDocumentHeader().getWorkflowDocument().isFinal()) {
663                         SpringContext.getBean(WorkflowDocumentService.class).saveRoutingData(this.getFinancialSystemDocumentHeader().getWorkflowDocument());
664                     }
665                 }
666                 // DOCUMENT DISAPPROVED
667                 else if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isDisapproved()) {
668                     String nodeName = SpringContext.getBean(WorkflowDocumentService.class).getCurrentRouteLevelName(this.getFinancialSystemDocumentHeader().getWorkflowDocument());
669                     String disapprovalStatus = PurapConstants.PurchaseOrderStatuses.getPurchaseOrderAppDocDisapproveStatuses().get(nodeName);
670 
671                     if (ObjectUtils.isNotNull(disapprovalStatus)) {
672                         //update the appDocStatus and save the workflow data
673                         updateAndSaveAppDocStatus(disapprovalStatus);
674 
675                         RequisitionDocument req = getPurApSourceDocumentIfPossible();
676                         String principalId = req.getFinancialSystemDocumentHeader().getWorkflowDocument()
677                                 .getRoutedByPrincipalId();
678                         appSpecificRouteDocumentToUser(this.getFinancialSystemDocumentHeader().getWorkflowDocument(),
679                                 principalId,
680                                 "Notification of Order Disapproval for Requisition " + req.getPurapDocumentIdentifier()
681                                         + "(document id " + req.getDocumentNumber() + ")", "Requisition Routed By User");
682                         return;
683                     }
684                     logAndThrowRuntimeException("No status found to set for document being disapproved in node '" + nodeName + "'");
685                 }
686                 // DOCUMENT CANCELED
687                 else if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isCanceled()) {
688                     updateAndSaveAppDocStatus(PurchaseOrderStatuses.APPDOC_CANCELLED);
689                 }
690             } catch (WorkflowException e) {
691                 logAndThrowRuntimeException("Error saving routing data while saving document with id " + getDocumentNumber(), e);
692             }
693         }
694     }
695 
696     /**
697      * Returns the name of the current route node.
698      *
699      * @param wd the current workflow document.
700      * @return the name of the current route node.
701      * @throws WorkflowException
702      */
703     protected String getCurrentRouteNodeName(WorkflowDocument wd) throws WorkflowException {
704         ArrayList<String> nodeNames = new ArrayList(wd.getCurrentNodeNames());
705         if ((nodeNames == null) || (nodeNames.size() == 0)) {
706             return null;
707         } else {
708             return nodeNames.get(0);
709         }
710     }
711 
712     /**
713      * Sends FYI workflow request to the given user on this document.
714      *
715      * @param workflowDocument the associated workflow document.
716      * @param userNetworkId    the network ID of the user to be sent to.
717      * @param annotation       the annotation notes contained in this document.
718      * @param responsibility   the responsibility specified in the request.
719      * @throws WorkflowException
720      */
721     public void appSpecificRouteDocumentToUser(WorkflowDocument workflowDocument, String routePrincipalName,
722                                                String annotation, String responsibility) throws WorkflowException {
723         if (ObjectUtils.isNotNull(workflowDocument)) {
724             String annotationNote = (ObjectUtils.isNull(annotation)) ? "" : annotation;
725             String responsibilityNote = (ObjectUtils.isNull(responsibility)) ? "" : responsibility;
726             String currentNodeName = getCurrentRouteNodeName(workflowDocument);
727             // Principal principal = SpringContext.getBean(IdentityManagementService.class).getPrincipalByPrincipalName(userNetworkId);
728             workflowDocument.adHocToPrincipal(ActionRequestType.FYI, currentNodeName, annotationNote,
729                     routePrincipalName, responsibilityNote, true);
730         }
731     }
732 
733     /**
734      * @see org.kuali.rice.kns.document.DocumentBase#handleRouteLevelChange(org.kuali.rice.kew.clientapp.vo.DocumentRouteLevelChangeDTO)
735      */
736     @Override
737     public void doRouteLevelChange(DocumentRouteLevelChange levelChangeEvent) {
738         /*LOG.debug("handleRouteLevelChange() started");*/
739         super.doRouteLevelChange(levelChangeEvent);
740 
741         // JHK : This has been commented out in KFS 5.0 - standard app doc status logic in KEW handles this
742 
743 //        String newNodeName = levelChangeEvent.getNewNodeName();
744 //        if (StringUtils.isNotBlank(newNodeName)) {
745 //            RoutingReportCriteria.Builder reportCriteriaDTO = RoutingReportCriteria.Builder.createByDocumentId(getDocumentNumber());
746 //            reportCriteriaDTO.setTargetNodeName(newNodeName);
747 //            try {
748 //                NodeDetails newNodeDetails = NodeDetailEnum.getNodeDetailEnumByName(newNodeName);
749 //                if (ObjectUtils.isNotNull(newNodeDetails)) {
750 //                    String newStatusCode = newNodeDetails.getAwaitingStatusCode();
751 //                    if (StringUtils.isNotBlank(newStatusCode)) {
752 //                        if (SpringContext.getBean(WorkflowDocumentActionsService.class).documentWillHaveAtLeastOneActionRequest(reportCriteriaDTO, new String[] { KewApiConstants.ACTION_REQUEST_APPROVE_REQ, KewApiConstants.ACTION_REQUEST_COMPLETE_REQ }, false)) {
753 //                            // if an approve or complete request will be created then we need to set the status as awaiting for
754 //                            // the new node
755 //                            this.setApplicationDocumentStatus(newStatusCode);
756 //
757 //                            SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
758 //                        }
759 //                    }
760 //                }
761 //            }
762 //            catch (WorkflowException e) {
763 //                String errorMsg = "Workflow Error found checking actions requests on document with id " + getDocumentNumber() + ". *** WILL NOT UPDATE PURAP STATUS ***";
764 //                LOG.warn(errorMsg, e);
765 //            }
766 //        }
767     }
768 
769     /**
770      * @see org.kuali.rice.krad.document.DocumentBase#doActionTaken(org.kuali.rice.kew.clientapp.vo.ActionTakenEventDTO)
771      */
772     @Override
773     public void doActionTaken(ActionTakenEvent event) {
774         super.doActionTaken(event);
775         // additional processing
776     }
777 
778     /**
779      * Gets the active items in this Purchase Order.
780      *
781      * @return the list of all active items in this Purchase Order.
782      */
783     public List getItemsActiveOnly() {
784         List returnList = new ArrayList();
785         for (Iterator iter = getItems().iterator(); iter.hasNext(); ) {
786             PurchaseOrderItem item = (PurchaseOrderItem) iter.next();
787             if (item.isItemActiveIndicator()) {
788                 returnList.add(item);
789             }
790         }
791         return returnList;
792     }
793 
794     /**
795      * Gets the active items in this Purchase Order, and sets up the alternate amount for GL entry creation.
796      *
797      * @return the list of all active items in this Purchase Order.
798      */
799     public List getItemsActiveOnlySetupAlternateAmount() {
800         List returnList = new ArrayList();
801         for (Iterator iter = getItems().iterator(); iter.hasNext(); ) {
802             PurchaseOrderItem item = (PurchaseOrderItem) iter.next();
803             if (item.isItemActiveIndicator()) {
804                 for (Object element : item.getSourceAccountingLines()) {
805                     PurchaseOrderAccount account = (PurchaseOrderAccount) element;
806                     account.setAlternateAmountForGLEntryCreation(account.getItemAccountOutstandingEncumbranceAmount());
807                 }
808                 returnList.add(item);
809             }
810         }
811         return returnList;
812     }
813 
814     public Integer getAlternateVendorDetailAssignedIdentifier() {
815         return alternateVendorDetailAssignedIdentifier;
816     }
817 
818     public void setAlternateVendorDetailAssignedIdentifier(Integer alternateVendorDetailAssignedIdentifier) {
819         this.alternateVendorDetailAssignedIdentifier = alternateVendorDetailAssignedIdentifier;
820     }
821 
822     public Integer getAlternateVendorHeaderGeneratedIdentifier() {
823         return alternateVendorHeaderGeneratedIdentifier;
824     }
825 
826     public void setAlternateVendorHeaderGeneratedIdentifier(Integer alternateVendorHeaderGeneratedIdentifier) {
827         this.alternateVendorHeaderGeneratedIdentifier = alternateVendorHeaderGeneratedIdentifier;
828     }
829 
830     public String getAlternateVendorName() {
831         return alternateVendorName;
832     }
833 
834     public void setAlternateVendorName(String alternateVendorName) {
835         this.alternateVendorName = alternateVendorName;
836     }
837 
838     public KualiDecimal getFinalPaymentAmount() {
839         return finalPaymentAmount;
840     }
841 
842     public void setFinalPaymentAmount(KualiDecimal finalPaymentAmount) {
843         this.finalPaymentAmount = finalPaymentAmount;
844     }
845 
846     public Date getFinalPaymentDate() {
847         return finalPaymentDate;
848     }
849 
850     public void setFinalPaymentDate(Date finalPaymentDate) {
851         this.finalPaymentDate = finalPaymentDate;
852     }
853 
854     public KualiDecimal getInitialPaymentAmount() {
855         return initialPaymentAmount;
856     }
857 
858     public void setInitialPaymentAmount(KualiDecimal initialPaymentAmount) {
859         this.initialPaymentAmount = initialPaymentAmount;
860     }
861 
862     public Date getInitialPaymentDate() {
863         return initialPaymentDate;
864     }
865 
866     public void setInitialPaymentDate(Date initialPaymentDate) {
867         this.initialPaymentDate = initialPaymentDate;
868     }
869 
870     public String getPurchaseOrderCommodityDescription() {
871         return purchaseOrderCommodityDescription;
872     }
873 
874     public void setPurchaseOrderCommodityDescription(String purchaseOrderCommodityDescription) {
875         this.purchaseOrderCommodityDescription = purchaseOrderCommodityDescription;
876     }
877 
878     public boolean isPurchaseOrderConfirmedIndicator() {
879         return purchaseOrderConfirmedIndicator;
880     }
881 
882     public void setPurchaseOrderConfirmedIndicator(boolean purchaseOrderConfirmedIndicator) {
883         this.purchaseOrderConfirmedIndicator = purchaseOrderConfirmedIndicator;
884     }
885 
886     public Timestamp getPurchaseOrderCreateTimestamp() {
887         return purchaseOrderCreateTimestamp;
888     }
889 
890     public void setPurchaseOrderCreateTimestamp(Timestamp purchaseOrderCreateTimestamp) {
891         this.purchaseOrderCreateTimestamp = purchaseOrderCreateTimestamp;
892     }
893 
894     public Timestamp getPurchaseOrderInitialOpenTimestamp() {
895         return purchaseOrderInitialOpenTimestamp;
896     }
897 
898     public void setPurchaseOrderInitialOpenTimestamp(Timestamp purchaseOrderInitialOpenDate) {
899         this.purchaseOrderInitialOpenTimestamp = purchaseOrderInitialOpenDate;
900     }
901 
902     public Timestamp getPurchaseOrderLastTransmitTimestamp() {
903         return purchaseOrderLastTransmitTimestamp;
904     }
905 
906     public void setPurchaseOrderLastTransmitTimestamp(Timestamp PurchaseOrderLastTransmitTimestamp) {
907         this.purchaseOrderLastTransmitTimestamp = PurchaseOrderLastTransmitTimestamp;
908     }
909 
910     public Integer getPurchaseOrderPreviousIdentifier() {
911         return purchaseOrderPreviousIdentifier;
912     }
913 
914     public void setPurchaseOrderPreviousIdentifier(Integer purchaseOrderPreviousIdentifier) {
915         this.purchaseOrderPreviousIdentifier = purchaseOrderPreviousIdentifier;
916     }
917 
918     public Date getPurchaseOrderQuoteDueDate() {
919         return purchaseOrderQuoteDueDate;
920     }
921 
922     public void setPurchaseOrderQuoteDueDate(Date purchaseOrderQuoteDueDate) {
923         this.purchaseOrderQuoteDueDate = purchaseOrderQuoteDueDate;
924     }
925 
926     public String getPurchaseOrderQuoteTypeDescription() {
927         String descript = purchaseOrderQuoteTypeCode;
928         if (PurapConstants.QuoteTypes.COMPETITIVE.equals(purchaseOrderQuoteTypeCode)) {
929             descript = QuoteTypeDescriptions.COMPETITIVE;
930         } else if (PurapConstants.QuoteTypes.PRICE_CONFIRMATION.equals(purchaseOrderQuoteTypeCode)) {
931             descript = QuoteTypeDescriptions.PRICE_CONFIRMATION;
932         }
933         return descript;
934     }
935 
936     public String getPurchaseOrderQuoteTypeCode() {
937         return purchaseOrderQuoteTypeCode;
938     }
939 
940     public void setPurchaseOrderQuoteTypeCode(String purchaseOrderQuoteTypeCode) {
941         this.purchaseOrderQuoteTypeCode = purchaseOrderQuoteTypeCode;
942     }
943 
944     public String getPurchaseOrderQuoteVendorNoteText() {
945         return purchaseOrderQuoteVendorNoteText;
946     }
947 
948     public void setPurchaseOrderQuoteVendorNoteText(String purchaseOrderQuoteVendorNoteText) {
949         this.purchaseOrderQuoteVendorNoteText = purchaseOrderQuoteVendorNoteText;
950     }
951 
952     public String getPurchaseOrderVendorChoiceCode() {
953         return purchaseOrderVendorChoiceCode;
954     }
955 
956     public void setPurchaseOrderVendorChoiceCode(String purchaseOrderVendorChoiceCode) {
957         this.purchaseOrderVendorChoiceCode = purchaseOrderVendorChoiceCode;
958     }
959 
960     public KualiDecimal getRecurringPaymentAmount() {
961         return recurringPaymentAmount;
962     }
963 
964     public void setRecurringPaymentAmount(KualiDecimal recurringPaymentAmount) {
965         this.recurringPaymentAmount = recurringPaymentAmount;
966     }
967 
968     public Date getRecurringPaymentDate() {
969         return recurringPaymentDate;
970     }
971 
972     public void setRecurringPaymentDate(Date recurringPaymentDate) {
973         this.recurringPaymentDate = recurringPaymentDate;
974     }
975 
976     public String getRecurringPaymentFrequencyCode() {
977         return recurringPaymentFrequencyCode;
978     }
979 
980     public void setRecurringPaymentFrequencyCode(String recurringPaymentFrequencyCode) {
981         this.recurringPaymentFrequencyCode = recurringPaymentFrequencyCode;
982     }
983 
984     public Integer getRequisitionIdentifier() {
985         return requisitionIdentifier;
986     }
987 
988     public void setRequisitionIdentifier(Integer requisitionIdentifier) {
989         this.requisitionIdentifier = requisitionIdentifier;
990     }
991 
992     public PurchaseOrderVendorChoice getPurchaseOrderVendorChoice() {
993         return purchaseOrderVendorChoice;
994     }
995 
996     public void setPurchaseOrderVendorChoice(PurchaseOrderVendorChoice purchaseOrderVendorChoice) {
997         this.purchaseOrderVendorChoice = purchaseOrderVendorChoice;
998     }
999 
1000     public RecurringPaymentFrequency getRecurringPaymentFrequency() {
1001         return recurringPaymentFrequency;
1002     }
1003 
1004     public void setRecurringPaymentFrequency(RecurringPaymentFrequency recurringPaymentFrequency) {
1005         this.recurringPaymentFrequency = recurringPaymentFrequency;
1006     }
1007 
1008     public PaymentTermType getVendorPaymentTerms() {
1009         return vendorPaymentTerms;
1010     }
1011 
1012     public void setVendorPaymentTerms(PaymentTermType vendorPaymentTerms) {
1013         this.vendorPaymentTerms = vendorPaymentTerms;
1014     }
1015 
1016     public ShippingPaymentTerms getVendorShippingPaymentTerms() {
1017         return vendorShippingPaymentTerms;
1018     }
1019 
1020     public void setVendorShippingPaymentTerms(ShippingPaymentTerms vendorShippingPaymentTerms) {
1021         this.vendorShippingPaymentTerms = vendorShippingPaymentTerms;
1022     }
1023 
1024     public ShippingTitle getVendorShippingTitle() {
1025 
1026         if (ObjectUtils.isNull(vendorShippingTitle)) {
1027             this.refreshReferenceObject("vendorShippingTitle");
1028         }
1029 
1030         return vendorShippingTitle;
1031     }
1032 
1033     public void setVendorShippingTitle(ShippingTitle vendorShippingTitle) {
1034         this.vendorShippingTitle = vendorShippingTitle;
1035     }
1036 
1037     public List getPurchaseOrderVendorStipulations() {
1038         return purchaseOrderVendorStipulations;
1039     }
1040 
1041     public String getStatusChange() {
1042         return statusChange;
1043     }
1044 
1045     public void setPurchaseOrderVendorStipulations(List purchaseOrderVendorStipulations) {
1046         this.purchaseOrderVendorStipulations = purchaseOrderVendorStipulations;
1047     }
1048 
1049     public List<PurchaseOrderVendorQuote> getPurchaseOrderVendorQuotes() {
1050         return purchaseOrderVendorQuotes;
1051     }
1052 
1053     public void setPurchaseOrderVendorQuotes(List<PurchaseOrderVendorQuote> purchaseOrderVendorQuotes) {
1054         this.purchaseOrderVendorQuotes = purchaseOrderVendorQuotes;
1055     }
1056 
1057     public PurchaseOrderVendorQuote getPurchaseOrderVendorQuote(int index) {
1058         while (getPurchaseOrderVendorQuotes().size() <= index) {
1059             getPurchaseOrderVendorQuotes().add(new PurchaseOrderVendorQuote());
1060         }
1061         return purchaseOrderVendorQuotes.get(index);
1062     }
1063 
1064     public void setStatusChange(String statusChange) {
1065         this.statusChange = statusChange;
1066     }
1067 
1068     public String getPurchaseOrderRetransmissionMethodCode() {
1069         return purchaseOrderRetransmissionMethodCode;
1070     }
1071 
1072     public void setPurchaseOrderRetransmissionMethodCode(String purchaseOrderRetransmissionMethodCode) {
1073         this.purchaseOrderRetransmissionMethodCode = purchaseOrderRetransmissionMethodCode;
1074     }
1075 
1076     public String getRetransmitHeader() {
1077         return retransmitHeader;
1078     }
1079 
1080     public void setRetransmitHeader(String retransmitHeader) {
1081         this.retransmitHeader = retransmitHeader;
1082     }
1083 
1084     public boolean isPendingActionIndicator() {
1085         return pendingActionIndicator;
1086     }
1087 
1088     public void setPendingActionIndicator(boolean pendingActionIndicator) {
1089         this.pendingActionIndicator = pendingActionIndicator;
1090     }
1091 
1092     public boolean isPurchaseOrderCurrentIndicator() {
1093         return purchaseOrderCurrentIndicator;
1094     }
1095 
1096     public void setPurchaseOrderCurrentIndicator(boolean purchaseOrderCurrentIndicator) {
1097         this.purchaseOrderCurrentIndicator = purchaseOrderCurrentIndicator;
1098     }
1099 
1100     public Timestamp getPurchaseOrderFirstTransmissionTimestamp() {
1101         return purchaseOrderFirstTransmissionTimestamp;
1102     }
1103 
1104     public void setPurchaseOrderFirstTransmissionTimestamp(Timestamp purchaseOrderFirstTransmissionTimestamp) {
1105         this.purchaseOrderFirstTransmissionTimestamp = purchaseOrderFirstTransmissionTimestamp;
1106     }
1107 
1108     /**
1109      * Gets the purchaseOrderQuoteAwardedDate attribute.
1110      *
1111      * @return Returns the purchaseOrderQuoteAwardedDate.
1112      */
1113     public Date getPurchaseOrderQuoteAwardedDate() {
1114         return purchaseOrderQuoteAwardedDate;
1115     }
1116 
1117     /**
1118      * Sets the purchaseOrderQuoteAwardedDate attribute value.
1119      *
1120      * @param purchaseOrderQuoteAwardedDate The purchaseOrderQuoteAwardedDate to set.
1121      */
1122     public void setPurchaseOrderQuoteAwardedDate(Date purchaseOrderQuoteAwardedDate) {
1123         this.purchaseOrderQuoteAwardedDate = purchaseOrderQuoteAwardedDate;
1124     }
1125 
1126     /**
1127      * Gets the purchaseOrderQuoteInitializationDate attribute.
1128      *
1129      * @return Returns the purchaseOrderQuoteInitializationDate.
1130      */
1131     public Date getPurchaseOrderQuoteInitializationDate() {
1132         return purchaseOrderQuoteInitializationDate;
1133     }
1134 
1135     /**
1136      * Sets the purchaseOrderQuoteInitializationDate attribute value.
1137      *
1138      * @param purchaseOrderQuoteInitializationDate
1139      *         The purchaseOrderQuoteInitializationDate to set.
1140      */
1141     public void setPurchaseOrderQuoteInitializationDate(Date purchaseOrderQuoteInitializationDate) {
1142         this.purchaseOrderQuoteInitializationDate = purchaseOrderQuoteInitializationDate;
1143     }
1144 
1145     /**
1146      * Gets the alternateVendorNumber attribute.
1147      *
1148      * @return Returns the alternateVendorNumber.
1149      */
1150     public String getAlternateVendorNumber() {
1151         String hdrGenId = "";
1152         String detAssgndId = "";
1153         String vendorNumber = "";
1154         if (this.alternateVendorHeaderGeneratedIdentifier != null) {
1155             hdrGenId = this.alternateVendorHeaderGeneratedIdentifier.toString();
1156         }
1157         if (this.alternateVendorDetailAssignedIdentifier != null) {
1158             detAssgndId = this.alternateVendorDetailAssignedIdentifier.toString();
1159         }
1160         if (!StringUtils.isEmpty(hdrGenId) && !StringUtils.isEmpty(detAssgndId)) {
1161             vendorNumber = hdrGenId + VendorConstants.DASH + detAssgndId;
1162         }
1163         return vendorNumber;
1164     }
1165 
1166     /**
1167      * Sets the alternateVendorNumber attribute value.
1168      *
1169      * @param alternateVendorNumber The vendorNumber to set.
1170      */
1171     public void setAlternateVendorNumber(String vendorNumber) {
1172         if (!StringUtils.isEmpty(vendorNumber)) {
1173             int dashInd = vendorNumber.indexOf(VendorConstants.DASH);
1174             if (vendorNumber.length() >= dashInd) {
1175                 String vndrHdrGenId = vendorNumber.substring(0, dashInd);
1176                 String vndrDetailAssgnedId = vendorNumber.substring(dashInd + 1);
1177                 if (!StringUtils.isEmpty(vndrHdrGenId) && !StringUtils.isEmpty(vndrDetailAssgnedId)) {
1178                     this.alternateVendorHeaderGeneratedIdentifier = new Integer(vndrHdrGenId);
1179                     this.alternateVendorDetailAssignedIdentifier = new Integer(vndrDetailAssgnedId);
1180                 }
1181             }
1182         } else {
1183             this.alternateVendorNumber = vendorNumber;
1184         }
1185     }
1186 
1187     /**
1188      * Sets alternate vendor fields based on a given VendorDetail.
1189      *
1190      * @param vendorDetail the vendor detail used to set vendor fields.
1191      */
1192     public void templateAlternateVendor(VendorDetail vendorDetail) {
1193         if (vendorDetail == null) {
1194             return;
1195         }
1196         this.setAlternateVendorNumber(vendorDetail.getVendorHeaderGeneratedIdentifier() + VendorConstants.DASH + vendorDetail.getVendorDetailAssignedIdentifier());
1197         this.setAlternateVendorName(vendorDetail.getVendorName());
1198     }
1199 
1200     /**
1201      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getItemClass()
1202      */
1203     @Override
1204     public Class getItemClass() {
1205         return PurchaseOrderItem.class;
1206     }
1207 
1208     @Override
1209     public Class getItemUseTaxClass() {
1210         return PurchaseOrderItemUseTax.class;
1211     }
1212 
1213     /**
1214      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentIfPossible()
1215      */
1216     @Override
1217     public RequisitionDocument getPurApSourceDocumentIfPossible() {
1218         RequisitionDocument sourceDoc = null;
1219         if (ObjectUtils.isNotNull(getRequisitionIdentifier())) {
1220             sourceDoc = SpringContext.getBean(RequisitionService.class).getRequisitionById(getRequisitionIdentifier());
1221         }
1222         return sourceDoc;
1223     }
1224 
1225     /**
1226      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentLabelIfPossible()
1227      */
1228     @Override
1229     public String getPurApSourceDocumentLabelIfPossible() {
1230         return SpringContext.getBean(DataDictionaryService.class).getDocumentLabelByTypeName(OLEConstants.FinancialDocumentTypeCodes.REQUISITION);
1231     }
1232 
1233     public Integer getNewQuoteVendorDetailAssignedIdentifier() {
1234         return newQuoteVendorDetailAssignedIdentifier;
1235     }
1236 
1237     public void setNewQuoteVendorDetailAssignedIdentifier(Integer newQuoteVendorDetailAssignedIdentifier) {
1238         this.newQuoteVendorDetailAssignedIdentifier = newQuoteVendorDetailAssignedIdentifier;
1239     }
1240 
1241     public Integer getNewQuoteVendorHeaderGeneratedIdentifier() {
1242         return newQuoteVendorHeaderGeneratedIdentifier;
1243     }
1244 
1245     public void setNewQuoteVendorHeaderGeneratedIdentifier(Integer newQuoteVendorHeaderGeneratedIdentifier) {
1246         this.newQuoteVendorHeaderGeneratedIdentifier = newQuoteVendorHeaderGeneratedIdentifier;
1247     }
1248 
1249     public Integer getPurchaseOrderQuoteListIdentifier() {
1250         return purchaseOrderQuoteListIdentifier;
1251     }
1252 
1253     public void setPurchaseOrderQuoteListIdentifier(Integer purchaseOrderQuoteListIdentifier) {
1254         this.purchaseOrderQuoteListIdentifier = purchaseOrderQuoteListIdentifier;
1255     }
1256 
1257     /**
1258      * Returns true if a vendor has been awarded for this Purchase Order.
1259      *
1260      * @return true if a vendor has been awarded for this Purchase Order.
1261      */
1262     public boolean isPurchaseOrderAwarded() {
1263         return (getAwardedVendorQuote() != null);
1264     }
1265 
1266     /**
1267      * Returns the quote from the awarded vendor.
1268      *
1269      * @return the quote from the awarded vendor.
1270      */
1271     public PurchaseOrderVendorQuote getAwardedVendorQuote() {
1272         for (PurchaseOrderVendorQuote vendorQuote : purchaseOrderVendorQuotes) {
1273             if (vendorQuote.getPurchaseOrderQuoteAwardTimestamp() != null) {
1274                 return vendorQuote;
1275             }
1276         }
1277         return null;
1278     }
1279 
1280     /**
1281      * @see org.kuali.ole.module.purap.document.PurchasingDocumentBase#getTotalDollarAmount()
1282      */
1283     @Override
1284     public KualiDecimal getTotalDollarAmount() {
1285         // return total without inactive and with below the line
1286         return getTotalDollarAmount(false, true);
1287     }
1288 
1289     /**
1290      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getTotalDollarAmountAboveLineItems()
1291      */
1292     @Override
1293     public KualiDecimal getTotalDollarAmountAboveLineItems() {
1294         return getTotalDollarAmount(false, false);
1295     }
1296 
1297     /**
1298      * Gets the total dollar amount for this Purchase Order.
1299      *
1300      * @param includeInactive     indicates whether inactive items shall be included.
1301      * @param includeBelowTheLine indicates whether below the line items shall be included.
1302      * @return the total dollar amount for this Purchase Order.
1303      */
1304     public KualiDecimal getTotalDollarAmount(boolean includeInactive, boolean includeBelowTheLine) {
1305         KualiDecimal total = new KualiDecimal(BigDecimal.ZERO);
1306         for (PurApItem item : (List<PurApItem>) getItems()) {
1307 
1308             if (item.getPurapDocument() == null) {
1309                 item.setPurapDocument(this);
1310             }
1311             ItemType it = item.getItemType();
1312             if ((includeBelowTheLine || it.isLineItemIndicator()) && (includeInactive || PurApItemUtils.checkItemActive(item))) {
1313                 KualiDecimal totalAmount = item.getTotalAmount();
1314                 KualiDecimal itemTotal = (totalAmount != null) ? totalAmount : KualiDecimal.ZERO;
1315                 total = total.add(itemTotal);
1316             }
1317         }
1318         return total;
1319     }
1320 
1321     /**
1322      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getTotalPreTaxDollarAmount()
1323      */
1324     @Override
1325     public KualiDecimal getTotalPreTaxDollarAmount() {
1326         // return total without inactive and with below the line
1327         return getTotalPreTaxDollarAmount(false, true);
1328     }
1329 
1330     /**
1331      * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getTotalPreTaxDollarAmountAboveLineItems()
1332      */
1333     @Override
1334     public KualiDecimal getTotalPreTaxDollarAmountAboveLineItems() {
1335         return getTotalPreTaxDollarAmount(false, false);
1336     }
1337 
1338     /**
1339      * Gets the pre tax total dollar amount for this Purchase Order.
1340      *
1341      * @param includeInactive     indicates whether inactive items shall be included.
1342      * @param includeBelowTheLine indicates whether below the line items shall be included.
1343      * @return the total dollar amount for this Purchase Order.
1344      */
1345     public KualiDecimal getTotalPreTaxDollarAmount(boolean includeInactive, boolean includeBelowTheLine) {
1346         KualiDecimal total = new KualiDecimal(BigDecimal.ZERO);
1347         for (PurchaseOrderItem item : (List<PurchaseOrderItem>) getItems()) {
1348             ItemType it = item.getItemType();
1349             if ((includeBelowTheLine || it.isLineItemIndicator()) && (includeInactive || item.isItemActiveIndicator())) {
1350                 KualiDecimal extendedPrice = item.getExtendedPrice();
1351                 KualiDecimal itemTotal = (extendedPrice != null) ? extendedPrice : KualiDecimal.ZERO;
1352                 total = total.add(itemTotal);
1353             }
1354         }
1355         return total;
1356     }
1357 
1358 
1359     @Override
1360     public KualiDecimal getTotalTaxAmount() {
1361         // return total without inactive and with below the line
1362         return getTotalTaxAmount(false, true);
1363     }
1364 
1365     @Override
1366     public KualiDecimal getTotalTaxAmountAboveLineItems() {
1367         return getTotalTaxAmount(false, false);
1368     }
1369 
1370     /**
1371      * Gets the tax total amount for this Purchase Order.
1372      *
1373      * @param includeInactive     indicates whether inactive items shall be included.
1374      * @param includeBelowTheLine indicates whether below the line items shall be included.
1375      * @return the total dollar amount for this Purchase Order.
1376      */
1377     public KualiDecimal getTotalTaxAmount(boolean includeInactive, boolean includeBelowTheLine) {
1378         KualiDecimal total = new KualiDecimal(BigDecimal.ZERO);
1379         for (PurchaseOrderItem item : (List<PurchaseOrderItem>) getItems()) {
1380             ItemType it = item.getItemType();
1381             if ((includeBelowTheLine || it.isLineItemIndicator()) && (includeInactive || item.isItemActiveIndicator())) {
1382                 KualiDecimal taxAmount = item.getItemTaxAmount();
1383                 KualiDecimal itemTotal = (taxAmount != null) ? taxAmount : KualiDecimal.ZERO;
1384                 total = total.add(itemTotal);
1385             }
1386         }
1387         return total;
1388     }
1389 
1390     /**
1391      * Returns true if this Purchase Order contains unpaid items in the Payment Request or Credit Memo.
1392      *
1393      * @return true if this Purchase Order contains unpaid items in the Payment Request or Credit Memo.
1394      */
1395     public boolean getContainsUnpaidPaymentRequestsOrCreditMemos() {
1396         if (getRelatedViews().getRelatedPaymentRequestViews() != null) {
1397             for (PaymentRequestView element : getRelatedViews().getRelatedPaymentRequestViews()) {
1398                 // If the PREQ is neither cancelled nor voided, check whether the PREQ has been paid.
1399                 // If it has not been paid, then this method will return true.
1400                 if (!PurapConstants.PaymentRequestStatuses.CANCELLED_STATUSES.contains(element.getApplicationDocumentStatus())) {
1401                     if (element.getPaymentPaidTimestamp() == null) {
1402                         return true;
1403                     }
1404                 }
1405             }// endfor
1406         }
1407         if (getRelatedViews().getRelatedCreditMemoViews() != null) {
1408             for (CreditMemoView element : getRelatedViews().getRelatedCreditMemoViews()) {
1409                 // If the CM is cancelled, check whether the CM has been paid.
1410                 // If it has not been paid, then this method will return true.
1411                 if (!CreditMemoStatuses.CANCELLED_STATUSES.contains(element.getApplicationDocumentStatus())) {
1412                     if (element.getCreditMemoPaidTimestamp() == null) {
1413                         return true;
1414                     }
1415                 }
1416             }// endfor
1417         }
1418         if (getRelatedViews().getRelatedInvoiceViews() != null) {
1419             for (InvoiceView element : getRelatedViews().getRelatedInvoiceViews()) {
1420                 // If the invoice is neither cancelled nor voided, check whether the invoice has been paid.
1421                 // If it has not been paid, then this method will return true.
1422                 if (!PurapConstants.InvoiceStatuses.CANCELLED_STATUSES.contains(element.getApplicationDocumentStatus())) {
1423                     if (element.getPaymentPaidTimestamp() == null) {
1424                         return true;
1425                     }
1426                 }
1427             }// endfor
1428         }
1429 
1430         return false;
1431     }
1432 
1433     public boolean getAdditionalChargesExist() {
1434         List<PurchaseOrderItem> items = this.getItems();
1435         for (PurchaseOrderItem item : items) {
1436             if ((item != null) &&
1437                     (item.getItemType() != null) &&
1438                     (item.getItemType().isAdditionalChargeIndicator()) &&
1439                     (item.getExtendedPrice() != null) &&
1440                     (!KualiDecimal.ZERO.equals(item.getExtendedPrice()))) {
1441                 return true;
1442             }
1443         }
1444         return false;
1445     }
1446 
1447     /**
1448      * Used for routing only.
1449      *
1450      * @deprecated
1451      */
1452     @Deprecated
1453     public String getContractManagerName() {
1454         return "";
1455     }
1456 
1457     /**
1458      * Used for routing only.
1459      *
1460      * @deprecated
1461      */
1462     @Deprecated
1463     public void setContractManagerName(String contractManagerName) {
1464     }
1465 
1466     public KualiDecimal getInternalPurchasingLimit() {
1467         //FIXME need the following because at places this field remains null because contract manager is not refreshed and null
1468 
1469         if (internalPurchasingLimit == null) {
1470             setInternalPurchasingLimit(SpringContext.getBean(PurchaseOrderService.class).getInternalPurchasingDollarLimit(this));
1471         }
1472         return internalPurchasingLimit;
1473     }
1474 
1475     public void setInternalPurchasingLimit(KualiDecimal internalPurchasingLimit) {
1476         this.internalPurchasingLimit = internalPurchasingLimit;
1477     }
1478 
1479     public boolean isPendingSplit() {
1480         return pendingSplit;
1481     }
1482 
1483     public void setPendingSplit(boolean pendingSplit) {
1484         this.pendingSplit = pendingSplit;
1485     }
1486 
1487     public boolean isCopyingNotesWhenSplitting() {
1488         return copyingNotesWhenSplitting;
1489     }
1490 
1491     public void setCopyingNotesWhenSplitting(boolean copyingNotesWhenSplitting) {
1492         this.copyingNotesWhenSplitting = copyingNotesWhenSplitting;
1493     }
1494 
1495     /**
1496      * @see org.kuali.module.purap.rules.PurapAccountingDocumentRuleBase#customizeExplicitGeneralLedgerPendingEntry(org.kuali.ole.sys.document.AccountingDocument,
1497      *      org.kuali.ole.sys.businessobject.AccountingLine, org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry)
1498      */
1499     @Override
1500     public void customizeExplicitGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySourceDetail postable, GeneralLedgerPendingEntry explicitEntry) {
1501         super.customizeExplicitGeneralLedgerPendingEntry(postable, explicitEntry);
1502 
1503         SpringContext.getBean(PurapGeneralLedgerService.class).customizeGeneralLedgerPendingEntry(this, (AccountingLine) postable, explicitEntry, getPurapDocumentIdentifier(), GL_DEBIT_CODE, PurapDocTypeCodes.PO_DOCUMENT, true);
1504 
1505         KualiDecimal accountTotalGLEntryAmount = this.getAccountTotalGLEntryAmount((AccountingLine) postable);
1506         explicitEntry.setTransactionLedgerEntryAmount(accountTotalGLEntryAmount);
1507         String debitCreditCode = GL_DEBIT_CODE;
1508 
1509         // if the amount is negative, flip the D/C indicator
1510         if (accountTotalGLEntryAmount.doubleValue() < 0) {
1511             if (GL_CREDIT_CODE.equals(debitCreditCode)) {
1512                 if (GL_CREDIT_CODE.equals(debitCreditCode)) {
1513                     explicitEntry.setTransactionDebitCreditCode(GL_DEBIT_CODE);
1514                 }
1515             } else {
1516                 explicitEntry.setTransactionDebitCreditCode(GL_CREDIT_CODE);
1517             }
1518         } else {
1519             explicitEntry.setTransactionDebitCreditCode(debitCreditCode);
1520         }
1521 
1522         // don't think i should have to override this, but default isn't getting the right PO doc
1523         explicitEntry.setFinancialDocumentTypeCode(PurapDocTypeCodes.PO_DOCUMENT);
1524     }
1525 
1526     @Override
1527     public Class getPurchasingCapitalAssetItemClass() {
1528         return PurchaseOrderCapitalAssetItem.class;
1529     }
1530 
1531     @Override
1532     public Class getPurchasingCapitalAssetSystemClass() {
1533         return PurchaseOrderCapitalAssetSystem.class;
1534     }
1535 
1536     /**
1537      * Validates whether we can indeed close the PO. Return false and give error if
1538      * the outstanding encumbrance amount of the trade in item is less than 0.
1539      *
1540      * @param po
1541      * @return
1542      */
1543     public boolean canClosePOForTradeIn() {
1544         for (PurchaseOrderItem item : (List<PurchaseOrderItem>) getItems()) {
1545             if (item.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE) && item.getItemOutstandingEncumberedAmount().isLessThan(new KualiDecimal(0))) {
1546                 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_ITEM_TRADE_IN_OUTSTANDING_ENCUMBERED_AMOUNT_NEGATIVE, "amend the PO");
1547                 return false;
1548             }
1549         }
1550         return true;
1551     }
1552 
1553     /**
1554      * Provides answers to the following splits:
1555      * RequiresContractManagementReview
1556      * RequiresBudgetReview
1557      * VendorIsEmployeeOrNonResidentAlien
1558      * TransmissionMethodIsPrint
1559      *
1560      * @see org.kuali.ole.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String)
1561      */
1562     @Override
1563     public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
1564         if (nodeName.equals(PurapWorkflowConstants.CONTRACT_MANAGEMENT_REVIEW_REQUIRED)) {
1565             return isContractManagementReviewRequired();
1566         }
1567         if (nodeName.equals(PurapWorkflowConstants.AWARD_REVIEW_REQUIRED)) {
1568             return isAwardReviewRequired();
1569         }
1570         if (nodeName.equals(PurapWorkflowConstants.BUDGET_REVIEW_REQUIRED)) {
1571             return isBudgetReviewRequired();
1572         }
1573         if (nodeName.equals(PurapWorkflowConstants.VENDOR_IS_EMPLOYEE_OR_NON_RESIDENT_ALIEN)) {
1574             return isVendorEmployeeOrNonResidentAlien();
1575         }
1576 
1577         if (nodeName.equals(PurapWorkflowConstants.NOTIFY_BUDGET_REVIEW)) {
1578             return isNotificationRequired();
1579         }
1580         return super.answerSplitNodeQuestion(nodeName);
1581     }
1582 
1583     protected boolean isContractManagementReviewRequired() {
1584         KualiDecimal internalPurchasingLimit = SpringContext.getBean(PurchaseOrderService.class).getInternalPurchasingDollarLimit(this);
1585         return ((ObjectUtils.isNull(internalPurchasingLimit)) || (internalPurchasingLimit.compareTo(this.getTotalDollarAmount()) < 0));
1586 
1587     }
1588 
1589     protected boolean isAwardReviewRequired() {
1590         ParameterService parameterService = SpringContext.getBean(ParameterService.class);
1591         boolean objectCodeAllowed = true;
1592 
1593         for (PurApItem item : (List<PurApItem>) this.getItems()) {
1594             for (PurApAccountingLine accountingLine : item.getSourceAccountingLines()) {
1595 
1596                 objectCodeAllowed = isObjectCodeAllowedForAwardRouting(accountingLine, parameterService);
1597                 // We should return true as soon as we have at least one objectCodeAllowed=true so that the PO will stop at Award
1598                 // level.
1599                 if (objectCodeAllowed) {
1600                     return objectCodeAllowed;
1601                 }
1602 
1603             }
1604         }
1605         return objectCodeAllowed;
1606     }
1607 
1608     protected boolean isObjectCodeAllowedForAwardRouting(PurApAccountingLine accountingLine, ParameterService parameterService) {
1609         if (ObjectUtils.isNull(accountingLine.getObjectCode())) {
1610             return false;
1611         }
1612 
1613         // make sure object code is active
1614         if (!accountingLine.getObjectCode().isFinancialObjectActiveCode()) {
1615             return false;
1616         }
1617 
1618         String chartCode = accountingLine.getChartOfAccountsCode();
1619         // check object level is in permitted list for award routing
1620         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();
1621 
1622         if (!objectCodeAllowed) {
1623             // If the object level is not permitting for award routing, then we need to also
1624             // check object code is in permitted list for award routing
1625             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();
1626         }
1627         return objectCodeAllowed;
1628     }
1629 
1630     protected boolean isBudgetReviewRequired() {
1631         // if document's fiscal year is less than or equal to the current fiscal year
1632         if (SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear().compareTo(getPostingYear()) >= 0) {
1633 
1634             List<SourceAccountingLine> sourceAccountingLineList = this.getSourceAccountingLines();
1635             boolean sufficientFundCheck = false;
1636             for (SourceAccountingLine accLine : sourceAccountingLineList) {
1637                 Map searchMap = new HashMap();
1638                 String notificationOption = null;
1639                 Map<String, Object> key = new HashMap<String, Object>();
1640                 String chartCode = accLine.getChartOfAccountsCode();
1641                 String accNo = accLine.getAccountNumber();
1642                 String objectCd = accLine.getFinancialObjectCode();
1643                 key.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartCode);
1644                 key.put(OLEPropertyConstants.ACCOUNT_NUMBER, accNo);
1645                 OleSufficientFundCheck account = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(
1646                         OleSufficientFundCheck.class, key);
1647                 if (account != null) {
1648                     notificationOption = account.getNotificationOption();
1649                 }
1650                 if (notificationOption != null
1651                         && (notificationOption.equals(OLEPropertyConstants.BUD_REVIEW) )) {
1652             // get list of sufficientfundItems
1653 
1654             // delete and recreate the GL entries for this document so they do not get included in the SF check
1655             // This is *NOT* ideal.  The SF service needs to be updated to allow it to provide the current
1656             // document number so that it can be exlcuded from pending entry checks.
1657             List<GeneralLedgerPendingEntry> pendingEntries = getPendingLedgerEntriesForSufficientFundsChecking();
1658             // dumb loop to just force OJB to load the objects.  Otherwise, the proxy object above
1659             // only gets resolved *after* the delete below and no SF check happens.
1660             for (GeneralLedgerPendingEntry glpe : pendingEntries) {
1661                 glpe.getChartOfAccountsCode();
1662             }
1663             SpringContext.getBean(GeneralLedgerPendingEntryService.class).delete(getDocumentNumber());
1664             List<SufficientFundsItem> fundsItems = SpringContext.getBean(SufficientFundsService.class).checkSufficientFunds(pendingEntries);
1665             SpringContext.getBean(GeneralLedgerPendingEntryService.class).generateGeneralLedgerPendingEntries(this);
1666             SpringContext.getBean(BusinessObjectService.class).save(getGeneralLedgerPendingEntries());
1667             if (fundsItems.size() > 0) {
1668                 return true;
1669             }
1670                 }
1671                 /*Commented for jira OLE-2359
1672                  * for (SufficientFundsItem fundsItem : fundsItems) {
1673                     if (this.getChartOfAccountsCode().equalsIgnoreCase(fundsItem.getAccount().getChartOfAccountsCode())) {
1674                     LOG.debug("Chart code of rule extension matches chart code of at least one Sufficient Funds Item");
1675                     return true;
1676                 }
1677             }*/
1678         }
1679         }
1680 
1681         return false;
1682     }
1683 
1684     private boolean isNotificationRequired() {
1685         OleRequisitionDocumentService oleRequisitionDocumentService = (OleRequisitionDocumentService) SpringContext
1686                 .getBean("oleRequisitionDocumentService");
1687         List<SourceAccountingLine> sourceAccountingLineList = this.getSourceAccountingLines();
1688         boolean sufficientFundCheck = false;
1689         for (SourceAccountingLine accLine : sourceAccountingLineList) {
1690             Map searchMap = new HashMap();
1691             String notificationOption = null;
1692             Map<String, Object> key = new HashMap<String, Object>();
1693             String chartCode = accLine.getChartOfAccountsCode();
1694             String accNo = accLine.getAccountNumber();
1695             String objectCd = accLine.getFinancialObjectCode();
1696             key.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, chartCode);
1697             key.put(OLEPropertyConstants.ACCOUNT_NUMBER, accNo);
1698             OleSufficientFundCheck account = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(
1699                     OleSufficientFundCheck.class, key);
1700             if (account != null) {
1701                 notificationOption = account.getNotificationOption();
1702             }
1703             if (notificationOption != null && notificationOption.equals(OLEPropertyConstants.NOTIFICATION)) {
1704                 sufficientFundCheck = oleRequisitionDocumentService.hasSufficientFundsOnRequisition(accLine);
1705                 if (sufficientFundCheck) {
1706                     return sufficientFundCheck;
1707                 }
1708             }
1709         }
1710         return sufficientFundCheck;
1711     }
1712 
1713 
1714     protected boolean isVendorEmployeeOrNonResidentAlien() {
1715         if (ObjectUtils.isNull(this.getVendorHeaderGeneratedIdentifier())) {
1716             // no vendor header id so can't check for proper tax routing
1717             return false;
1718         }
1719         String currencytype=new String();
1720         String vendorHeaderGeneratedId = this.getVendorHeaderGeneratedIdentifier().toString();
1721         VendorService vendorService = SpringContext.getBean(VendorService.class);
1722         boolean routeDocumentAsEmployeeVendor = vendorService.isVendorInstitutionEmployee(Integer.valueOf(vendorHeaderGeneratedId));
1723       //  boolean routeDocumentAsForeignVendor = vendorService.isVendorForeign(Integer.valueOf(vendorHeaderGeneratedId));
1724         Map fieldValues = new HashMap();
1725         fieldValues.put(OleSelectConstant.VENDOR_HEADER_GENERATED_ID, vendorHeaderGeneratedId);
1726         ArrayList<VendorDetail> vendorDetail=new  ArrayList<>(SpringContext.getBean(BusinessObjectService.class).findMatching(VendorDetail.class, fieldValues)) ;
1727         if(vendorDetail!=null && vendorDetail.size()>0 ) {
1728             if (vendorDetail.get(0).getCurrencyType()!= null){
1729                 currencytype=vendorDetail.get(0).getCurrencyType().getCurrencyType();
1730             }
1731         }
1732         if ((!routeDocumentAsEmployeeVendor) && ((currencytype.equalsIgnoreCase(OleSelectConstant.CURRENCY_TYPE_NAME) || (vendorDetail.get(0).getCurrencyType() == null)) )) {
1733             // no need to route
1734             return false;
1735         }
1736 
1737         return true;
1738     }
1739 
1740     public List<Account> getAccountsForAwardRouting() {
1741         List<Account> accounts = new ArrayList<Account>();
1742 
1743         ParameterService parameterService = SpringContext.getBean(ParameterService.class);
1744         for (PurApItem item : (List<PurApItem>) this.getItems()) {
1745             for (PurApAccountingLine accountingLine : item.getSourceAccountingLines()) {
1746                 if (isObjectCodeAllowedForAwardRouting(accountingLine, parameterService)) {
1747                     if (ObjectUtils.isNull(accountingLine.getAccount())) {
1748                         accountingLine.refreshReferenceObject("account");
1749                     }
1750                     if (accountingLine.getAccount() != null && !accounts.contains(accountingLine.getAccount())) {
1751                         accounts.add(accountingLine.getAccount());
1752                     }
1753                 }
1754             }
1755         }
1756         return accounts;
1757     }
1758 
1759     @Override
1760     public DocumentSearchCriteria convertSelections(DocumentSearchCriteria searchCriteria) {
1761         // RICE 20 : No longer applicable with Rice 2.0 functionality
1762 //        for (DocumentTypeAttributeBo comp : searchCriteria.getSearchableAttributes()) {
1763 //            if (comp.getLookupableFieldType().equals(Field.MULTISELECT)) {
1764 //                List<String> values = comp.getValues();
1765 //                List<String> newVals = new ArrayList<String>();
1766 //                if (values.contains("INCOMPLETE")) {
1767 //                    for (String str : PurchaseOrderStatuses.INCOMPLETE_STATUSES) {
1768 //                        newVals.add(str);
1769 //                    }
1770 //                } if (values.contains("COMPLETE")) {
1771 //                    for (String str : PurchaseOrderStatuses.COMPLETE_STATUSES) {
1772 //                        newVals.add(str);
1773 //                    }
1774 //                }
1775 //
1776 //                for (String str : values) {
1777 //                    newVals.add(str);
1778 //                }
1779 //
1780 //                comp.setValues(newVals);
1781 //            }
1782 //        }
1783         return searchCriteria;
1784     }
1785 
1786     /**
1787      * @return the purchase order current indicator
1788      */
1789     public boolean getPurchaseOrderCurrentIndicatorForSearching() {
1790         return purchaseOrderCurrentIndicator;
1791     }
1792 
1793     public String getDocumentTitleForResult() throws WorkflowException {
1794         return KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(this.getFinancialSystemDocumentHeader().getWorkflowDocument().getDocumentTypeName()).getLabel();
1795     }
1796 
1797     /**
1798      * Checks whether the purchase order needs a warning to be displayed, i.e. it never has been opened.
1799      *
1800      * @return true if the purchase order needs a warning; false otherwise.
1801      */
1802     public boolean getNeedWarning() {
1803         return getPurchaseOrderInitialOpenTimestamp() == null;
1804     }
1805 
1806     public List<SourceAccountingLine> getGlOnlySourceAccountingLines() {
1807         return glOnlySourceAccountingLines;
1808     }
1809 
1810     public void setGlOnlySourceAccountingLines(List<SourceAccountingLine> glOnlySourceAccountingLines) {
1811         this.glOnlySourceAccountingLines = glOnlySourceAccountingLines;
1812     }
1813 
1814     @Override
1815     public PersistableBusinessObject getNoteTarget() {
1816         PurchaseOrderDao purchaseOrderDao = SpringContext.getBean(PurchaseOrderDao.class);
1817         DocumentDao docDao = GlobalResourceLoader.getService( "documentDao"  );
1818 
1819         PurchaseOrderDocument oldest = docDao.findByDocumentHeaderId(PurchaseOrderDocument.class,
1820                 purchaseOrderDao.getOldestPurchaseOrderDocumentNumber(this.getPurapDocumentIdentifier()));
1821 
1822         // OLEMI-9746: added this for null safe checking.
1823         if (oldest != null) {
1824             return oldest.getDocumentHeader();
1825         }
1826 
1827         return this.getDocumentHeader();
1828     }
1829 
1830     @Override
1831     public NoteType getNoteType() {
1832         return NoteType.BUSINESS_OBJECT;
1833     }
1834 
1835     public boolean isCreatedFromRequisition() {
1836         return this.getRequisitionIdentifier() != null;
1837     }
1838 
1839 }