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