001/*
002 * Copyright 2007 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.kuali.ole.module.purap.document;
018
019import org.apache.commons.lang.StringUtils;
020import org.kuali.ole.module.purap.PurapConstants;
021import org.kuali.ole.module.purap.PurapConstants.InvoiceStatuses;
022import org.kuali.ole.module.purap.PurapConstants.PurapDocTypeCodes;
023import org.kuali.ole.module.purap.PurapParameterConstants;
024import org.kuali.ole.module.purap.PurapPropertyConstants;
025import org.kuali.ole.module.purap.PurapWorkflowConstants;
026import org.kuali.ole.module.purap.businessobject.*;
027import org.kuali.ole.module.purap.document.service.*;
028import org.kuali.ole.module.purap.service.PurapGeneralLedgerService;
029import org.kuali.ole.module.purap.util.ExpiredOrClosedAccountEntry;
030import org.kuali.ole.select.businessobject.OleLineItemReceivingItem;
031import org.kuali.ole.select.businessobject.OlePurchaseOrderItem;
032import org.kuali.ole.select.document.OleLineItemReceivingDocument;
033import org.kuali.ole.select.document.OlePurchaseOrderDocument;
034import org.kuali.ole.select.document.service.OleInvoiceService;
035import org.kuali.ole.sys.OLEConstants;
036import org.kuali.ole.sys.businessobject.AccountingLine;
037import org.kuali.ole.sys.businessobject.Bank;
038import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry;
039import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
040import org.kuali.ole.sys.context.SpringContext;
041import org.kuali.ole.sys.service.BankService;
042import org.kuali.ole.sys.service.UniversityDateService;
043import org.kuali.ole.sys.service.impl.OleParameterConstants;
044import org.kuali.ole.vnd.VendorPropertyConstants;
045import org.kuali.ole.vnd.businessobject.PaymentTermType;
046import org.kuali.ole.vnd.businessobject.PurchaseOrderCostSource;
047import org.kuali.ole.vnd.businessobject.ShippingPaymentTerms;
048import org.kuali.ole.vnd.businessobject.VendorDetail;
049import org.kuali.ole.vnd.document.service.VendorService;
050import org.kuali.rice.core.api.datetime.DateTimeService;
051import org.kuali.rice.core.api.util.type.KualiDecimal;
052import org.kuali.rice.coreservice.framework.parameter.ParameterService;
053import org.kuali.rice.kew.api.WorkflowDocument;
054import org.kuali.rice.kew.api.exception.WorkflowException;
055import org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent;
056import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
057import org.kuali.rice.kim.api.identity.Person;
058import org.kuali.rice.kns.service.DataDictionaryService;
059import org.kuali.rice.krad.bo.Note;
060import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent;
061import org.kuali.rice.krad.service.DocumentHeaderService;
062import org.kuali.rice.krad.util.GlobalVariables;
063import org.kuali.rice.krad.util.ObjectUtils;
064import org.kuali.rice.krad.workflow.service.WorkflowDocumentService;
065
066import java.math.BigDecimal;
067import java.sql.Date;
068import java.sql.Timestamp;
069import java.text.SimpleDateFormat;
070import java.util.*;
071
072/**
073 * Payment Request Document Business Object. Contains the fields associated with the main document table.
074 */
075public class InvoiceDocument extends AccountsPayableDocumentBase {
076    protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(InvoiceDocument.class);
077
078    protected Date invoiceDate;
079    protected String invoiceNumber;
080    protected KualiDecimal vendorInvoiceAmount;
081    protected String vendorPaymentTermsCode;
082    protected String vendorShippingPaymentTermsCode;
083    protected Date invoicePayDate;
084    protected String invoiceCostSourceCode;
085    protected boolean invoiceCancelIndicator;
086    protected boolean paymentAttachmentIndicator;
087    protected boolean immediatePaymentIndicator;
088    protected String specialHandlingInstructionLine1Text;
089    protected String specialHandlingInstructionLine2Text;
090    protected String specialHandlingInstructionLine3Text;
091    protected Timestamp paymentPaidTimestamp;
092    protected boolean invoiceElectronicInvoiceIndicator;
093    protected String accountsPayableRequestCancelIdentifier;
094    protected Integer originalVendorHeaderGeneratedIdentifier;
095    protected Integer originalVendorDetailAssignedIdentifier;
096    protected Integer alternateVendorHeaderGeneratedIdentifier;
097    protected Integer alternateVendorDetailAssignedIdentifier;
098    protected String purchaseOrderNotes;
099    protected String recurringPaymentTypeCode;
100    protected boolean receivingDocumentRequiredIndicator;
101    protected boolean invoicePositiveApprovalIndicator;
102
103    // TAX EDIT AREA FIELDS
104    protected String taxClassificationCode;
105    protected String taxCountryCode;
106    protected String taxNQIId;
107    protected BigDecimal taxFederalPercent; // number is in whole form so 5% is 5.00
108    protected BigDecimal taxStatePercent; // number is in whole form so 5% is 5.00
109    protected KualiDecimal taxSpecialW4Amount;
110    protected Boolean taxGrossUpIndicator;
111    protected Boolean taxExemptTreatyIndicator;
112    protected Boolean taxForeignSourceIndicator;
113    protected Boolean taxUSAIDPerDiemIndicator;
114    protected Boolean taxOtherExemptIndicator;
115
116    // NOT PERSISTED IN DB
117    protected String vendorShippingTitleCode;
118    protected Date purchaseOrderEndDate;
119    protected String primaryVendorName;
120
121    // BELOW USED BY ROUTING
122    protected Integer requisitionIdentifier;
123
124    // REFERENCE OBJECTS
125    protected PaymentTermType vendorPaymentTerms;
126    protected ShippingPaymentTerms vendorShippingPaymentTerms;
127    protected PurchaseOrderCostSource invoiceCostSource;
128    protected RecurringPaymentType recurringPaymentType;
129    private List<OlePurchaseOrderDocument> purchaseOrderDocuments = new ArrayList<OlePurchaseOrderDocument>();
130
131    public List<OlePurchaseOrderDocument> getPurchaseOrderDocuments() {
132        return purchaseOrderDocuments;
133    }
134
135    public void setPurchaseOrderDocuments(List<OlePurchaseOrderDocument> purchaseOrderDocuments) {
136        this.purchaseOrderDocuments = purchaseOrderDocuments;
137    }
138
139    /*private InvoiceService invoiceService;*/
140
141
142    /**
143     * Default constructor.
144     */
145    public InvoiceDocument() {
146        super();
147    }
148
149    /**
150     * @see org.kuali.rice.krad.bo.PersistableBusinessObjectBase#isBoNotesSupport()
151     */
152    public boolean isBoNotesSupport() {
153        return true;
154    }
155
156    public Integer getPostingYearPriorOrCurrent() {
157        if (SpringContext.getBean(InvoiceService.class).allowBackpost(this)) {
158            // allow prior; use it
159            return SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear() - 1;
160        }
161        // don't allow prior; use CURRENT
162        return SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear();
163    }
164
165
166    /**
167     * Overrides the method in PurchasingAccountsPayableDocumentBase to add the criteria specific to Payment Request Document.
168     *
169     * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#isInquiryRendered()
170     */
171    @Override
172    public boolean isInquiryRendered() {
173        if (isPostingYearPrior() && (getApplicationDocumentStatus().equals(InvoiceStatuses.APPDOC_DEPARTMENT_APPROVED) || getApplicationDocumentStatus().equals(InvoiceStatuses.APPDOC_AUTO_APPROVED) || getApplicationDocumentStatus().equals(InvoiceStatuses.APPDOC_CANCELLED_POST_AP_APPROVE) || getApplicationDocumentStatus().equals(InvoiceStatuses.APPDOC_CANCELLED_IN_PROCESS))) {
174            return false;
175        } else {
176            return true;
177        }
178    }
179
180    public Integer getRequisitionIdentifier() {
181        return getPurchaseOrderDocument().getRequisitionIdentifier();
182    }
183
184    public void setRequisitionIdentifier(Integer requisitionIdentifier) {
185        this.requisitionIdentifier = requisitionIdentifier;
186    }
187
188    /**
189     * @see org.kuali.ole.module.purap.document.AccountsPayableDocumentBase#populateDocumentForRouting()
190     */
191   /* @Override
192    public void populateDocumentForRouting() {
193        this.setRequisitionIdentifier(getPurchaseOrderDocument().getRequisitionIdentifier());
194        super.populateDocumentForRouting();
195    }*/
196
197    /**
198     * Decides whether receivingDocumentRequiredIndicator functionality shall be enabled according to the controlling parameter.
199     */
200    public boolean isEnableReceivingDocumentRequiredIndicator() {
201        return SpringContext.getBean(OleInvoiceService.class).getParameterBoolean(OLEConstants.OptionalModuleNamespaces.PURCHASING_ACCOUNTS_PAYABLE, OleParameterConstants.DOCUMENT_COMPONENT,PurapParameterConstants.RECEIVING_DOCUMENT_REQUIRED_IND);
202    }
203
204    /**
205     * Decides whether invoicePositiveApprovalIndicator functionality shall be enabled according to the controlling parameter.
206     */
207    public boolean isEnableInvoicePositiveApprovalIndicator() {
208        return SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(OleParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.PAYMENT_REQUEST_POSITIVE_APPROVAL_IND);
209    }
210
211    public Date getInvoiceDate() {
212        return invoiceDate;
213    }
214
215    public void setInvoiceDate(Date invoiceDate) {
216        this.invoiceDate = invoiceDate;
217    }
218
219    public String getInvoiceNumber() {
220        return invoiceNumber;
221    }
222
223    public void setInvoiceNumber(String invoiceNumber) {
224        if (!StringUtils.isEmpty(invoiceNumber)) {
225            this.invoiceNumber = invoiceNumber.toUpperCase();
226        } else {
227            this.invoiceNumber = invoiceNumber;
228        }
229    }
230
231    public KualiDecimal getVendorInvoiceAmount() {
232        return vendorInvoiceAmount;
233    }
234
235    public void setVendorInvoiceAmount(KualiDecimal vendorInvoiceAmount) {
236        this.vendorInvoiceAmount = vendorInvoiceAmount;
237    }
238
239    public String getVendorPaymentTermsCode() {
240        return vendorPaymentTermsCode;
241    }
242
243    public void setVendorPaymentTermsCode(String vendorPaymentTermsCode) {
244        this.vendorPaymentTermsCode = vendorPaymentTermsCode;
245        refreshReferenceObject("vendorPaymentTerms");
246    }
247
248    public PaymentTermType getVendorPaymentTerms() {
249        if (ObjectUtils.isNull(vendorPaymentTerms) || !StringUtils.equalsIgnoreCase(getVendorPaymentTermsCode(), vendorPaymentTerms.getVendorPaymentTermsCode())) {
250            refreshReferenceObject(VendorPropertyConstants.VENDOR_PAYMENT_TERMS);
251        }
252        return vendorPaymentTerms;
253    }
254
255    public void setVendorPaymentTerms(PaymentTermType vendorPaymentTerms) {
256        this.vendorPaymentTerms = vendorPaymentTerms;
257    }
258
259    public String getVendorShippingPaymentTermsCode() {
260        if (ObjectUtils.isNull(vendorPaymentTerms)) {
261            refreshReferenceObject(VendorPropertyConstants.VENDOR_SHIPPING_PAYMENT_TERMS);
262        }
263        return vendorShippingPaymentTermsCode;
264    }
265
266    public void setVendorShippingPaymentTermsCode(String vendorShippingPaymentTermsCode) {
267        this.vendorShippingPaymentTermsCode = vendorShippingPaymentTermsCode;
268    }
269
270    public Date getInvoicePayDate() {
271        return invoicePayDate;
272    }
273
274    public void setInvoicePayDate(Date invoicePayDate) {
275        this.invoicePayDate = invoicePayDate;
276    }
277
278    public String getInvoiceCostSourceCode() {
279        return invoiceCostSourceCode;
280    }
281
282    public void setInvoiceCostSourceCode(String invoiceCostSourceCode) {
283        this.invoiceCostSourceCode = invoiceCostSourceCode;
284    }
285
286    public boolean getInvoiceCancelIndicator() {
287        return invoiceCancelIndicator;
288    }
289
290    public boolean isInvoiceCancelIndicator() {
291        return invoiceCancelIndicator;
292    }
293
294    public void setInvoiceCancelIndicator(boolean invoiceCancelIndicator) {
295        this.invoiceCancelIndicator = invoiceCancelIndicator;
296    }
297
298    public boolean getPaymentAttachmentIndicator() {
299        return paymentAttachmentIndicator;
300    }
301
302    public void setPaymentAttachmentIndicator(boolean paymentAttachmentIndicator) {
303        this.paymentAttachmentIndicator = paymentAttachmentIndicator;
304    }
305
306    public boolean getImmediatePaymentIndicator() {
307        return immediatePaymentIndicator;
308    }
309
310    public void setImmediatePaymentIndicator(boolean immediatePaymentIndicator) {
311        this.immediatePaymentIndicator = immediatePaymentIndicator;
312    }
313
314    public String getSpecialHandlingInstructionLine1Text() {
315        return specialHandlingInstructionLine1Text;
316    }
317
318    public void setSpecialHandlingInstructionLine1Text(String specialHandlingInstructionLine1Text) {
319        this.specialHandlingInstructionLine1Text = specialHandlingInstructionLine1Text;
320    }
321
322    public String getSpecialHandlingInstructionLine2Text() {
323        return specialHandlingInstructionLine2Text;
324    }
325
326    public void setSpecialHandlingInstructionLine2Text(String specialHandlingInstructionLine2Text) {
327        this.specialHandlingInstructionLine2Text = specialHandlingInstructionLine2Text;
328    }
329
330    public String getSpecialHandlingInstructionLine3Text() {
331        return specialHandlingInstructionLine3Text;
332    }
333
334    public void setSpecialHandlingInstructionLine3Text(String specialHandlingInstructionLine3Text) {
335        this.specialHandlingInstructionLine3Text = specialHandlingInstructionLine3Text;
336    }
337
338    public Timestamp getPaymentPaidTimestamp() {
339        return paymentPaidTimestamp;
340    }
341
342    public void setPaymentPaidTimestamp(Timestamp paymentPaidTimestamp) {
343        this.paymentPaidTimestamp = paymentPaidTimestamp;
344    }
345
346    public boolean getInvoiceElectronicInvoiceIndicator() {
347        return invoiceElectronicInvoiceIndicator;
348    }
349
350    public void setInvoiceElectronicInvoiceIndicator(boolean invoiceElectronicInvoiceIndicator) {
351        this.invoiceElectronicInvoiceIndicator = invoiceElectronicInvoiceIndicator;
352    }
353
354    public String getAccountsPayableRequestCancelIdentifier() {
355        return accountsPayableRequestCancelIdentifier;
356    }
357
358    public void setAccountsPayableRequestCancelIdentifier(String accountsPayableRequestCancelIdentifier) {
359        this.accountsPayableRequestCancelIdentifier = accountsPayableRequestCancelIdentifier;
360    }
361
362    public Integer getOriginalVendorHeaderGeneratedIdentifier() {
363        return originalVendorHeaderGeneratedIdentifier;
364    }
365
366    public void setOriginalVendorHeaderGeneratedIdentifier(Integer originalVendorHeaderGeneratedIdentifier) {
367        this.originalVendorHeaderGeneratedIdentifier = originalVendorHeaderGeneratedIdentifier;
368    }
369
370    public Integer getOriginalVendorDetailAssignedIdentifier() {
371        return originalVendorDetailAssignedIdentifier;
372    }
373
374    public void setOriginalVendorDetailAssignedIdentifier(Integer originalVendorDetailAssignedIdentifier) {
375        this.originalVendorDetailAssignedIdentifier = originalVendorDetailAssignedIdentifier;
376    }
377
378    public Integer getAlternateVendorHeaderGeneratedIdentifier() {
379        return alternateVendorHeaderGeneratedIdentifier;
380    }
381
382    public void setAlternateVendorHeaderGeneratedIdentifier(Integer alternateVendorHeaderGeneratedIdentifier) {
383        this.alternateVendorHeaderGeneratedIdentifier = alternateVendorHeaderGeneratedIdentifier;
384    }
385
386    public Integer getAlternateVendorDetailAssignedIdentifier() {
387        return alternateVendorDetailAssignedIdentifier;
388    }
389
390    public void setAlternateVendorDetailAssignedIdentifier(Integer alternateVendorDetailAssignedIdentifier) {
391        this.alternateVendorDetailAssignedIdentifier = alternateVendorDetailAssignedIdentifier;
392    }
393
394    public ShippingPaymentTerms getVendorShippingPaymentTerms() {
395        return vendorShippingPaymentTerms;
396    }
397
398    public void setVendorShippingPaymentTerms(ShippingPaymentTerms vendorShippingPaymentTerms) {
399        this.vendorShippingPaymentTerms = vendorShippingPaymentTerms;
400    }
401
402    public String getVendorShippingTitleCode() {
403        if (ObjectUtils.isNotNull(this.getPurchaseOrderDocument())) {
404            return this.getPurchaseOrderDocument().getVendorShippingTitleCode();
405        }
406        return vendorShippingTitleCode;
407    }
408
409    public void setVendorShippingTitleCode(String vendorShippingTitleCode) {
410        this.vendorShippingTitleCode = vendorShippingTitleCode;
411    }
412
413    public Date getPurchaseOrderEndDate() {
414        return purchaseOrderEndDate;
415    }
416
417    public void setPurchaseOrderEndDate(Date purchaseOrderEndDate) {
418        this.purchaseOrderEndDate = purchaseOrderEndDate;
419    }
420
421    /**
422     * Gets the invoicePositiveApprovalIndicator attribute.
423     *
424     * @return Returns the invoicePositiveApprovalIndicator.
425     */
426    public boolean isInvoicePositiveApprovalIndicator() {
427        return invoicePositiveApprovalIndicator;
428    }
429
430    /**
431     * Sets the invoicePositiveApprovalIndicator attribute value.
432     *
433     * @param invoicePositiveApprovalIndicator
434     *         The invoicePositiveApprovalIndicator to set.
435     */
436    public void setInvoicePositiveApprovalIndicator(boolean invoicePositiveApprovalIndicator) {
437        // if invoicePositiveApprovalIndicator functionality is disabled, always set it to false, overriding the passed-in value
438        if (!isEnableInvoicePositiveApprovalIndicator()) {
439            invoicePositiveApprovalIndicator = false;
440        } else {
441            this.invoicePositiveApprovalIndicator = invoicePositiveApprovalIndicator;
442        }
443    }
444
445    /**
446     * Gets the receivingDocumentRequiredIndicator attribute.
447     *
448     * @return Returns the receivingDocumentRequiredIndicator.
449     */
450    public boolean isReceivingDocumentRequiredIndicator() {
451        return receivingDocumentRequiredIndicator;
452    }
453
454    /**
455     * Sets the receivingDocumentRequiredIndicator attribute value.
456     *
457     * @param receivingDocumentRequiredIndicator
458     *         The receivingDocumentRequiredIndicator to set.
459     */
460    public void setReceivingDocumentRequiredIndicator(boolean receivingDocumentRequiredIndicator) {
461        // if receivingDocumentRequiredIndicator functionality is disabled, always set it to false, overriding the passed-in value
462        if (!isEnableReceivingDocumentRequiredIndicator()) {
463            this.receivingDocumentRequiredIndicator = false;
464        } else {
465            this.receivingDocumentRequiredIndicator = receivingDocumentRequiredIndicator;
466        }
467    }
468
469    /**
470     * Perform logic needed to initiate PRQS Document
471     */
472    public void initiateDocument() throws WorkflowException {
473        LOG.debug("initiateDocument() started");
474        Person currentUser = GlobalVariables.getUserSession().getPerson();
475        if (this.getDocumentHeader().getDocumentNumber() == null) {
476            this.setDocumentHeader(SpringContext.getBean(DocumentHeaderService.class).getDocumentHeaderById(getDocumentNumber()));
477        }
478        //oleInvoiceDocument.setItems(items);
479        UniversityDateService universityDateService = SpringContext.getBean(UniversityDateService.class);
480        this.setPostingYear(universityDateService.getCurrentUniversityDate().getUniversityFiscalYear());
481        Bank defaultBank = SpringContext.getBean(BankService.class).getDefaultBankByDocType(this.getClass());
482        if (defaultBank != null) {
483            this.setBankCode(defaultBank.getBankCode());
484            this.setBank(defaultBank);
485        }
486        updateAndSaveAppDocStatus(InvoiceStatuses.APPDOC_INITIATE);
487        this.setAccountsPayableProcessorIdentifier(currentUser.getPrincipalId());
488        this.setProcessingCampusCode(currentUser.getCampusCode());
489        this.refreshNonUpdateableReferences();
490        this.getDocumentHeader().setDocumentDescription(" New Invoice Document ");
491    }
492
493    /**
494     * Perform logic needed to clear the initial fields on a PRQS Document
495     */
496    public void clearInitFields() {
497        LOG.debug("clearDocument() started");
498        // Clearing document overview fields
499        this.getDocumentHeader().setDocumentDescription(null);
500        this.getDocumentHeader().setExplanation(null);
501        this.getFinancialSystemDocumentHeader().setFinancialDocumentTotalAmount(null);
502        this.getDocumentHeader().setOrganizationDocumentNumber(null);
503
504        // Clearing document Init fields
505        //this.setPurchaseOrderIdentifier(null);
506        this.setInvoiceNumber(null);
507        this.setInvoiceDate(null);
508        this.setVendorInvoiceAmount(null);
509        this.setSpecialHandlingInstructionLine1Text(null);
510        this.setSpecialHandlingInstructionLine2Text(null);
511        this.setSpecialHandlingInstructionLine3Text(null);
512    }
513
514    /**
515     * Populates a preq from a PO - delegate method
516     *
517     * @param po -
518     */
519    public void populateInvoiceFromPurchaseOrder(PurchaseOrderDocument po) {
520        populateInvoiceFromPurchaseOrder(po, new HashMap<String, ExpiredOrClosedAccountEntry>());
521    }
522
523
524    /**
525     * Populates a preq from a PO
526     *
527     * @param po                         Purchase Order Document used for populating the PRQS
528     * @param expiredOrClosedAccountList a list of closed or expired accounts
529     */
530    public void populateInvoiceFromPurchaseOrder(PurchaseOrderDocument po, HashMap<String, ExpiredOrClosedAccountEntry> expiredOrClosedAccountList) {
531        //this.setPurchaseOrderIdentifier(po.getPurapDocumentIdentifier());
532        this.getDocumentHeader().setOrganizationDocumentNumber(po.getDocumentHeader().getOrganizationDocumentNumber());
533        this.setPostingYear(this.getPostingYearPriorOrCurrent());
534        this.setReceivingDocumentRequiredIndicator(po.isReceivingDocumentRequiredIndicator());
535        //this.setUseTaxIndicator(po.isUseTaxIndicator());
536        this.setInvoicePositiveApprovalIndicator(po.isPaymentRequestPositiveApprovalIndicator());
537        //this.setVendorCustomerNumber(po.getVendorCustomerNumber());
538        //this.setAccountDistributionMethod(po.getAccountDistributionMethod());
539
540        if (po.getPurchaseOrderCostSource() != null) {
541            this.setInvoiceCostSource(po.getPurchaseOrderCostSource());
542            this.setInvoiceCostSourceCode(po.getPurchaseOrderCostSourceCode());
543        }
544
545        if (po.getVendorShippingPaymentTerms() != null) {
546            this.setVendorShippingPaymentTerms(po.getVendorShippingPaymentTerms());
547            this.setVendorShippingPaymentTermsCode(po.getVendorShippingPaymentTermsCode());
548        }
549
550        if (po.getVendorPaymentTerms() != null) {
551            this.setVendorPaymentTermsCode(po.getVendorPaymentTermsCode());
552            this.setVendorPaymentTerms(po.getVendorPaymentTerms());
553        }
554
555        if (po.getRecurringPaymentType() != null) {
556            this.setRecurringPaymentType(po.getRecurringPaymentType());
557            this.setRecurringPaymentTypeCode(po.getRecurringPaymentTypeCode());
558        }
559
560        /*this.setVendorHeaderGeneratedIdentifier(po.getVendorHeaderGeneratedIdentifier());
561        this.setVendorDetailAssignedIdentifier(po.getVendorDetailAssignedIdentifier());
562        this.setVendorCustomerNumber(po.getVendorCustomerNumber());
563        this.setVendorName(po.getVendorName());*/
564
565        // set original vendor
566        this.setOriginalVendorHeaderGeneratedIdentifier(po.getVendorHeaderGeneratedIdentifier());
567        this.setOriginalVendorDetailAssignedIdentifier(po.getVendorDetailAssignedIdentifier());
568
569        // set alternate vendor info as well
570        this.setAlternateVendorHeaderGeneratedIdentifier(po.getAlternateVendorHeaderGeneratedIdentifier());
571        this.setAlternateVendorDetailAssignedIdentifier(po.getAlternateVendorDetailAssignedIdentifier());
572
573        // populate preq vendor address with the default remit address type for the vendor if found
574        String userCampus = GlobalVariables.getUserSession().getPerson().getCampusCode();
575        /*VendorAddress vendorAddress = SpringContext.getBean(VendorService.class).getVendorDefaultAddress(po.getVendorHeaderGeneratedIdentifier(), po.getVendorDetailAssignedIdentifier(), VendorConstants.AddressTypes.REMIT, userCampus);
576        if (vendorAddress != null) {
577            this.templateVendorAddress(vendorAddress);
578            this.setVendorAddressGeneratedIdentifier(vendorAddress.getVendorAddressGeneratedIdentifier());
579            setVendorAttentionName(StringUtils.defaultString(vendorAddress.getVendorAttentionName()));
580        }
581        else {
582            // set address from PO
583            this.setVendorAddressGeneratedIdentifier(po.getVendorAddressGeneratedIdentifier());
584            this.setVendorLine1Address(po.getVendorLine1Address());
585            this.setVendorLine2Address(po.getVendorLine2Address());
586            this.setVendorCityName(po.getVendorCityName());
587            this.setVendorAddressInternationalProvinceName(po.getVendorAddressInternationalProvinceName());
588            this.setVendorStateCode(po.getVendorStateCode());
589            this.setVendorPostalCode(po.getVendorPostalCode());
590            this.setVendorCountryCode(po.getVendorCountryCode());
591
592            boolean blankAttentionLine = StringUtils.equalsIgnoreCase("Y", SpringContext.getBean(ParameterService.class).getParameterValueAsString(PurapConstants.PURAP_NAMESPACE, "Document", PurapParameterConstants.BLANK_ATTENTION_LINE_FOR_PO_TYPE_ADDRESS));
593
594            if (blankAttentionLine) {
595                setVendorAttentionName(StringUtils.EMPTY);
596            }
597            else {
598                setVendorAttentionName(StringUtils.defaultString(po.getVendorAttentionName()));
599            }
600        }*/
601
602        this.setInvoicePayDate(SpringContext.getBean(InvoiceService.class).calculatePayDate(this.getInvoiceDate(), this.getVendorPaymentTerms()));
603
604        AccountsPayableService accountsPayableService = SpringContext.getBean(AccountsPayableService.class);
605
606        if (SpringContext.getBean(InvoiceService.class).encumberedItemExistsForInvoicing(po)) {
607            for (PurchaseOrderItem poi : (List<PurchaseOrderItem>) po.getItems()) {
608                // check to make sure it's eligible for payment (i.e. active and has encumbrance available
609                if (getDocumentSpecificService().poItemEligibleForAp(this, poi)) {
610                    InvoiceItem invoiceItem = new InvoiceItem(poi, this, expiredOrClosedAccountList);
611                    invoiceItem.setReceivingDocumentRequiredIndicator(po.isReceivingDocumentRequiredIndicator());
612                    this.getItems().add(invoiceItem);
613                    PurchasingCapitalAssetItem purchasingCAMSItem = po.getPurchasingCapitalAssetItemByItemIdentifier(poi.getItemIdentifier());
614                    if (purchasingCAMSItem != null) {
615                        invoiceItem.setCapitalAssetTransactionTypeCode(purchasingCAMSItem.getCapitalAssetTransactionTypeCode());
616                    }
617
618                    /*
619                    // copy usetaxitems over
620                    invoiceItem.getUseTaxItems().clear();
621                    for (PurApItemUseTax useTax : poi.getUseTaxItems()) {
622                        invoiceItem.getUseTaxItems().add(useTax);
623                    }
624                    */
625                }
626            }
627        }
628
629        // add missing below the line
630        SpringContext.getBean(PurapService.class).addBelowLineItems(this);
631        this.setAccountsPayablePurchasingDocumentLinkIdentifier(po.getAccountsPayablePurchasingDocumentLinkIdentifier());
632
633        //fix up below the line items
634        SpringContext.getBean(InvoiceService.class).removeIneligibleAdditionalCharges(this);
635
636        this.fixItemReferences();
637        this.refreshNonUpdateableReferences();
638    }
639
640    /**
641     * @see org.kuali.rice.krad.document.DocumentBase#getDocumentTitle()
642     */
643    @Override
644    public String getDocumentTitle() {
645        if (SpringContext.getBean(OleInvoiceService.class).getParameterBoolean(OLEConstants.OptionalModuleNamespaces.PURCHASING_ACCOUNTS_PAYABLE, OLEConstants.InvoiceDocument.CMPNT_CD, PurapParameterConstants.PURAP_OVERRIDE_PRQS_DOC_TITLE)) {
646            return getCustomDocumentTitle();
647        }
648        return this.buildDocumentTitle(super.getDocumentTitle());
649    }
650
651    /**
652     * Returns a custom document title based on the workflow document title. Depending on what route level the document is currently
653     * in, the PO, vendor, amount, account number, dept, campus may be added to the documents title.
654     *
655     * @return - Customized document title text dependent upon route level.
656     */
657    protected String getCustomDocumentTitle() {
658
659        // set the workflow document title
660        //String poNumber = getPurchaseOrderIdentifier().toString();
661        String vendorName = StringUtils.trimToEmpty(getVendorName());
662        String preqAmount = getGrandTotal().toString();
663
664        String documentTitle = "";
665        Set<String> nodeNames = this.getFinancialSystemDocumentHeader().getWorkflowDocument().getCurrentNodeNames();
666
667        // if this doc is final or will be final
668        if (nodeNames.size() == 0 || this.getFinancialSystemDocumentHeader().getWorkflowDocument().isFinal()) {
669            // documentTitle = (new StringBuffer("PO: ")).append(poNumber).append(" Vendor: ").append(vendorName).append(" Amount: ").append(preqAmount).toString();
670            documentTitle = (new StringBuffer()).append(" Vendor: ").append(vendorName).append(" Amount: ").append(preqAmount).toString();
671        } else {
672            PurApAccountingLine theAccount = getFirstAccount();
673            String accountNumber = (theAccount != null ? StringUtils.trimToEmpty(theAccount.getAccountNumber()) : "n/a");
674            String accountChart = (theAccount != null ? theAccount.getChartOfAccountsCode() : "");
675            String payDate = (new SimpleDateFormat("MM/dd/yyyy")).format(getInvoicePayDate());
676            String indicator = getTitleIndicator();
677
678            // set title to: PO# - VendorName - Chart/Account - total amt - Pay Date - Indicator (ie Hold, Request Cancel)
679            documentTitle = (new StringBuffer()).append(" Vendor: ").append(vendorName).append(" Account: ").append(accountChart).append(" ").append(accountNumber).append(" Amount: ").append(preqAmount).append(" Pay Date: ").append(payDate).append(" ").append(indicator).toString();
680        }
681        return documentTitle;
682    }
683
684    /**
685     * Returns the first payment item's first account (assuming the item list is sequentially ordered).
686     *
687     * @return - Accounting Line object for first account of first payment item.
688     */
689    public PurApAccountingLine getFirstAccount() {
690        // loop through items, and pick the first item
691        if ((getItems() != null) && (!getItems().isEmpty())) {
692            InvoiceItem itemToUse = null;
693            for (Iterator iter = getItems().iterator(); iter.hasNext(); ) {
694                InvoiceItem item = (InvoiceItem) iter.next();
695                if ((item.isConsideredEntered()) && ((item.getSourceAccountingLines() != null) && (!item.getSourceAccountingLines().isEmpty()))) {
696                    // accounting lines are not empty so pick the first account
697                    PurApAccountingLine accountLine = item.getSourceAccountingLine(0);
698                    accountLine.refreshNonUpdateableReferences();
699                    return accountLine;
700                }
701                /*
702                if (((item.getExtendedPrice() != null) && item.getExtendedPrice().compareTo(BigDecimal.ZERO) > 0) && ((item.getAccounts() != null) && (!item.getAccounts().isEmpty()))) {
703                    // accounting lines are not empty so pick the first account
704               List accts = (List)item.getAccounts();
705               InvoiceAccount accountLine = (InvoiceAccount)accts.get(0);
706                    return accountLine.getFinancialChartOfAccountsCode() + "-" + accountLine.getAccountNumber();
707                }
708                */
709            }
710        }
711        return null;
712    }
713
714    /**
715     * Determines the indicator text that will appear in the workflow document title
716     *
717     * @return - Text of hold or request cancel
718     */
719    protected String getTitleIndicator() {
720        if (isHoldIndicator()) {
721            return PurapConstants.InvoiceIndicatorText.HOLD;
722        } else if (isInvoiceCancelIndicator()) {
723            return PurapConstants.InvoiceIndicatorText.REQUEST_CANCEL;
724        }
725        return "";
726    }
727
728
729    /**
730     * @see org.kuali.rice.krad.document.DocumentBase#doRouteStatusChange(org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange)
731     */
732    @Override
733    public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) {
734        LOG.debug("doRouteStatusChange() started");
735
736        super.doRouteStatusChange(statusChangeEvent);
737        try {
738            // DOCUMENT PROCESSED
739            if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isProcessed()) {
740                if (!InvoiceStatuses.APPDOC_AUTO_APPROVED.equals(getApplicationDocumentStatus())) {
741                    populateDocumentForRouting();
742                    updateAndSaveAppDocStatus(InvoiceStatuses.APPDOC_DEPARTMENT_APPROVED);
743
744                    //PurchaseOrderDocument purchaseOrderDocument = this.getPurchaseOrderDocument();
745                    /*if (purchaseOrderDocument.getOrderType().getPurchaseOrderType().equals(OLEConstants.ORD_TYPE_FIRM_FIX) || purchaseOrderDocument.getOrderType().getPurchaseOrderType().equals(OLEConstants.APPROVAL) || purchaseOrderDocument.getOrderType().getPurchaseOrderType().equals(OLEConstants.FIRM_MUL_PART)) {
746                        DocumentHeader invoiceDocumentHeader = this.getDocumentHeader();
747                        closePurchaseOrder();
748                        this.setDocumentHeader(invoiceDocumentHeader);
749                        } */
750
751                }
752            }
753
754            // DOCUMENT DISAPPROVED
755            else if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isDisapproved()) {
756                String nodeName = SpringContext.getBean(WorkflowDocumentService.class).getCurrentRouteLevelName(getDocumentHeader().getWorkflowDocument());
757                String disapprovalStatus = InvoiceStatuses.getInvoiceAppDocDisapproveStatuses().get(nodeName);
758
759                if (ObjectUtils.isNotNull(nodeName)) {
760                    if (((StringUtils.isBlank(disapprovalStatus)) && ((InvoiceStatuses.APPDOC_INITIATE.equals(getApplicationDocumentStatus())) || (InvoiceStatuses.APPDOC_IN_PROCESS.equals(getApplicationDocumentStatus()))))) {
761                        disapprovalStatus = InvoiceStatuses.APPDOC_CANCELLED_IN_PROCESS;
762                    }
763                    if (StringUtils.isNotBlank(disapprovalStatus)) {
764                        SpringContext.getBean(AccountsPayableService.class).cancelAccountsPayableDocument(this, nodeName);
765                    }
766                } else {
767                    logAndThrowRuntimeException("No status found to set for document being disapproved in node '" + nodeName + "'");
768                }
769            }
770            // DOCUMENT CANCELED
771            else if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isCanceled()) {
772                String currentNodeName = SpringContext.getBean(WorkflowDocumentService.class).getCurrentRouteLevelName(this.getDocumentHeader().getWorkflowDocument());
773                String cancelledStatus = InvoiceStatuses.getInvoiceAppDocDisapproveStatuses().get(currentNodeName);
774
775                //**START AZ** KATTS-37 KevinMcO
776                if (StringUtils.isBlank(cancelledStatus) &&
777                        StringUtils.isBlank(InvoiceStatuses.getInvoiceAppDocDisapproveStatuses().get(currentNodeName)) &&
778                        (InvoiceStatuses.APPDOC_INITIATE.equals(getStatusCode()) || InvoiceStatuses.APPDOC_IN_PROCESS.equals(getStatusCode()))) {
779                    cancelledStatus = InvoiceStatuses.APPDOC_CANCELLED_IN_PROCESS;
780                }
781                //**END AZ**
782
783                if (ObjectUtils.isNotNull(cancelledStatus)) {
784                    SpringContext.getBean(AccountsPayableService.class).cancelAccountsPayableDocument(this, currentNodeName);
785                    updateAndSaveAppDocStatus(cancelledStatus);
786                } else {
787                    logAndThrowRuntimeException("No status found to set for document being canceled in node '" + currentNodeName + "'");
788                }
789            }
790        } catch (WorkflowException e) {
791            logAndThrowRuntimeException("Error saving routing data while saving document with id " + getDocumentNumber(), e);
792        }
793    }
794
795    /**
796     * Generates correcting entries to the GL if accounts are modified.
797     *
798     * @see org.kuali.rice.krad.document.Document#doActionTaken(org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent)
799     */
800    @Override
801    public void doActionTaken(ActionTakenEvent event) {
802        super.doActionTaken(event);
803        WorkflowDocument workflowDocument = getDocumentHeader().getWorkflowDocument();
804        String currentNode = null;
805        Object[] names = workflowDocument.getCurrentNodeNames().toArray();
806        if (names.length > 0) {
807            currentNode = (String) names[0];
808        }
809
810        // everything in the below list requires correcting entries to be written to the GL
811        //   if (InvoiceStatuses.getNodesRequiringCorrectingGeneralLedgerEntries().contains(currentNode)) {
812        //       SpringContext.getBean(PurapGeneralLedgerService.class).generateEntriesModifyInvoice(this);
813        //    }
814    }
815
816    /**
817     * @see org.kuali.ole.module.purap.document.AccountsPayableDocumentBase#processNodeChange(String, String)
818     */
819    @Override
820    public boolean processNodeChange(String newNodeName, String oldNodeName) {
821        if (InvoiceStatuses.APPDOC_AUTO_APPROVED.equals(getApplicationDocumentStatus())) {
822            // do nothing for an auto approval
823            return false;
824        }
825        if (InvoiceStatuses.NODE_ADHOC_REVIEW.equals(oldNodeName)) {
826            SpringContext.getBean(AccountsPayableService.class).performLogicForFullEntryCompleted(this);
827        }
828        return true;
829    }
830
831    /**
832     * @see org.kuali.ole.module.purap.document.AccountsPayableDocumentBase#saveDocumentFromPostProcessing()
833     */
834    @Override
835    public void saveDocumentFromPostProcessing() {
836        SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
837
838        // if we've hit full entry completed then close/reopen po
839        if (SpringContext.getBean(PurapService.class).isFullDocumentEntryCompleted(this) && this.isClosePurchaseOrderIndicator()) {
840            SpringContext.getBean(PurapService.class).performLogicForCloseReopenPO(this);
841        }
842    }
843
844    /**
845     * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getItemClass()
846     */
847    @Override
848    public Class getItemClass() {
849        return InvoiceItem.class;
850    }
851
852    @Override
853    public Class getItemUseTaxClass() {
854        return InvoiceItemUseTax.class;
855    }
856
857    /**
858     * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentIfPossible()
859     */
860    @Override
861    public PurchaseOrderDocument getPurApSourceDocumentIfPossible() {
862        return getPurchaseOrderDocument();
863    }
864
865    /**
866     * @see org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentLabelIfPossible()
867     */
868    @Override
869    public String getPurApSourceDocumentLabelIfPossible() {
870        return SpringContext.getBean(DataDictionaryService.class).getDocumentLabelByTypeName(OLEConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER);
871    }
872
873    public String getPurchaseOrderNotes() {
874
875        ArrayList poNotes = (ArrayList) this.getPurchaseOrderDocument().getNotes();
876
877        if (poNotes.size() > 0) {
878            return "Yes";
879        }
880        return "No";
881    }
882
883    public void setPurchaseOrderNotes(String purchaseOrderNotes) {
884        this.purchaseOrderNotes = purchaseOrderNotes;
885    }
886
887    public String getRecurringPaymentTypeCode() {
888        return recurringPaymentTypeCode;
889    }
890
891    public void setRecurringPaymentTypeCode(String recurringPaymentTypeCode) {
892        this.recurringPaymentTypeCode = recurringPaymentTypeCode;
893    }
894
895    /**
896     * Returns the total encumbered amount from the purchase order excluding below the line.
897     *
898     * @return Total cost excluding below the line
899     */
900    public KualiDecimal getItemTotalPoEncumbranceAmount() {
901        // get total from po excluding below the line and inactive
902        return this.getPurchaseOrderDocument().getTotalDollarAmount(false, false);
903    }
904
905    public KualiDecimal getItemTotalPoEncumbranceAmountRelieved() {
906        return getItemTotalPoEncumbranceAmountRelieved(false);
907    }
908
909    public KualiDecimal getItemTotalPoEncumbranceAmountRelieved(boolean includeBelowTheLine) {
910
911        KualiDecimal total = KualiDecimal.ZERO;
912
913        for (PurchaseOrderItem item : (List<PurchaseOrderItem>) getPurchaseOrderDocument().getItems()) {
914            ItemType it = item.getItemType();
915            if (includeBelowTheLine || it.isLineItemIndicator()) {
916                total = total.add(item.getItemEncumbranceRelievedAmount());
917            }
918        }
919        return total;
920    }
921
922    public KualiDecimal getLineItemTotal() {
923        return this.getTotalDollarAmountAboveLineItems();
924    }
925
926    public KualiDecimal getLineItemPreTaxTotal() {
927        return this.getTotalPreTaxDollarAmountAboveLineItems();
928    }
929
930    public KualiDecimal getLineItemTaxAmount() {
931        return this.getTotalTaxAmountAboveLineItems();
932    }
933
934    @Override
935    public KualiDecimal getGrandTotal() {
936        return this.getTotalDollarAmount();
937    }
938
939    public KualiDecimal getGrandTotalExcludingDiscount() {
940        String[] discountCode = new String[]{PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE};
941        return this.getTotalDollarAmountWithExclusions(discountCode, true);
942    }
943
944    /**
945     * This method is here due to a setter requirement by the htmlControlAttribute
946     *
947     * @param amount - Grand total for document, excluding discount
948     */
949    public void setGrandTotalExcludingDiscount(KualiDecimal amount) {
950        // do nothing
951    }
952
953    public KualiDecimal getGrandPreTaxTotal() {
954        return this.getTotalPreTaxDollarAmount();
955    }
956
957    public KualiDecimal getGrandPreTaxTotalExcludingDiscount() {
958        String[] discountCode = new String[]{PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE};
959        return this.getTotalPreTaxDollarAmountWithExclusions(discountCode, true);
960    }
961
962    public KualiDecimal getGrandTaxAmount() {
963        return this.getTotalTaxAmount();
964    }
965
966    public KualiDecimal getGrandTaxAmountExcludingDiscount() {
967        String[] discountCode = new String[]{PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE};
968        return this.getTotalTaxAmountWithExclusions(discountCode, true);
969    }
970
971    public boolean isDiscount() {
972        return SpringContext.getBean(InvoiceService.class).hasDiscountItem(this);
973    }
974
975    /**
976     * The total that was paid on the po excluding below the line
977     *
978     * @return total paid
979     */
980    public KualiDecimal getItemTotalPoPaidAmount() {
981        KualiDecimal total = KualiDecimal.ZERO;
982        for (PurchaseOrderItem item : (List<PurchaseOrderItem>) getPurchaseOrderDocument().getItems()) {
983            ItemType iT = item.getItemType();
984            if (iT.isLineItemIndicator()) {
985                KualiDecimal itemPaid = item.getItemPaidAmount();
986                total = total.add(itemPaid);
987            }
988        }
989        return total;
990    }
991
992    /**
993     * Returns the name of who requested cancel.
994     *
995     * @return - name of who requested cancel.
996     */
997    public String getAccountsPayableRequestCancelPersonName() {
998        String personName = null;
999        Person user = SpringContext.getBean(org.kuali.rice.kim.api.identity.PersonService.class).getPerson(getAccountsPayableRequestCancelIdentifier());
1000        if (user != null) {
1001            personName = user.getName();
1002        } else {
1003            personName = "";
1004        }
1005
1006        return personName;
1007    }
1008
1009    /**
1010     * Exists due to a setter requirement by the htmlControlAttribute
1011     *
1012     * @param amount - total po amount paid
1013     */
1014    public void setItemTotalPoPaidAmount(KualiDecimal amount) {
1015        // do nothing
1016    }
1017
1018    /**
1019     * Exists due to a setter requirement by the htmlControlAttribute
1020     *
1021     * @param amount - total po encumbrance
1022     */
1023    public void setItemTotalPoEncumbranceAmount(KualiDecimal amount) {
1024        // do nothing
1025    }
1026
1027    /**
1028     * Exists due to a setter requirement by the htmlControlAttribute
1029     *
1030     * @param amount - total po encumbrance amount relieved
1031     */
1032    public void setItemTotalPoEncumbranceAmountRelieved(KualiDecimal amount) {
1033        // do nothing
1034    }
1035
1036    /**
1037     * Determinines the route levels for a given document.
1038     *
1039     * @param workflowDocument - work flow document
1040     * @return List - list of route levels
1041     */
1042    protected List<String> getCurrentRouteLevels(WorkflowDocument workflowDocument) {
1043        Set<String> names = workflowDocument.getCurrentNodeNames();
1044        return new ArrayList<String>(names);
1045    }
1046
1047    public RecurringPaymentType getRecurringPaymentType() {
1048        /*if (ObjectUtils.isNull(recurringPaymentType)) {
1049            refreshReferenceObject(PurapPropertyConstants.RECURRING_PAYMENT_TYPE);
1050        }*/
1051        return recurringPaymentType;
1052    }
1053
1054    public void setRecurringPaymentType(RecurringPaymentType recurringPaymentType) {
1055        this.recurringPaymentType = recurringPaymentType;
1056    }
1057
1058    public PurchaseOrderCostSource getInvoiceCostSource() {
1059        return invoiceCostSource;
1060    }
1061
1062    public void setInvoiceCostSource(PurchaseOrderCostSource invoiceCostSource) {
1063        this.invoiceCostSource = invoiceCostSource;
1064    }
1065
1066    /**
1067     * @see AccountsPayableDocumentBase#getPoDocumentTypeForAccountsPayableDocumentCancel()
1068     */
1069    @Override
1070    public String getPoDocumentTypeForAccountsPayableDocumentCancel() {
1071        return PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_REOPEN_DOCUMENT;
1072    }
1073
1074    /**
1075     * @see AccountsPayableDocumentBase#getInitialAmount()
1076     */
1077    @Override
1078    public KualiDecimal getInitialAmount() {
1079        return this.getVendorInvoiceAmount();
1080    }
1081
1082    /**
1083     * Populates the payment request document, then continues with preparing for save.
1084     *
1085     * @see org.kuali.rice.krad.document.Document#prepareForSave(org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent)
1086     */
1087    @Override
1088    public void prepareForSave(KualiDocumentEvent event) {
1089        WorkflowDocument workflowDocument = this.getDocumentHeader().getWorkflowDocument();
1090        String workflowDocumentTitle = this.buildDocumentTitle(workflowDocument.getTitle());
1091
1092        this.getFinancialSystemDocumentHeader().getWorkflowDocument().setTitle(workflowDocumentTitle);
1093
1094        // first populate, then call super
1095        /*if (event instanceof AttributedContinuePurapEvent) {
1096            SpringContext.getBean(InvoiceService.class).populateInvoice(this);
1097        }*/
1098        super.prepareForSave(event);
1099
1100    }
1101
1102    /**
1103     * @see AccountsPayableDocumentBase#isAttachmentRequired()
1104     */
1105    @Override
1106    protected boolean isAttachmentRequired() {
1107        if (getInvoiceElectronicInvoiceIndicator()) {
1108            return false;
1109        }
1110        return StringUtils.equalsIgnoreCase("Y", SpringContext.getBean(OleInvoiceService.class).getParameter(OLEConstants.OptionalModuleNamespaces.PURCHASING_ACCOUNTS_PAYABLE, OLEConstants.InvoiceDocument.CMPNT_CD,PurapParameterConstants.PURAP_PRQS_REQUIRE_ATTACHMENT));
1111    }
1112
1113    /**
1114     * @see AccountsPayableDocument#getDocumentSpecificService()
1115     */
1116    @Override
1117    public AccountsPayableDocumentSpecificService getDocumentSpecificService() {
1118        return SpringContext.getBean(InvoiceService.class);
1119    }
1120
1121    /**
1122     * @see PurchasingAccountsPayableDocumentBase#getItem(int)
1123     */
1124    @Override
1125    public PurApItem getItem(int pos) {
1126        InvoiceItem item = (InvoiceItem) super.getItem(pos);
1127        if (item.getInvoice() == null) {
1128            item.setInvoice(this);
1129        }
1130        return item;
1131    }
1132
1133    public String getPrimaryVendorName() {
1134
1135        if (primaryVendorName == null) {
1136            VendorDetail vd = SpringContext.getBean(VendorService.class).getVendorDetail(this.getOriginalVendorHeaderGeneratedIdentifier(), this.getOriginalVendorDetailAssignedIdentifier());
1137
1138            if (vd != null) {
1139                primaryVendorName = vd.getVendorName();
1140            }
1141        }
1142
1143        return primaryVendorName;
1144    }
1145
1146    /**
1147     * @deprecated
1148     */
1149    @Deprecated
1150    public void setPrimaryVendorName(String primaryVendorName) {
1151    }
1152
1153    /**
1154     * Forces general ledger entries to be approved, does not wait for payment request document final approval.
1155     *
1156     * @see org.kuali.module.purap.rules.PurapAccountingDocumentRuleBase#customizeExplicitGeneralLedgerPendingEntry(org.kuali.ole.sys.document.AccountingDocument,
1157     *      org.kuali.ole.sys.businessobject.AccountingLine, org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry)
1158     */
1159    @Override
1160    public void customizeExplicitGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySourceDetail postable, GeneralLedgerPendingEntry explicitEntry) {
1161        super.customizeExplicitGeneralLedgerPendingEntry(postable, explicitEntry);
1162
1163        SpringContext.getBean(PurapGeneralLedgerService.class).customizeGeneralLedgerPendingEntry(this, (AccountingLine) postable, explicitEntry, getPurchaseOrderIdentifier(), getDebitCreditCodeForGLEntries(), PurapDocTypeCodes.INVOICE_DOCUMENT, isGenerateEncumbranceEntries());
1164
1165        // PRQSs do not wait for document final approval to post GL entries; here we are forcing them to be APPROVED
1166        explicitEntry.setFinancialDocumentApprovedCode(OLEConstants.PENDING_ENTRY_APPROVED_STATUS_CODE.APPROVED);
1167    }
1168
1169    /**
1170     * Provides answers to the following splits: PurchaseWasReceived VendorIsEmployeeOrNonResidentAlien
1171     *
1172     * @see org.kuali.ole.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(String)
1173     */
1174    @Override
1175    public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
1176        if (nodeName.equals(PurapWorkflowConstants.REQUIRES_IMAGE_ATTACHMENT)) {
1177            return requiresAccountsPayableReviewRouting();
1178        }
1179        if (nodeName.equals(PurapWorkflowConstants.PURCHASE_WAS_RECEIVED)) {
1180            return shouldWaitForReceiving();
1181        }
1182        if (nodeName.equals(PurapWorkflowConstants.VENDOR_IS_EMPLOYEE_OR_NON_RESIDENT_ALIEN)) {
1183            return isVendorEmployeeOrNonResidentAlien();
1184        }
1185        throw new UnsupportedOperationException("Cannot answer split question for this node you call \"" + nodeName + "\"");
1186    }
1187
1188    protected boolean isVendorEmployeeOrNonResidentAlien() {
1189        String vendorHeaderGeneratedId = this.getVendorHeaderGeneratedIdentifier().toString();
1190        if (StringUtils.isBlank(vendorHeaderGeneratedId)) {
1191            // no vendor header id so can't check for proper tax routing
1192            return false;
1193        }
1194        VendorService vendorService = SpringContext.getBean(VendorService.class);
1195        boolean routeDocumentAsEmployeeVendor = vendorService.isVendorInstitutionEmployee(Integer.valueOf(vendorHeaderGeneratedId));
1196        boolean routeDocumentAsForeignVendor = vendorService.isVendorForeign(Integer.valueOf(vendorHeaderGeneratedId));
1197        if ((!routeDocumentAsEmployeeVendor) && (!routeDocumentAsForeignVendor)) {
1198            // no need to route
1199            return false;
1200        }
1201
1202        return true;
1203    }
1204
1205    /**
1206     * Payment Request needs to wait for receiving if the receiving requirements have NOT been met.
1207     *
1208     * @return
1209     */
1210    protected boolean shouldWaitForReceiving() {
1211        // only require if PO was marked to require receiving
1212        if (isReceivingDocumentRequiredIndicator()) {
1213            return !isReceivingRequirementMet();
1214        }
1215
1216        //receiving is not required or has already been fulfilled, no need to stop for routing
1217        return false;
1218    }
1219
1220    /**
1221     * Determine if the receiving requirement has been met for all items on the payment request. If any item does not have receiving
1222     * requirements met, return false. Receiving requirement has NOT been met if the quantity invoiced on the Payment Request is
1223     * greater than the quantity of "unpaid and received" items determined by (poQtyReceived - (poQtyInvoiced)).
1224     *
1225     * @return boolean return true if the receiving requirement has been met for all items on the payment request; false if
1226     *         requirement has not been met
1227     */
1228    public boolean isReceivingRequirementMet() {
1229
1230        for (Iterator iter = getItems().iterator(); iter.hasNext(); ) {
1231            InvoiceItem prqsItem = (InvoiceItem) iter.next();
1232
1233            if (prqsItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
1234                PurchaseOrderItem poItem = prqsItem.getPurchaseOrderItem();
1235                KualiDecimal prqsQuantityInvoiced = prqsItem.getItemQuantity() == null ? KualiDecimal.ZERO : prqsItem.getItemQuantity();
1236                KualiDecimal poQuantityReceived = poItem.getItemReceivedTotalQuantity() == null ? KualiDecimal.ZERO : poItem.getItemReceivedTotalQuantity();
1237                KualiDecimal poQuantityInvoiced = poItem.getItemInvoicedTotalQuantity() == null ? KualiDecimal.ZERO : poItem.getItemInvoicedTotalQuantity();
1238
1239                // receiving has NOT been met if prqsQtyInvoiced is greater than (poQtyReceived & (poQtyInvoiced & prqsQtyInvoiced))
1240                if (prqsQuantityInvoiced.compareTo(poQuantityReceived.subtract(poQuantityInvoiced)) > 0) {
1241                    return false;
1242                }
1243            }
1244        }
1245
1246        return true;
1247    }
1248
1249    @Override
1250    public Date getTransactionTaxDate() {
1251        return getInvoiceDate();
1252    }
1253
1254    public String getTaxClassificationCode() {
1255        return taxClassificationCode;
1256    }
1257
1258    public void setTaxClassificationCode(String taxClassificationCode) {
1259        this.taxClassificationCode = taxClassificationCode;
1260    }
1261
1262    public KualiDecimal getTaxFederalPercentShort() {
1263        return new KualiDecimal(taxFederalPercent);
1264    }
1265
1266    public BigDecimal getTaxFederalPercent() {
1267        return taxFederalPercent;
1268    }
1269
1270    public void setTaxFederalPercent(BigDecimal taxFederalPercent) {
1271        this.taxFederalPercent = taxFederalPercent;
1272    }
1273
1274    public KualiDecimal getTaxStatePercentShort() {
1275        return new KualiDecimal(taxStatePercent);
1276    }
1277
1278    public BigDecimal getTaxStatePercent() {
1279        return taxStatePercent;
1280    }
1281
1282    public void setTaxStatePercent(BigDecimal taxStatePercent) {
1283        this.taxStatePercent = taxStatePercent;
1284    }
1285
1286    public String getTaxCountryCode() {
1287        return taxCountryCode;
1288    }
1289
1290    public void setTaxCountryCode(String taxCountryCode) {
1291        this.taxCountryCode = taxCountryCode;
1292    }
1293
1294    public Boolean getTaxGrossUpIndicator() {
1295        return taxGrossUpIndicator;
1296    }
1297
1298    public void setTaxGrossUpIndicator(Boolean taxGrossUpIndicator) {
1299        this.taxGrossUpIndicator = taxGrossUpIndicator;
1300    }
1301
1302    public Boolean getTaxExemptTreatyIndicator() {
1303        return taxExemptTreatyIndicator;
1304    }
1305
1306    public void setTaxExemptTreatyIndicator(Boolean taxExemptTreatyIndicator) {
1307        this.taxExemptTreatyIndicator = taxExemptTreatyIndicator;
1308    }
1309
1310    public Boolean getTaxForeignSourceIndicator() {
1311        return taxForeignSourceIndicator;
1312    }
1313
1314    public void setTaxForeignSourceIndicator(Boolean taxForeignSourceIndicator) {
1315        this.taxForeignSourceIndicator = taxForeignSourceIndicator;
1316    }
1317
1318    public KualiDecimal getTaxSpecialW4Amount() {
1319        return taxSpecialW4Amount;
1320    }
1321
1322    public void setTaxSpecialW4Amount(KualiDecimal taxSpecialW4Amount) {
1323        this.taxSpecialW4Amount = taxSpecialW4Amount;
1324    }
1325
1326    public Boolean getTaxUSAIDPerDiemIndicator() {
1327        return taxUSAIDPerDiemIndicator;
1328    }
1329
1330    public void setTaxUSAIDPerDiemIndicator(Boolean taxUSAIDPerDiemIndicator) {
1331        this.taxUSAIDPerDiemIndicator = taxUSAIDPerDiemIndicator;
1332    }
1333
1334    public Boolean getTaxOtherExemptIndicator() {
1335        return taxOtherExemptIndicator;
1336    }
1337
1338    public void setTaxOtherExemptIndicator(Boolean taxOtherExemptIndicator) {
1339        this.taxOtherExemptIndicator = taxOtherExemptIndicator;
1340    }
1341
1342    public String getTaxNQIId() {
1343        return taxNQIId;
1344    }
1345
1346    public void setTaxNQIId(String taxNQIId) {
1347        this.taxNQIId = taxNQIId;
1348    }
1349
1350    public boolean isInvoiceCancelIndicatorForSearching() {
1351        return invoiceCancelIndicator;
1352    }
1353
1354    /**
1355     * @return the payment request positive approval indicator
1356     */
1357    public boolean getInvoicePositiveApprovalIndicatorForSearching() {
1358        return invoicePositiveApprovalIndicator;
1359    }
1360
1361    /**
1362     * @return the receiving document required indicator
1363     */
1364    public boolean getReceivingDocumentRequiredIndicatorForSearching() {
1365        return receivingDocumentRequiredIndicator;
1366    }
1367
1368
1369    public String getRequestCancelIndicatorForResult() {
1370        return isInvoiceCancelIndicator() ? "Yes" : "No";
1371    }
1372
1373    public String getPaidIndicatorForResult() {
1374        return getPaymentPaidTimestamp() != null ? "Yes" : "No";
1375    }
1376
1377    public Date getAccountsPayableApprovalDateForSearching() {
1378        if (this.getAccountsPayableApprovalTimestamp() == null) {
1379            return null;
1380        }
1381        try {
1382            Date date = SpringContext.getBean(DateTimeService.class).convertToSqlDate(this.getAccountsPayableApprovalTimestamp());
1383            if (LOG.isDebugEnabled()) {
1384                LOG.debug("getAccountsPayableApprovalDateForSearching() returns " + date);
1385            }
1386            return date;
1387        } catch (Exception e) {
1388            return new Date(this.getAccountsPayableApprovalTimestamp().getTime());
1389        }
1390    }
1391
1392    /**
1393     * Checks all documents notes for attachments.
1394     *
1395     * @return - true if document does not have an image attached, false otherwise
1396     */
1397    @Override
1398    public boolean documentHasNoImagesAttached() {
1399        List boNotes = this.getNotes();
1400        if (ObjectUtils.isNotNull(boNotes)) {
1401            for (Object obj : boNotes) {
1402                Note note = (Note) obj;
1403
1404                note.refreshReferenceObject("attachment");
1405                if (ObjectUtils.isNotNull(note.getAttachment()) && PurapConstants.AttachmentTypeCodes.ATTACHMENT_TYPE_INVOICE_IMAGE.equals(note.getAttachment().getAttachmentTypeCode())) {
1406                    return false;
1407                }
1408            }
1409        }
1410        return true;
1411    }
1412
1413    protected void closePurchaseOrder() {
1414        //Added for jira OLE-3529 Starts
1415        Integer poIdentifier = purchaseOrderDocument.getPurapDocumentIdentifier();
1416        String docNumber = purchaseOrderDocument.getDocumentNumber();
1417        Map purchaseOrderMap = new HashMap();
1418        purchaseOrderMap.put("documentNumber", docNumber);
1419        purchaseOrderMap.put("itemTypeCode", OLEConstants.ITEM);
1420        KualiDecimal itemQuantity = new KualiDecimal(0);
1421        KualiDecimal itemOrderQuantity = new KualiDecimal(0);
1422        List<OlePurchaseOrderItem> olePurchaseOrderItemList = (List<OlePurchaseOrderItem>) getBusinessObjectService().findMatching(OlePurchaseOrderItem.class, purchaseOrderMap);
1423        for (OlePurchaseOrderItem olePurchaseOrderItem : olePurchaseOrderItemList) {
1424            itemQuantity = itemQuantity.add(olePurchaseOrderItem.getItemQuantity());
1425        }
1426        Map lineItemReceivingMap = new HashMap();
1427        lineItemReceivingMap.put("purchaseOrderIdentifier", poIdentifier);
1428        List<OleLineItemReceivingDocument> oleLineItemReceivingDocumentList = (List<OleLineItemReceivingDocument>) getBusinessObjectService().findMatching(OleLineItemReceivingDocument.class, lineItemReceivingMap);
1429        for (OleLineItemReceivingDocument oleLineItemReceivingDocument : oleLineItemReceivingDocumentList) {
1430            String docId = oleLineItemReceivingDocument.getDocumentNumber();
1431            Map docIdMap = new HashMap();
1432            docIdMap.put("documentNumber", docId);
1433            List<OleLineItemReceivingItem> oleLineItemReceivingItemList = (List<OleLineItemReceivingItem>) getBusinessObjectService().findMatching(OleLineItemReceivingItem.class, docIdMap);
1434            for (OleLineItemReceivingItem oleLineItemReceivingItem : oleLineItemReceivingItemList) {
1435                itemOrderQuantity = itemOrderQuantity.add(oleLineItemReceivingItem.getItemOrderedQuantity());
1436            }
1437            if (itemQuantity.equals(itemOrderQuantity)) {
1438                try {
1439                    this.setDocumentHeader(purchaseOrderDocument.getDocumentHeader());
1440                    updateAndSaveAppDocStatus(PurapConstants.PurchaseOrderStatuses.APPDOC_CLOSED);
1441                } catch (WorkflowException e) {
1442                    logAndThrowRuntimeException("Error while Closing the PO from Payment Request "
1443                            + getDocumentNumber(), e);
1444                }
1445            }
1446        }
1447        //End
1448    }
1449
1450    /**
1451     * @see AccountsPayableDocument#getPurchaseOrderDocument()
1452     */
1453    @Override
1454    public PurchaseOrderDocument getPurchaseOrderDocument() {
1455        if ((ObjectUtils.isNull(purchaseOrderDocument) || ObjectUtils.isNull(purchaseOrderDocument.getPurapDocumentIdentifier())) && (ObjectUtils.isNotNull(getPurchaseOrderIdentifier()))) {
1456            Map map = new HashMap();
1457            map.put("purapDocumentIdentifier",this.getPurchaseOrderIdentifier());
1458            List<OlePurchaseOrderDocument> purchaseOrderDocumentList = (List<OlePurchaseOrderDocument>)getBusinessObjectService().findMatching(OlePurchaseOrderDocument.class,map);
1459            if(purchaseOrderDocumentList!=null && purchaseOrderDocumentList.size()>0){
1460                setPurchaseOrderDocument(purchaseOrderDocumentList.get(0));
1461            }
1462        }
1463        return purchaseOrderDocument;
1464    }
1465
1466    /**
1467     * @see AccountsPayableDocument#getPurchaseOrderDocument()
1468     */
1469
1470    public PurchaseOrderDocument getPurchaseOrderDocument(Integer poID) {
1471        if (ObjectUtils.isNull(purchaseOrderDocument) || ObjectUtils.isNull(purchaseOrderDocument.getPurapDocumentIdentifier())) {
1472            // && (ObjectUtils.isNotNull(getPurchaseOrderIdentifier()))) {
1473            Map map = new HashMap();
1474            map.put("purapDocumentIdentifier",poID);
1475            List<OlePurchaseOrderDocument> purchaseOrderDocumentList = (List<OlePurchaseOrderDocument>)getBusinessObjectService().findMatching(OlePurchaseOrderDocument.class,map);
1476            if(purchaseOrderDocumentList!=null && purchaseOrderDocumentList.size()>0){
1477                setPurchaseOrderDocument(purchaseOrderDocumentList.get(0));
1478            }
1479          //  setPurchaseOrderDocument(SpringContext.getBean(PurchaseOrderService.class).getCurrentPurchaseOrder(poID));
1480        }
1481        return purchaseOrderDocument;
1482    }
1483
1484
1485   /* private InvoiceService getInvoiceService() {
1486        if (invoiceService == null ) {
1487            invoiceService = SpringContext.getBean(OleInvoiceService.class);
1488        }
1489        return invoiceService;
1490    }
1491*/
1492
1493}