/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.ar.document; import java.sql.Date; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.coa.businessobject.Chart; import org.kuali.kfs.coa.businessobject.Organization; import org.kuali.kfs.integration.ar.AccountsReceivableCustomerAddress; import org.kuali.kfs.integration.ar.AccountsReceivableCustomerInvoice; import org.kuali.kfs.integration.ar.AccountsReceivableCustomerInvoiceRecurrenceDetails; import org.kuali.kfs.module.ar.ArKeyConstants; import org.kuali.kfs.module.ar.businessobject.AccountsReceivableDocumentHeader; import org.kuali.kfs.module.ar.businessobject.Customer; import org.kuali.kfs.module.ar.businessobject.CustomerAddress; import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail; import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceRecurrenceDetails; import org.kuali.kfs.module.ar.businessobject.CustomerProcessingType; import org.kuali.kfs.module.ar.businessobject.InvoiceRecurrence; import org.kuali.kfs.module.ar.businessobject.PrintInvoiceOptions; import org.kuali.kfs.module.ar.businessobject.ReceivableCustomerInvoiceDetail; import org.kuali.kfs.module.ar.businessobject.SalesTaxCustomerInvoiceDetail; import org.kuali.kfs.module.ar.document.service.AccountsReceivablePendingEntryService; import org.kuali.kfs.module.ar.document.service.AccountsReceivableTaxService; import org.kuali.kfs.module.ar.document.service.CustomerAddressService; import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDetailService; import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper; import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail; import org.kuali.kfs.sys.businessobject.TaxDetail; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.document.AccountingDocumentBase; import org.kuali.kfs.sys.document.AmountTotaling; import org.kuali.kfs.sys.document.Correctable; import org.kuali.kfs.sys.document.dataaccess.FinancialSystemDocumentHeaderDao; import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService; import org.kuali.kfs.sys.service.TaxService; import org.kuali.kfs.sys.util.KfsDateUtils; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange; import org.kuali.rice.kns.document.MaintenanceDocument; import org.kuali.rice.krad.UserSession; import org.kuali.rice.krad.bo.DocumentHeader; import org.kuali.rice.krad.document.Copyable; import org.kuali.rice.krad.service.DocumentService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; public class CustomerInvoiceDocument extends AccountingDocumentBase implements AmountTotaling, Copyable, Correctable, Comparable<CustomerInvoiceDocument>, AccountsReceivableCustomerInvoice { private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CustomerInvoiceDocument.class); protected static final String HAS_RECCURENCE_NODE = "HasReccurence"; protected static final String BATCH_GENERATED_NODE = "BatchGenerated"; protected String invoiceHeaderText; protected String invoiceAttentionLineText; protected Date invoiceDueDate; protected Date billingDate; protected Date closedDate; protected Date billingDateForDisplay; protected String invoiceTermsText; protected String organizationInvoiceNumber; protected String customerPurchaseOrderNumber; protected String printInvoiceIndicator; protected Date customerPurchaseOrderDate; protected String billByChartOfAccountCode; protected String billedByOrganizationCode; protected Integer customerShipToAddressIdentifier; protected Integer customerBillToAddressIdentifier; protected String customerSpecialProcessingCode; protected boolean customerRecordAttachmentIndicator; protected boolean openInvoiceIndicator; protected Date printDate; protected Integer age; protected String customerName; protected String billingAddressName; protected String billingCityName; protected String billingStateCode; protected String billingZipCode; protected String billingCountryCode; protected String billingAddressInternationalProvinceName; protected String billingInternationalMailCode; protected String billingEmailAddress; protected String billingAddressTypeCode; protected String billingLine1StreetAddress; protected String billingLine2StreetAddress; protected String shippingLine1StreetAddress; protected String shippingLine2StreetAddress; protected String shippingAddressName; protected String shippingCityName; protected String shippingStateCode; protected String shippingZipCode; protected String shippingCountryCode; protected String shippingAddressInternationalProvinceName; protected String shippingInternationalMailCode; protected String shippingEmailAddress; protected String shippingAddressTypeCode; protected boolean recurredInvoiceIndicator; protected Date reportedDate; protected AccountsReceivableDocumentHeader accountsReceivableDocumentHeader; protected Chart billByChartOfAccount; protected Organization billedByOrganization; protected CustomerProcessingType customerSpecialProcessing; protected PrintInvoiceOptions printInvoiceOption; protected CustomerAddress customerShipToAddress; protected CustomerAddress customerBillToAddress; protected CustomerInvoiceRecurrenceDetails customerInvoiceRecurrenceDetails; /** * Default constructor. */ public CustomerInvoiceDocument() { super(); } /** * This method calculates the outstanding balance on an invoice. * * @return the outstanding balance on this invoice */ @Override public KualiDecimal getOpenAmount() { return SpringContext.getBean(CustomerInvoiceDocumentService.class).getOpenAmountForCustomerInvoiceDocument(this); } /** * Gets the documentNumber attribute. * * @return Returns the documentNumber */ @Override public String getDocumentNumber() { return documentNumber; } /** * Sets the documentNumber attribute. * * @param documentNumber The documentNumber to set. */ @Override public void setDocumentNumber(String documentNumber) { this.documentNumber = documentNumber; } /** * Gets the invoiceHeaderText attribute. * * @return Returns the invoiceHeaderText */ public String getInvoiceHeaderText() { return invoiceHeaderText; } /** * Sets the invoiceHeaderText attribute. * * @param invoiceHeaderText The invoiceHeaderText to set. */ public void setInvoiceHeaderText(String invoiceHeaderText) { this.invoiceHeaderText = invoiceHeaderText; } /** * Gets the invoiceAttentionLineText attribute. * * @return Returns the invoiceAttentionLineText */ @Override public String getInvoiceAttentionLineText() { return invoiceAttentionLineText; } /** * Sets the invoiceAttentionLineText attribute. * * @param invoiceAttentionLineText The invoiceAttentionLineText to set. */ public void setInvoiceAttentionLineText(String invoiceAttentionLineText) { this.invoiceAttentionLineText = invoiceAttentionLineText; } /** * Gets the invoiceDueDate attribute. * * @return Returns the invoiceDueDate */ @Override public Date getInvoiceDueDate() { return invoiceDueDate; } /** * Sets the invoiceDueDate attribute. * * @param invoiceDueDate The invoiceDueDate to set. */ @Override public void setInvoiceDueDate(Date invoiceDueDate) { this.invoiceDueDate = invoiceDueDate; } /** * Gets the billingDate attribute. * * @return Returns the billingDate */ @Override public Date getBillingDate() { return billingDate; } /** * This method returns the age of an invoice (i.e. current date - billing date) * * @return */ @Override public Integer getAge() { if (ObjectUtils.isNotNull(billingDate)) { return (int) KfsDateUtils.getDifferenceInDays(new Timestamp(billingDate.getTime()), SpringContext.getBean(DateTimeService.class).getCurrentTimestamp()); } // TODO should I be throwing an exception or throwing a null? return null; } public void setAge(Integer age) { this.age = age; } /** * Sets the billingDate attribute. * * @param billingDate The billingDate to set. */ @Override public void setBillingDate(Date billingDate) { this.billingDate = billingDate; } /** * Gets the invoiceTermsText attribute. * * @return Returns the invoiceTermsText */ @Override public String getInvoiceTermsText() { return invoiceTermsText; } /** * Sets the invoiceTermsText attribute. * * @param invoiceTermsText The invoiceTermsText to set. */ @Override public void setInvoiceTermsText(String invoiceTermsText) { this.invoiceTermsText = invoiceTermsText; } /** * Gets the organizationInvoiceNumber attribute. * * @return Returns the organizationInvoiceNumber */ public String getOrganizationInvoiceNumber() { return organizationInvoiceNumber; } /** * Sets the organizationInvoiceNumber attribute. * * @param organizationInvoiceNumber The organizationInvoiceNumber to set. */ @Override public void setOrganizationInvoiceNumber(String organizationInvoiceNumber) { this.organizationInvoiceNumber = organizationInvoiceNumber; } /** * Gets the customerPurchaseOrderNumber attribute. * * @return Returns the customerPurchaseOrderNumber */ public String getCustomerPurchaseOrderNumber() { return customerPurchaseOrderNumber; } /** * Sets the customerPurchaseOrderNumber attribute. * * @param customerPurchaseOrderNumber The customerPurchaseOrderNumber to set. */ public void setCustomerPurchaseOrderNumber(String customerPurchaseOrderNumber) { this.customerPurchaseOrderNumber = customerPurchaseOrderNumber; } /** * Gets the printInvoiceIndicator attribute. * * @return Returns the printInvoiceIndicator. */ public String getPrintInvoiceIndicator() { return printInvoiceIndicator; } /** * Sets the printInvoiceIndicator attribute value. * * @param printInvoiceIndicator The printInvoiceIndicator to set. */ @Override public void setPrintInvoiceIndicator(String printInvoiceIndicator) { this.printInvoiceIndicator = printInvoiceIndicator; } /** * Gets the customerPurchaseOrderDate attribute. * * @return Returns the customerPurchaseOrderDate */ public Date getCustomerPurchaseOrderDate() { return customerPurchaseOrderDate; } /** * Sets the customerPurchaseOrderDate attribute. * * @param customerPurchaseOrderDate The customerPurchaseOrderDate to set. */ public void setCustomerPurchaseOrderDate(Date customerPurchaseOrderDate) { this.customerPurchaseOrderDate = customerPurchaseOrderDate; } /** * Gets the billByChartOfAccountCode attribute. * * @return Returns the billByChartOfAccountCode */ @Override public String getBillByChartOfAccountCode() { return billByChartOfAccountCode; } /** * Sets the billByChartOfAccountCode attribute. * * @param billByChartOfAccountCode The billByChartOfAccountCode to set. */ @Override public void setBillByChartOfAccountCode(String billByChartOfAccountCode) { this.billByChartOfAccountCode = billByChartOfAccountCode; } /** * Gets the billedByOrganizationCode attribute. * * @return Returns the billedByOrganizationCode */ @Override public String getBilledByOrganizationCode() { return billedByOrganizationCode; } /** * Sets the billedByOrganizationCode attribute. * * @param billedByOrganizationCode The billedByOrganizationCode to set. */ @Override public void setBilledByOrganizationCode(String billedByOrganizationCode) { this.billedByOrganizationCode = billedByOrganizationCode; } /** * Gets the customerShipToAddressIdentifier attribute. * * @return Returns the customerShipToAddressIdentifier */ public Integer getCustomerShipToAddressIdentifier() { return customerShipToAddressIdentifier; } /** * Sets the customerShipToAddressIdentifier attribute. * * @param customerShipToAddressIdentifier The customerShipToAddressIdentifier to set. */ public void setCustomerShipToAddressIdentifier(Integer customerShipToAddressIdentifier) { this.customerShipToAddressIdentifier = customerShipToAddressIdentifier; } /** * Gets the customerBillToAddressIdentifier attribute. * * @return Returns the customerBillToAddressIdentifier */ public Integer getCustomerBillToAddressIdentifier() { return customerBillToAddressIdentifier; } /** * Sets the customerBillToAddressIdentifier attribute. * * @param customerBillToAddressIdentifier The customerBillToAddressIdentifier to set. */ @Override public void setCustomerBillToAddressIdentifier(Integer customerBillToAddressIdentifier) { this.customerBillToAddressIdentifier = customerBillToAddressIdentifier; } /** * Gets the customerSpecialProcessingCode attribute. * * @return Returns the customerSpecialProcessingCode */ public String getCustomerSpecialProcessingCode() { return customerSpecialProcessingCode; } /** * Sets the customerSpecialProcessingCode attribute. * * @param customerSpecialProcessingCode The customerSpecialProcessingCode to set. */ public void setCustomerSpecialProcessingCode(String customerSpecialProcessingCode) { this.customerSpecialProcessingCode = customerSpecialProcessingCode; } /** * Gets the customerRecordAttachmentIndicator attribute. * * @return Returns the customerRecordAttachmentIndicator */ public boolean isCustomerRecordAttachmentIndicator() { return customerRecordAttachmentIndicator; } /** * Sets the customerRecordAttachmentIndicator attribute. * * @param customerRecordAttachmentIndicator The customerRecordAttachmentIndicator to set. */ public void setCustomerRecordAttachmentIndicator(boolean customerRecordAttachmentIndicator) { this.customerRecordAttachmentIndicator = customerRecordAttachmentIndicator; } /** * Gets the openInvoiceIndicator attribute. * * @return Returns the openInvoiceIndicator */ @Override public boolean isOpenInvoiceIndicator() { return openInvoiceIndicator; } /** * Sets the openInvoiceIndicator attribute. * * @param openInvoiceIndicator The openInvoiceIndicator to set. */ @Override public void setOpenInvoiceIndicator(boolean openInvoiceIndicator) { this.openInvoiceIndicator = openInvoiceIndicator; } /** * Gets the printDate attribute. * * @return Returns the printDate */ public Date getPrintDate() { return printDate; } /** * Sets the printDate attribute. * * @param printDate The printDate to set. */ public void setPrintDate(Date printDate) { this.printDate = printDate; } /** * Gets the accountsReceivableDocumentHeader attribute. * * @return Returns the accountsReceivableDocumentHeader */ @Override public AccountsReceivableDocumentHeader getAccountsReceivableDocumentHeader() { return accountsReceivableDocumentHeader; } /** * Sets the accountsReceivableDocumentHeader attribute. * * @param accountsReceivableDocumentHeader The accountsReceivableDocumentHeader to set. */ public void setAccountsReceivableDocumentHeader(AccountsReceivableDocumentHeader accountsReceivableDocumentHeader) { this.accountsReceivableDocumentHeader = accountsReceivableDocumentHeader; } /** * * This method... * @return */ public String getParentInvoiceNumber() { return getAccountsReceivableDocumentHeader().getDocumentHeader().getDocumentTemplateNumber(); } /** * Gets the billByChartOfAccount attribute. * * @return Returns the billByChartOfAccount */ public Chart getBillByChartOfAccount() { return billByChartOfAccount; } /** * Sets the billByChartOfAccount attribute. * * @param billByChartOfAccount The billByChartOfAccount to set. * @deprecated */ @Deprecated public void setBillByChartOfAccount(Chart billByChartOfAccount) { this.billByChartOfAccount = billByChartOfAccount; } /** * Gets the billedByOrganization attribute. * * @return Returns the billedByOrganization */ public Organization getBilledByOrganization() { return billedByOrganization; } /** * Sets the billedByOrganization attribute. * * @param billedByOrganization The billedByOrganization to set. * @deprecated */ @Deprecated public void setBilledByOrganization(Organization billedByOrganization) { this.billedByOrganization = billedByOrganization; } /** * Gets the customerSpecialProcessing attribute. * * @return Returns the customerSpecialProcessing */ public CustomerProcessingType getCustomerSpecialProcessing() { return customerSpecialProcessing; } /** * Sets the customerSpecialProcessing attribute. * * @param customerSpecialProcessing The customerSpecialProcessing to set. * @deprecated */ @Deprecated public void setCustomerSpecialProcessing(CustomerProcessingType customerSpecialProcessing) { this.customerSpecialProcessing = customerSpecialProcessing; } /** * This method returns the billing date for display. If billing date hasn't been set yet, just display current date * * @return */ public Date getBillingDateForDisplay() { if (ObjectUtils.isNotNull(getBillingDate())) { return getBillingDate(); } else { return SpringContext.getBean(DateTimeService.class).getCurrentSqlDate(); } } /** * This method... * * @param date */ public void setBillingDateForDisplay(Date date) { // do nothing } public Date getClosedDate() { return closedDate; } public void setClosedDate(Date closedDate) { this.closedDate = closedDate; } /** * @see org.kuali.rice.krad.bo.BusinessObjectBase#toStringMapper() */ @SuppressWarnings("unchecked") protected LinkedHashMap toStringMapper_RICE20_REFACTORME() { LinkedHashMap m = new LinkedHashMap(); m.put("documentNumber", this.documentNumber); return m; } /** * This method returns true if this document has been corrected * * @return */ public boolean hasInvoiceBeenCorrected() { DocumentHeader documentHeader = SpringContext.getBean(FinancialSystemDocumentHeaderDao.class).getCorrectingDocumentHeader(documentNumber); if (ObjectUtils.isNotNull(documentHeader) && StringUtils.isNotBlank(documentHeader.getDocumentNumber())) { return true; } return false; } /** * This method returns true if this document is a reversal for another document * * @return */ public boolean isInvoiceReversal() { return ObjectUtils.isNotNull(getFinancialSystemDocumentHeader().getFinancialDocumentInErrorNumber()); } /** * @see org.kuali.kfs.sys.document.AccountingDocumentBase#isDebit(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail) */ @Override public boolean isDebit(GeneralLedgerPendingEntrySourceDetail postable) { return ((CustomerInvoiceDetail) postable).isDebit(); } /** * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getSourceAccountingLineClass() */ @Override public Class<CustomerInvoiceDetail> getSourceAccountingLineClass() { return CustomerInvoiceDetail.class; } /** * Ensures that all the accounts receivable object codes are correctly updated */ public void updateAccountReceivableObjectCodes() { for (Iterator e = getSourceAccountingLines().iterator(); e.hasNext();) { SpringContext.getBean(CustomerInvoiceDetailService.class).updateAccountsReceivableObjectCode(((CustomerInvoiceDetail) e.next())); } } /** * This method creates the following GLPE's for the invoice 1. Debit to receivable for total line amount ( including sales tax * if it exists ). 2. Credit to income based on item price * quantity. 3. Credit to state sales tax account/object code if state * sales tax exists. 4. Credit to district sales tax account/object code if district sales tax exists. * * @see org.kuali.kfs.service.impl.GenericGeneralLedgerPendingEntryGenerationProcessImpl#processGenerateGeneralLedgerPendingEntries(org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource, * org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail, * org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper) */ @Override public boolean generateGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, GeneralLedgerPendingEntrySequenceHelper sequenceHelper) { addReceivableGLPEs(sequenceHelper, glpeSourceDetail); sequenceHelper.increment(); addIncomeGLPEs(sequenceHelper, glpeSourceDetail); // if sales tax is enabled generate GLPEs if (SpringContext.getBean(AccountsReceivableTaxService.class).isCustomerInvoiceDetailTaxable(this, (CustomerInvoiceDetail) glpeSourceDetail)) { addSalesTaxGLPEs(sequenceHelper, glpeSourceDetail); } return true; } /** * This method creates the receivable GLPEs for each invoice detail line. * * @param poster * @param sequenceHelper * @param postable * @param explicitEntry */ protected void addReceivableGLPEs(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntrySourceDetail glpeSourceDetail) { CustomerInvoiceDetail customerInvoiceDetail = (CustomerInvoiceDetail) glpeSourceDetail; ReceivableCustomerInvoiceDetail receivableCustomerInvoiceDetail = new ReceivableCustomerInvoiceDetail(customerInvoiceDetail, this); AccountsReceivablePendingEntryService service = SpringContext.getBean(AccountsReceivablePendingEntryService.class); service.createAndAddGenericInvoiceRelatedGLPEs(this, receivableCustomerInvoiceDetail, sequenceHelper, isInvoiceDetailReceivableDebit(customerInvoiceDetail), false, customerInvoiceDetail.getInvoiceItemPreTaxAmount()); } /** * Determines if the given customer invoice detail should be a debit on the receivable glpe, or a credit * @param customerInvoiceDetail the customer invoice detail to determine debitness of * @return true if the detail represents a debit, false if it represents a credit */ protected boolean isInvoiceDetailReceivableDebit(CustomerInvoiceDetail customerInvoiceDetail) { final boolean isDebit = (!isInvoiceReversal() && !customerInvoiceDetail.isDiscountLine()) || (isInvoiceReversal() && customerInvoiceDetail.isDiscountLine()); return isDebit; } /** * This method adds pending entry with transaction ledger entry amount set to item price * quantity * * @param poster * @param sequenceHelper * @param postable * @param explicitEntry */ protected void addIncomeGLPEs(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntrySourceDetail glpeSourceDetail) { CustomerInvoiceDetail customerInvoiceDetail = (CustomerInvoiceDetail) glpeSourceDetail; AccountsReceivablePendingEntryService service = SpringContext.getBean(AccountsReceivablePendingEntryService.class); service.createAndAddGenericInvoiceRelatedGLPEs(this, customerInvoiceDetail, sequenceHelper, isInvoiceDetailIncomeDebit(customerInvoiceDetail), false, customerInvoiceDetail.getInvoiceItemPreTaxAmount()); } /** * Determines if the given customer invoice detail should be a debit on the income glpe, or a credit * @param customerInvoiceDetail the customer invoice detail to determine debitness of * @return true if the detail represents a debit, false if it represents a credit */ protected boolean isInvoiceDetailIncomeDebit(CustomerInvoiceDetail customerInvoiceDetail) { final boolean isDebit = (!isInvoiceReversal() && customerInvoiceDetail.isDiscountLine()) || (isInvoiceReversal() && !customerInvoiceDetail.isDiscountLine()); return isDebit; } /** * This method add pending entries for every tax detail that exists for a particular postal code * * @param sequenceHelper * @param glpeSourceDetail * @param hasClaimOnCashOffset */ protected void addSalesTaxGLPEs(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntrySourceDetail glpeSourceDetail) { CustomerInvoiceDetail customerInvoiceDetail = (CustomerInvoiceDetail) glpeSourceDetail; boolean isDebit = (!isInvoiceReversal() && customerInvoiceDetail.isDiscountLine()) || (isInvoiceReversal() && !customerInvoiceDetail.isDiscountLine()); String postalCode = SpringContext.getBean(AccountsReceivableTaxService.class).getPostalCodeForTaxation(this); Date dateOfTransaction = SpringContext.getBean(DateTimeService.class).getCurrentSqlDate(); List<TaxDetail> salesTaxDetails = SpringContext.getBean(TaxService.class).getSalesTaxDetails(dateOfTransaction, postalCode, customerInvoiceDetail.getInvoiceItemPreTaxAmount()); AccountsReceivablePendingEntryService service = SpringContext.getBean(AccountsReceivablePendingEntryService.class); SalesTaxCustomerInvoiceDetail salesTaxCustomerInvoiceDetail; ReceivableCustomerInvoiceDetail receivableCustomerInvoiceDetail; for (TaxDetail salesTaxDetail : salesTaxDetails) { salesTaxCustomerInvoiceDetail = new SalesTaxCustomerInvoiceDetail(salesTaxDetail, customerInvoiceDetail); receivableCustomerInvoiceDetail = new ReceivableCustomerInvoiceDetail(salesTaxCustomerInvoiceDetail, this); sequenceHelper.increment(); service.createAndAddGenericInvoiceRelatedGLPEs(this, receivableCustomerInvoiceDetail, sequenceHelper, !isDebit, false, salesTaxDetail.getTaxAmount()); sequenceHelper.increment(); service.createAndAddGenericInvoiceRelatedGLPEs(this, salesTaxCustomerInvoiceDetail, sequenceHelper, isDebit, false, salesTaxDetail.getTaxAmount()); } } /** * Returns an implementation of the GeneralLedgerPendingEntryService * * @return an implementation of the GeneralLedgerPendingEntryService */ public GeneralLedgerPendingEntryService getGeneralLedgerPendingEntryService() { return SpringContext.getBean(GeneralLedgerPendingEntryService.class); } @Override public List<String> getWorkflowEngineDocumentIdsToLock() { // add the invoice number of the Error Corrected doc, if this is an error correction if (this.isInvoiceReversal()) { if (StringUtils.isNotBlank(getFinancialSystemDocumentHeader().getFinancialDocumentInErrorNumber())) { List<String> documentIds = new ArrayList<String>(); documentIds.add(getFinancialSystemDocumentHeader().getFinancialDocumentInErrorNumber()); return documentIds; } } return null; } /** * When document is processed do the following: 1) Set the billingDate to today's date if not already set 2) If there are * discounts, create corresponding invoice paid applied rows 3) If the document is a reversal, in addition to reversing paid * applied rows, update the open paid applied indicator * * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocumentBase#doRouteStatusChange() */ @Override public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) { super.doRouteStatusChange(statusChangeEvent); // fast-exit if status != P if (!getDocumentHeader().getWorkflowDocument().isProcessed()) { return; } // wire up the billing date if (ObjectUtils.isNull(getBillingDate())) { setBillingDate(SpringContext.getBean(DateTimeService.class).getCurrentSqlDateMidnight()); } // apply discounts CustomerInvoiceDocumentService invoiceService = SpringContext.getBean(CustomerInvoiceDocumentService.class); invoiceService.convertDiscountsToPaidApplieds(this); // handle a Correction/Reversal document if (this.isInvoiceReversal()) { CustomerInvoiceDocument correctedCustomerInvoiceDocument; try { correctedCustomerInvoiceDocument = (CustomerInvoiceDocument) SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(this.getFinancialSystemDocumentHeader().getFinancialDocumentInErrorNumber()); } catch (WorkflowException e) { throw new RuntimeException("Cannot find customer invoice document with id " + this.getFinancialSystemDocumentHeader().getFinancialDocumentInErrorNumber()); } // if reversal, close both this reversal invoice and the original invoice SpringContext.getBean(CustomerInvoiceDocumentService.class).closeCustomerInvoiceDocument(correctedCustomerInvoiceDocument); SpringContext.getBean(CustomerInvoiceDocumentService.class).closeCustomerInvoiceDocument(this); } // handle Recurrence if (ObjectUtils.isNull(this.getCustomerInvoiceRecurrenceDetails()) || (ObjectUtils.isNull(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceBeginDate()) && ObjectUtils.isNull(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceEndDate()) && ObjectUtils.isNull(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceIntervalCode()) && ObjectUtils.isNull(this.getCustomerInvoiceRecurrenceDetails().getDocumentTotalRecurrenceNumber()) && ObjectUtils.isNull(this.getCustomerInvoiceRecurrenceDetails().getDocumentInitiatorUserIdentifier()))) { } else { // set new user session to recurrence initiator UserSession currentSession = GlobalVariables.getUserSession(); GlobalVariables.setUserSession(new UserSession(KFSConstants.SYSTEM_USER)); // populate InvoiceRecurrence business object InvoiceRecurrence newInvoiceRecurrence = new InvoiceRecurrence(); newInvoiceRecurrence.setInvoiceNumber(this.getCustomerInvoiceRecurrenceDetails().getInvoiceNumber()); newInvoiceRecurrence.setCustomerNumber(this.getCustomerInvoiceRecurrenceDetails().getCustomerNumber()); newInvoiceRecurrence.setDocumentRecurrenceBeginDate(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceBeginDate()); newInvoiceRecurrence.setDocumentRecurrenceEndDate(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceEndDate()); newInvoiceRecurrence.setDocumentRecurrenceIntervalCode(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceIntervalCode()); newInvoiceRecurrence.setDocumentTotalRecurrenceNumber(this.getCustomerInvoiceRecurrenceDetails().getDocumentTotalRecurrenceNumber()); newInvoiceRecurrence.setDocumentInitiatorUserIdentifier(this.getCustomerInvoiceRecurrenceDetails().getDocumentInitiatorUserIdentifier()); newInvoiceRecurrence.setActive(this.getCustomerInvoiceRecurrenceDetails().isActive()); // create a new InvoiceRecurrenceMaintenanceDocument MaintenanceDocument invoiceRecurrenceMaintDoc = null; try { invoiceRecurrenceMaintDoc = (MaintenanceDocument) SpringContext.getBean(DocumentService.class).getNewDocument(getInvoiceRecurrenceMaintenanceDocumentTypeName()); } catch (WorkflowException e1) { throw new RuntimeException("Cannot create new Invoice Recurrence Maintenance Document."); } invoiceRecurrenceMaintDoc.getDocumentHeader().setDocumentDescription("Automatically created from Invoice"); invoiceRecurrenceMaintDoc.getNewMaintainableObject().setBusinessObject(newInvoiceRecurrence); try { // blanket approve the INVR, bypassing everything //invoiceRecurrenceMaintDoc.getDocumentHeader().getWorkflowDocument().blanketApprove("Blanket Approved by the creating Invoice Document #" + getDocumentNumber()); //TODO temporarily just do regular route until we can get blanket approve perms setup for KFS SpringContext.getBean(DocumentService.class).saveDocument(invoiceRecurrenceMaintDoc); invoiceRecurrenceMaintDoc.getDocumentHeader().getWorkflowDocument().route("Automatically created and routed by CustomerInvoiceDocument #" + getDocumentNumber() + "."); } catch (WorkflowException e) { throw new RuntimeException("Cannot route Invoice Recurrence Maintenance Document with id " + invoiceRecurrenceMaintDoc.getDocumentNumber() + "."); } // return the session to the original initiator GlobalVariables.setUserSession(currentSession); } } protected String getInvoiceRecurrenceMaintenanceDocumentTypeName() { return "INVR"; } /** * If this invoice is a reversal, set the open indicator to false * * @see org.kuali.kfs.sys.document.FinancialSystemTransactionalDocumentBase#prepareForSave() */ @Override public void prepareForSave() { if (this.isInvoiceReversal()) { setOpenInvoiceIndicator(false); } // make sure the docHeader gets its doc total right. This is here because there's an ordering // bug in the struts classes for invoice that is preventing this from being set right. There is // probably a better way to fix this that can be pursued later. getFinancialSystemDocumentHeader().setFinancialDocumentTotalAmount(getTotalDollarAmount()); captureWorkflowHeaderInformation(); // invoice recurrence stuff, if there is a recurrence object if (ObjectUtils.isNotNull(this.getCustomerInvoiceRecurrenceDetails()) && getProcessRecurrenceFlag()) { // wire up the recurrence customer number if one exists if (ObjectUtils.isNull(this.getCustomerInvoiceRecurrenceDetails().getCustomerNumber())) { this.getCustomerInvoiceRecurrenceDetails().setCustomerNumber(this.getAccountsReceivableDocumentHeader().getCustomerNumber()); } customerInvoiceRecurrenceDetails.setInvoiceNumber(getDocumentNumber()); // calc recurrence number if only end-date specified if (ObjectUtils.isNull(this.getCustomerInvoiceRecurrenceDetails().getDocumentTotalRecurrenceNumber()) && ObjectUtils.isNotNull(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceEndDate())) { Calendar beginCalendar = Calendar.getInstance(); beginCalendar.setTime(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceBeginDate()); Date beginDate = this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceBeginDate(); Calendar endCalendar = Calendar.getInstance(); endCalendar.setTime(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceEndDate()); Date endDate = this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceEndDate(); Calendar nextCalendar = Calendar.getInstance(); Date nextDate = beginDate; int totalRecurrences = 0; int addCounter = 0; String intervalCode = this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceIntervalCode(); if (intervalCode.equals("M")) { addCounter = 1; } if (intervalCode.equals("Q")) { addCounter = 3; } /* perform this loop while begin_date is less than or equal to end_date */ while (!(beginDate.after(endDate))) { beginCalendar.setTime(beginDate); beginCalendar.add(Calendar.MONTH, addCounter); beginDate = KfsDateUtils.convertToSqlDate(beginCalendar.getTime()); totalRecurrences++; nextDate = beginDate; nextCalendar.setTime(nextDate); nextCalendar.add(Calendar.MONTH, addCounter); nextDate = KfsDateUtils.convertToSqlDate(nextCalendar.getTime()); if (endDate.after(beginDate) && endDate.before(nextDate)) { totalRecurrences++; break; } } if (totalRecurrences > 0) { this.getCustomerInvoiceRecurrenceDetails().setDocumentTotalRecurrenceNumber(totalRecurrences); } } // calc end-date if only recurrence-number is specified if (ObjectUtils.isNotNull(this.getCustomerInvoiceRecurrenceDetails().getDocumentTotalRecurrenceNumber()) && ObjectUtils.isNull(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceEndDate())) { Calendar beginCalendar = Calendar.getInstance(); beginCalendar.setTime(new Timestamp(this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceBeginDate().getTime())); Calendar endCalendar = Calendar.getInstance(); endCalendar = beginCalendar; int addCounter = 0; Integer documentTotalRecurrenceNumber = this.getCustomerInvoiceRecurrenceDetails().getDocumentTotalRecurrenceNumber(); String intervalCode = this.getCustomerInvoiceRecurrenceDetails().getDocumentRecurrenceIntervalCode(); if (intervalCode.equals("M")) { addCounter = -1; addCounter += documentTotalRecurrenceNumber * 1; } if (intervalCode.equals("Q")) { addCounter = -3; addCounter += documentTotalRecurrenceNumber * 3; } endCalendar.add(Calendar.MONTH, addCounter); this.getCustomerInvoiceRecurrenceDetails().setDocumentRecurrenceEndDate(KfsDateUtils.convertToSqlDate(endCalendar.getTime())); } } // Force upper case //TODO Force to upper case here since DD forceUpperCase doesn't work. Revert this temp fix after Rice fix. setBilledByOrganizationCode(StringUtils.upperCase(billedByOrganizationCode)); accountsReceivableDocumentHeader.setProcessingOrganizationCode(StringUtils.upperCase(accountsReceivableDocumentHeader.getProcessingOrganizationCode())); accountsReceivableDocumentHeader.setCustomerNumber(StringUtils.upperCase(accountsReceivableDocumentHeader.getCustomerNumber())); if (ObjectUtils.isNull(getCustomerShipToAddressIdentifier())) { setCustomerShipToAddress(null); setCustomerShipToAddressOnInvoice(null); } } // returns true only when there is all the required recurrence info public boolean getProcessRecurrenceFlag() { CustomerInvoiceRecurrenceDetails rec = this.getCustomerInvoiceRecurrenceDetails(); boolean processRecurrenceFlag = (null != rec.getDocumentRecurrenceIntervalCode()); processRecurrenceFlag &= (null != rec.getDocumentRecurrenceBeginDate()); processRecurrenceFlag &= ( (null != rec.getDocumentRecurrenceEndDate()) || (null != rec.getDocumentTotalRecurrenceNumber())); processRecurrenceFlag &= (rec.isActive()); processRecurrenceFlag &= (null != rec.getDocumentInitiatorUserIdentifier()); return processRecurrenceFlag; } // returns true only if there is no recurrence data at all in recurrence tab public boolean getNoRecurrenceDataFlag() { CustomerInvoiceRecurrenceDetails rec = this.getCustomerInvoiceRecurrenceDetails(); boolean noRecurrenceDataFlag = ObjectUtils.isNull(rec.getDocumentRecurrenceIntervalCode()); noRecurrenceDataFlag &= ObjectUtils.isNull(rec.getDocumentRecurrenceBeginDate()); noRecurrenceDataFlag &= ObjectUtils.isNull(rec.getDocumentRecurrenceEndDate()); noRecurrenceDataFlag &= !rec.isActive(); noRecurrenceDataFlag &= ObjectUtils.isNull(rec.getDocumentTotalRecurrenceNumber()); noRecurrenceDataFlag &= ObjectUtils.isNull(rec.getDocumentInitiatorUserIdentifier()); return noRecurrenceDataFlag; } /** * @see org.kuali.kfs.sys.document.AccountingDocumentBase#toCopy() */ @Override public void toCopy() throws WorkflowException { super.toCopy(); CustomerInvoiceDocumentService customerInvoiceDocumentService = SpringContext.getBean(CustomerInvoiceDocumentService.class); customerInvoiceDocumentService.setupDefaultValuesForCopiedCustomerInvoiceDocument(this); this.getFinancialSystemDocumentHeader().setFinancialDocumentTotalAmount(getTotalDollarAmount()); } /** * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocumentBase#toErrorCorrection() */ @Override public void toErrorCorrection() throws WorkflowException { super.toErrorCorrection(); negateCustomerInvoiceDetailUnitPrices(); this.setOpenInvoiceIndicator(false); this.getFinancialSystemDocumentHeader().setFinancialDocumentTotalAmount(getTotalDollarAmount()); // if we dont force this on the error correction, the recurrence will // have the old doc number, and will revert the main doc due to OJB fun, // which will cause PK unique index failure. if (ObjectUtils.isNotNull(customerInvoiceRecurrenceDetails)) { customerInvoiceRecurrenceDetails.setInvoiceNumber(this.documentNumber); } } /** * This method... */ @SuppressWarnings("unchecked") public void negateCustomerInvoiceDetailUnitPrices() { CustomerInvoiceDetail customerInvoiceDetail; for (Iterator i = getSourceAccountingLines().iterator(); i.hasNext();) { customerInvoiceDetail = (CustomerInvoiceDetail) i.next(); customerInvoiceDetail.setInvoiceItemUnitPrice(customerInvoiceDetail.getInvoiceItemUnitPrice().negate()); //clear the old CustomerInvoiceDocument customerInvoiceDetail.setCustomerInvoiceDocument(null); // revert changes for custom invoice error correction //SpringContext.getBean(CustomerInvoiceDetailService.class).prepareCustomerInvoiceDetailForErrorCorrection(customerInvoiceDetail, this); } } /** * This method returns true if invoice document has at least one discount line * * @return */ @SuppressWarnings("unchecked") public boolean hasAtLeastOneDiscount() { CustomerInvoiceDetail customerInvoiceDetail; for (Iterator i = getSourceAccountingLines().iterator(); i.hasNext();) { customerInvoiceDetail = (CustomerInvoiceDetail) i.next(); if (customerInvoiceDetail.isDiscountLineParent()) { return true; } } return false; } /** * This method returns true if line number is discount line number based on sequence number * * @param sequenceNumber * @return */ @SuppressWarnings("unchecked") public boolean isDiscountLineBasedOnSequenceNumber(Integer sequenceNumber) { if (ObjectUtils.isNull(sequenceNumber)) { return false; } CustomerInvoiceDetail customerInvoiceDetail; for (Iterator i = getSourceAccountingLines().iterator(); i.hasNext();) { customerInvoiceDetail = (CustomerInvoiceDetail) i.next(); Integer discLineNum = customerInvoiceDetail.getInvoiceItemDiscountLineNumber(); // check if sequence number is referenced as a discount line for another customer invoice detail (i.e. the parent line) if (ObjectUtils.isNotNull(discLineNum) && sequenceNumber.equals(customerInvoiceDetail.getInvoiceItemDiscountLineNumber())) { return true; } } return false; } /** * This method returns parent customer invoice detail based on child discount sequence number * * @param sequenceNumber * @return */ @SuppressWarnings("unchecked") public CustomerInvoiceDetail getParentLineBasedOnDiscountSequenceNumber(Integer discountSequenceNumber) { if (ObjectUtils.isNull(discountSequenceNumber)) { return null; } CustomerInvoiceDetail customerInvoiceDetail; for (Iterator i = getSourceAccountingLines().iterator(); i.hasNext();) { customerInvoiceDetail = (CustomerInvoiceDetail) i.next(); Integer discLineNum = customerInvoiceDetail.getInvoiceItemDiscountLineNumber(); if (ObjectUtils.isNotNull(discLineNum) && discountSequenceNumber.equals(customerInvoiceDetail.getInvoiceItemDiscountLineNumber())) { return customerInvoiceDetail; } } return null; } /** * This method is called on CustomerInvoiceDocumentAction.execute() to set isDiscount to true if it truly is a discount line */ @SuppressWarnings("unchecked") public void updateDiscountAndParentLineReferences() { CustomerInvoiceDetail discount; for (Iterator i = getSourceAccountingLines().iterator(); i.hasNext();) { discount = (CustomerInvoiceDetail) i.next(); // get sequence number and check if theres a corresponding parent line for that discount line CustomerInvoiceDetail parent = getParentLineBasedOnDiscountSequenceNumber(discount.getSequenceNumber()); if (ObjectUtils.isNotNull(parent)) { discount.setParentDiscountCustomerInvoiceDetail(parent); parent.setDiscountCustomerInvoiceDetail(discount); } else { discount.setParentDiscountCustomerInvoiceDetail(null); } } } /** * This method removes the corresponding discount line based on the index of the parent line index. This assumes that the * discount line is ALWAYS after the index of the parent line. * * @param deleteIndex */ public void removeDiscountLineBasedOnParentLineIndex(int parentLineIndex) { // get parent line line CustomerInvoiceDetail parentLine = (CustomerInvoiceDetail) getSourceAccountingLines().get(parentLineIndex); // get index for discount line int discountLineIndex = -1; // this should ALWAYS get set for (int i = 0; i < getSourceAccountingLines().size(); i++) { if (parentLine.getInvoiceItemDiscountLineNumber().equals(((CustomerInvoiceDetail) getSourceAccountingLines().get(i)).getSequenceNumber())) { discountLineIndex = i; } } // remove discount line getSourceAccountingLines().remove(discountLineIndex); } public CustomerInvoiceRecurrenceDetails getCustomerInvoiceRecurrenceDetails() { return customerInvoiceRecurrenceDetails; } public void setCustomerInvoiceRecurrenceDetails(CustomerInvoiceRecurrenceDetails customerInvoiceRecurrenceDetails) { this.customerInvoiceRecurrenceDetails = customerInvoiceRecurrenceDetails; } public CustomerAddress getCustomerShipToAddress() { return customerShipToAddress; } public void setCustomerShipToAddress(CustomerAddress customerShipToAddress) { this.customerShipToAddress = customerShipToAddress; } public CustomerAddress getCustomerBillToAddress() { return customerBillToAddress; } public void setCustomerBillToAddress(CustomerAddress customerBillToAddress) { this.customerBillToAddress = customerBillToAddress; } public PrintInvoiceOptions getPrintInvoiceOption() { if (ObjectUtils.isNull(printInvoiceOption) && StringUtils.isNotEmpty(printInvoiceIndicator)){ refreshReferenceObject("printInvoiceOption"); } return printInvoiceOption; } public void setPrintInvoiceOption(PrintInvoiceOptions printInvoiceOption) { this.printInvoiceOption = printInvoiceOption; } /** * This method returns the total of all pre tax amounts for all customer invoice detail lines * * @return */ public KualiDecimal getInvoiceItemPreTaxAmountTotal() { KualiDecimal invoiceItemPreTaxAmountTotal = new KualiDecimal(0); for (Iterator i = getSourceAccountingLines().iterator(); i.hasNext();) { invoiceItemPreTaxAmountTotal = invoiceItemPreTaxAmountTotal.add(((CustomerInvoiceDetail) i.next()).getInvoiceItemPreTaxAmount()); } return invoiceItemPreTaxAmountTotal; } /** * This method returns the total of all tax amounts for all customer invoice detail lines * * @return */ public KualiDecimal getInvoiceItemTaxAmountTotal() { KualiDecimal invoiceItemTaxAmountTotal = new KualiDecimal(0); for (Iterator i = getSourceAccountingLines().iterator(); i.hasNext();) { invoiceItemTaxAmountTotal = invoiceItemTaxAmountTotal.add(((CustomerInvoiceDetail) i.next()).getInvoiceItemTaxAmount()); } return invoiceItemTaxAmountTotal; } /** * This method returns the primary customer address for the customer number provided. * * @return */ public CustomerAddress getPrimaryAddressForCustomerNumber() { if (ObjectUtils.isNotNull(accountsReceivableDocumentHeader) && StringUtils.isNotEmpty(accountsReceivableDocumentHeader.getCustomerNumber())) { return SpringContext.getBean(CustomerAddressService.class).getPrimaryAddress(accountsReceivableDocumentHeader.getCustomerNumber()); } return null; } /** * This method returns the customer object for the invoice * * @return */ public Customer getCustomer() { if (ObjectUtils.isNotNull(accountsReceivableDocumentHeader)) { return accountsReceivableDocumentHeader.getCustomer(); } return null; } /** * This method will return all the customer invoice details excluding discount invoice detail lines. * * @return */ public List<CustomerInvoiceDetail> getCustomerInvoiceDetailsWithoutDiscounts() { List<CustomerInvoiceDetail> customerInvoiceDetailsWithoutDiscounts = new ArrayList<CustomerInvoiceDetail>(); updateDiscountAndParentLineReferences(); List<CustomerInvoiceDetail> customerInvoiceDetailsWithDiscounts = getSourceAccountingLines(); for (CustomerInvoiceDetail customerInvoiceDetail : customerInvoiceDetailsWithDiscounts) { if (!customerInvoiceDetail.isDiscountLine()) { customerInvoiceDetail.setDocumentNumber(getDocumentNumber()); customerInvoiceDetailsWithoutDiscounts.add(customerInvoiceDetail); } } return customerInvoiceDetailsWithoutDiscounts; } //TODO Andrew // /** // * This method could be a bit dangerous. It's meant to be used only on the payment application document, where the modified // * invoice is never saved. // * // * @param customerInvoiceDetails // */ // public void setCustomerInvoiceDetailsWithoutDiscounts(List<CustomerInvoiceDetail> customerInvoiceDetails) { // List<CustomerInvoiceDetail> customerInvoiceDetailsWithoutDiscounts = getSourceAccountingLines(); // int sequenceCounter = 0; // for (CustomerInvoiceDetail customerInvoiceDetail : customerInvoiceDetailsWithoutDiscounts) { // for (CustomerInvoiceDetail revisedCustomerInvoiceDetail : customerInvoiceDetails) { // if (!customerInvoiceDetail.isDiscountLine() && customerInvoiceDetail.getSequenceNumber().equals(revisedCustomerInvoiceDetail.getSequenceNumber())) { // customerInvoiceDetailsWithoutDiscounts.remove(sequenceCounter); // customerInvoiceDetailsWithoutDiscounts.add(sequenceCounter, revisedCustomerInvoiceDetail); // } // } // sequenceCounter += 1; // } // setSourceAccountingLines(customerInvoiceDetailsWithoutDiscounts); // } /** * This method will return all the customer invoice details that are discounts * * @return */ public List<CustomerInvoiceDetail> getDiscounts() { List<CustomerInvoiceDetail> discounts = new ArrayList<CustomerInvoiceDetail>(); updateDiscountAndParentLineReferences(); List<CustomerInvoiceDetail> customerInvoiceDetailsWithDiscounts = getSourceAccountingLines(); for (CustomerInvoiceDetail customerInvoiceDetail : customerInvoiceDetailsWithDiscounts) { if (customerInvoiceDetail.isDiscountLine()) { customerInvoiceDetail.setDocumentNumber(getDocumentNumber()); discounts.add(customerInvoiceDetail); } } return discounts; } @Override public int compareTo(CustomerInvoiceDocument customerInvoiceDocument) { if (this.getBillByChartOfAccountCode().equals(customerInvoiceDocument.getBillByChartOfAccountCode())) { if (this.getBilledByOrganizationCode().equals(customerInvoiceDocument.getBilledByOrganizationCode())) { return 0; } } return -1; } /** * * Returns whether or not the Invoice would be paid off by applying the additional amount, passed in * by the parameter. * * @param additionalAmountToApply The additional applied amount to test against. * @return True if applying the additionalAmountToApply parameter amount would bring the OpenAmount to zero. */ public boolean wouldPayOff(KualiDecimal additionalAmountToApply) { KualiDecimal openAmount = getOpenAmount(); return KualiDecimal.ZERO.isGreaterEqual(openAmount.subtract(additionalAmountToApply)); } @Override public KualiDecimal getTotalDollarAmount() { return getSourceTotal(); } public String getBillingAddressInternationalProvinceName() { return billingAddressInternationalProvinceName; } @Override public void setBillingAddressInternationalProvinceName(String billingAddressInternationalProvinceName) { this.billingAddressInternationalProvinceName = billingAddressInternationalProvinceName; } public String getBillingAddressName() { return billingAddressName; } @Override public void setBillingAddressName(String billingAddressName) { this.billingAddressName = billingAddressName; } public String getBillingAddressTypeCode() { return billingAddressTypeCode; } public void setBillingAddressTypeCode(String billingAddressTypeCode) { this.billingAddressTypeCode = billingAddressTypeCode; } public String getBillingCityName() { return billingCityName; } @Override public void setBillingCityName(String billingCityName) { this.billingCityName = billingCityName; } public String getBillingCountryCode() { return billingCountryCode; } @Override public void setBillingCountryCode(String billingCountryCode) { this.billingCountryCode = billingCountryCode; } public String getBillingEmailAddress() { return billingEmailAddress; } @Override public void setBillingEmailAddress(String billingEmailAddress) { this.billingEmailAddress = billingEmailAddress; } public String getBillingInternationalMailCode() { return billingInternationalMailCode; } @Override public void setBillingInternationalMailCode(String billingInternationalMailCode) { this.billingInternationalMailCode = billingInternationalMailCode; } public String getBillingStateCode() { return billingStateCode; } @Override public void setBillingStateCode(String billingStateCode) { this.billingStateCode = billingStateCode; } public String getBillingZipCode() { return billingZipCode; } @Override public void setBillingZipCode(String billingZipCode) { this.billingZipCode = billingZipCode; } @Override public String getCustomerName() { return customerName; } public void setCustomerName(String customerName) { this.customerName = customerName; } public String getShippingAddressInternationalProvinceName() { return shippingAddressInternationalProvinceName; } public void setShippingAddressInternationalProvinceName(String shippingAddressInternationalProvinceName) { this.shippingAddressInternationalProvinceName = shippingAddressInternationalProvinceName; } public String getShippingAddressName() { return shippingAddressName; } public void setShippingAddressName(String shippingAddressName) { this.shippingAddressName = shippingAddressName; } public String getShippingAddressTypeCode() { return shippingAddressTypeCode; } public void setShippingAddressTypeCode(String shippingAddressTypeCode) { this.shippingAddressTypeCode = shippingAddressTypeCode; } public String getShippingCityName() { return shippingCityName; } public void setShippingCityName(String shippingCityName) { this.shippingCityName = shippingCityName; } public String getShippingCountryCode() { return shippingCountryCode; } public void setShippingCountryCode(String shippingCountryCode) { this.shippingCountryCode = shippingCountryCode; } public String getShippingEmailAddress() { return shippingEmailAddress; } public void setShippingEmailAddress(String shippingEmailAddress) { this.shippingEmailAddress = shippingEmailAddress; } public String getShippingInternationalMailCode() { return shippingInternationalMailCode; } public void setShippingInternationalMailCode(String shippingInternationalMailCode) { this.shippingInternationalMailCode = shippingInternationalMailCode; } public String getShippingStateCode() { return shippingStateCode; } public void setShippingStateCode(String shippingStateCode) { this.shippingStateCode = shippingStateCode; } public String getShippingZipCode() { return shippingZipCode; } public void setShippingZipCode(String shippingZipCode) { this.shippingZipCode = shippingZipCode; } public String getBillingLine1StreetAddress() { return billingLine1StreetAddress; } @Override public void setBillingLine1StreetAddress(String billingLine1StreetAddress) { this.billingLine1StreetAddress = billingLine1StreetAddress; } public String getBillingLine2StreetAddress() { return billingLine2StreetAddress; } @Override public void setBillingLine2StreetAddress(String billingLine2StreetAddress) { this.billingLine2StreetAddress = billingLine2StreetAddress; } public String getShippingLine1StreetAddress() { return shippingLine1StreetAddress; } public void setShippingLine1StreetAddress(String shippingLine1StreetAddress) { this.shippingLine1StreetAddress = shippingLine1StreetAddress; } public String getShippingLine2StreetAddress() { return shippingLine2StreetAddress; } public void setShippingLine2StreetAddress(String shippingLine2StreetAddress) { this.shippingLine2StreetAddress = shippingLine2StreetAddress; } public boolean getRecurredInvoiceIndicator() { return recurredInvoiceIndicator; } public void setRecurredInvoiceIndicator(boolean recurredInvoiceIndicator) { this.recurredInvoiceIndicator = recurredInvoiceIndicator; } public Date getReportedDate() { return reportedDate; } public void setReportedDate(Date reportedDate) { this.reportedDate = reportedDate; } /** * Get a string representation for billing chart/organization * * @return */ public String getBilledByChartOfAccCodeAndOrgCode() { String returnVal = getBillByChartOfAccountCode() + "/" + getBilledByOrganizationCode(); return returnVal; } /** * Populate Customer Billing Address fields on Customer Invoice. * * @return */ public void setCustomerBillToAddressOnInvoice(CustomerAddress customerBillToAddress) { accountsReceivableDocumentHeader.refreshReferenceObject("customer"); if (ObjectUtils.isNotNull(accountsReceivableDocumentHeader.getCustomer())) { this.setCustomerName(accountsReceivableDocumentHeader.getCustomer().getCustomerName()); } if (ObjectUtils.isNotNull(customerBillToAddress)) { this.setBillingAddressTypeCode(customerBillToAddress.getCustomerAddressTypeCode()); this.setBillingAddressName(customerBillToAddress.getCustomerAddressName()); this.setBillingLine1StreetAddress(customerBillToAddress.getCustomerLine1StreetAddress()); this.setBillingLine2StreetAddress(customerBillToAddress.getCustomerLine2StreetAddress()); this.setBillingCityName(customerBillToAddress.getCustomerCityName()); this.setBillingStateCode(customerBillToAddress.getCustomerStateCode()); this.setBillingZipCode(customerBillToAddress.getCustomerZipCode()); this.setBillingCountryCode(customerBillToAddress.getCustomerCountryCode()); this.setBillingAddressInternationalProvinceName(customerBillToAddress.getCustomerAddressInternationalProvinceName()); this.setBillingInternationalMailCode(customerBillToAddress.getCustomerInternationalMailCode()); this.setBillingEmailAddress(customerBillToAddress.getCustomerEmailAddress()); } } /** * Populate Customer Shipping Address fields on Customer Invoice. * * @return */ public void setCustomerShipToAddressOnInvoice(CustomerAddress customerShipToAddress) { accountsReceivableDocumentHeader.refreshReferenceObject("customer"); Customer customer = accountsReceivableDocumentHeader.getCustomer(); if (ObjectUtils.isNotNull(customer)) { this.setCustomerName(customer.getCustomerName()); } if (ObjectUtils.isNotNull(customerShipToAddress)) { this.setShippingAddressTypeCode(customerShipToAddress.getCustomerAddressTypeCode()); this.setShippingAddressName(customerShipToAddress.getCustomerAddressName()); this.setShippingLine1StreetAddress(customerShipToAddress.getCustomerLine1StreetAddress()); this.setShippingLine2StreetAddress(customerShipToAddress.getCustomerLine2StreetAddress()); this.setShippingCityName(customerShipToAddress.getCustomerCityName()); this.setShippingStateCode(customerShipToAddress.getCustomerStateCode()); this.setShippingZipCode(customerShipToAddress.getCustomerZipCode()); this.setShippingCountryCode(customerShipToAddress.getCustomerCountryCode()); this.setShippingAddressInternationalProvinceName(customerShipToAddress.getCustomerAddressInternationalProvinceName()); this.setShippingInternationalMailCode(customerShipToAddress.getCustomerInternationalMailCode()); this.setShippingEmailAddress(customerShipToAddress.getCustomerEmailAddress()); } else { this.setShippingAddressTypeCode(null); this.setShippingAddressName(null); this.setShippingLine1StreetAddress(null); this.setShippingLine2StreetAddress(null); this.setShippingCityName(null); this.setShippingStateCode(null); this.setShippingZipCode(null); this.setShippingCountryCode(null); this.setShippingAddressInternationalProvinceName(null); this.setShippingInternationalMailCode(null); this.setShippingEmailAddress(null); } } /** * Gets the quickApply attribute. * * @return Returns the quickApply. */ //TODO Andrew - this is payapp specific stuff and needs to go // public boolean isQuickApply() { // return quickApply; // } // // //TODO Andrew - this is payapp specific stuff and needs to go // public boolean getQuickApply() { // return isQuickApply(); // } // // /** // * Sets the quickApply attribute value. // * // * @param quickApply The quickApply to set. // */ // //TODO Andrew - this is payapp specific stuff and needs to go // public void setQuickApply(boolean quickApply) { // this.quickApply = quickApply; // } /** * Answers true when invoice recurrence details are provided by the user * * @see org.kuali.kfs.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String) */ @Override public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException { if (HAS_RECCURENCE_NODE.equals(nodeName)) { return hasRecurrence(); } if (BATCH_GENERATED_NODE.equals(nodeName)) { return isBatchGenerated(); } throw new UnsupportedOperationException("answerSplitNode('" + nodeName + "') was called but no handler for nodeName specified."); } /** * * Determines whether this document was generated from a recurrence batch. Returns true if so, false if not. * @return */ protected boolean isBatchGenerated() { return recurredInvoiceIndicator; } /** * * Determines whether this document has a Recurrence filled out enough to create an INVR doc. * @return */ protected boolean hasRecurrence() { return (ObjectUtils.isNotNull(getCustomerInvoiceRecurrenceDetails()) && getCustomerInvoiceRecurrenceDetails().isActive()); } @Override public void setCustomerBillToAddress(AccountsReceivableCustomerAddress customerBillToAddress) { this.customerBillToAddress = (CustomerAddress) customerBillToAddress; } @Override public void setBillingAddressTypeCodeAsPrimary() { setBillingAddressTypeCode(ArKeyConstants.CustomerConstants.CUSTOMER_ADDRESS_TYPE_CODE_PRIMARY); } @Override public void setCustomerInvoiceRecurrenceDetails(AccountsReceivableCustomerInvoiceRecurrenceDetails customerInvoiceRecurrenceDetails) { this.customerInvoiceRecurrenceDetails = (CustomerInvoiceRecurrenceDetails) customerInvoiceRecurrenceDetails; } @Override public void setAccountsReceivableDocumentHeader(org.kuali.kfs.integration.ar.AccountsReceivableDocumentHeader accountsReceivableDocumentHeader) { this.accountsReceivableDocumentHeader = (org.kuali.kfs.module.ar.businessobject.AccountsReceivableDocumentHeader)accountsReceivableDocumentHeader; } private Timestamp agingReportSentTime; /** * Gets the agingReportSentTime attribute. * @return Returns the agingReportSentTime. */ public Timestamp getAgingReportSentTime() { return agingReportSentTime; } /** * Sets the agingReportSentTime attribute value. * @param agingReportSentTime The agingReportSentTime to set. */ public void setAgingReportSentTime(Timestamp agingReportSentTime) { this.agingReportSentTime = agingReportSentTime; } }