/* * 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.math.BigDecimal; import java.sql.Date; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.integration.ar.AccountsReceivableCustomerCreditMemo; import org.kuali.kfs.module.ar.ArConstants; import org.kuali.kfs.module.ar.businessobject.AccountsReceivableDocumentHeader; import org.kuali.kfs.module.ar.businessobject.CustomerCreditMemoDetail; import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail; import org.kuali.kfs.module.ar.businessobject.ReceivableCustomerCreditMemoDetail; import org.kuali.kfs.module.ar.businessobject.ReceivableCustomerInvoiceDetail; import org.kuali.kfs.module.ar.businessobject.SalesTaxCustomerCreditMemoDetail; import org.kuali.kfs.module.ar.document.service.AccountsReceivableDocumentHeaderService; 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.CustomerCreditMemoDocumentService; import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDetailService; import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry; 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.AmountTotaling; import org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource; import org.kuali.kfs.sys.document.GeneralLedgerPostingDocumentBase; import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService; import org.kuali.kfs.sys.service.TaxService; import org.kuali.kfs.sys.service.UniversityDateService; 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.core.web.format.CurrencyFormatter; import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange; import org.kuali.rice.kns.service.DataDictionaryService; import org.kuali.rice.krad.exception.ValidationException; import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent; import org.kuali.rice.krad.util.ObjectUtils; public class CustomerCreditMemoDocument extends GeneralLedgerPostingDocumentBase implements GeneralLedgerPendingEntrySource, AmountTotaling, AccountsReceivableCustomerCreditMemo { protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CustomerCreditMemoDocument.class); protected String statusCode; protected String financialDocumentReferenceInvoiceNumber; protected KualiDecimal crmTotalItemAmount = KualiDecimal.ZERO; protected KualiDecimal crmTotalTaxAmount = KualiDecimal.ZERO; protected KualiDecimal crmTotalAmount = KualiDecimal.ZERO; protected Integer invOutstandingDays; protected CustomerInvoiceDocument invoice; protected AccountsReceivableDocumentHeader accountsReceivableDocumentHeader; protected List<CustomerCreditMemoDetail> creditMemoDetails; protected transient TaxService taxService; protected transient AccountsReceivableTaxService arTaxService; public CustomerCreditMemoDocument() { super(); setPostingYear(SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear()); creditMemoDetails = new ArrayList<CustomerCreditMemoDetail>(); setGeneralLedgerPendingEntries(new ArrayList<GeneralLedgerPendingEntry>()); } /** * Gets the creditMemoDetails attribute. * @return Returns the creditMemoDetails. */ public List<CustomerCreditMemoDetail> getCreditMemoDetails() { return creditMemoDetails; } /** * Sets the creditMemoDetails attribute value. * @param creditMemoDetails The creditMemoDetails to set. */ public void setCreditMemoDetails(List<CustomerCreditMemoDetail> creditMemoDetails) { this.creditMemoDetails = creditMemoDetails; } /** * Gets the financialDocumentReferenceInvoiceNumber attribute. * @return Returns the financialDocumentReferenceInvoiceNumber. */ public String getFinancialDocumentReferenceInvoiceNumber() { return financialDocumentReferenceInvoiceNumber; } /** * Sets the financialDocumentReferenceInvoiceNumber attribute value. * @param financialDocumentReferenceInvoiceNumber The financialDocumentReferenceInvoiceNumber to set. */ public void setFinancialDocumentReferenceInvoiceNumber(String financialDocumentReferenceInvoiceNumber) { if (financialDocumentReferenceInvoiceNumber != null) { financialDocumentReferenceInvoiceNumber = financialDocumentReferenceInvoiceNumber.toUpperCase(); } this.financialDocumentReferenceInvoiceNumber = financialDocumentReferenceInvoiceNumber; } /** * Gets the invoice attribute. * @return Returns the invoice. */ public CustomerInvoiceDocument getInvoice() { if (ObjectUtils.isNull(invoice) && StringUtils.isNotEmpty(financialDocumentReferenceInvoiceNumber)){ refreshReferenceObject("invoice"); } return invoice; } /** * Sets the invoice attribute value. * @param invoice The invoice to set. */ public void setInvoice(CustomerInvoiceDocument invoice) { this.invoice = invoice; } /** * Gets the statusCode attribute. * @return Returns the statusCode. */ public String getStatusCode() { return statusCode; } /** * Sets the statusCode attribute value. * @param statusCode The statusCode to set. */ public void setStatusCode(String statusCode) { this.statusCode = statusCode; } /** * Initializes the values for a new document. */ public void initiateDocument() { LOG.debug("initiateDocument() started"); setStatusCode(ArConstants.CustomerCreditMemoStatuses.INITIATE); } /** * Clear out the initially populated fields. */ public void clearInitFields() { LOG.debug("clearDocument() started"); // Clearing document Init fields setFinancialDocumentReferenceInvoiceNumber(null); } /** * Gets the crmTotalAmount attribute. * @return Returns the crmTotalAmount. */ public KualiDecimal getCrmTotalAmount() { return crmTotalAmount; } /** * This method returns the crmTotalAmount as a currency formatted string. * @return String */ public String getCurrencyFormattedCrmTotalAmount() { return (String) new CurrencyFormatter().format(crmTotalAmount); } /** * Sets the crmTotalAmount attribute value. * @param crmTotalAmount The crmTotalAmount to set. */ public void setCrmTotalAmount(KualiDecimal crmTotalAmount) { this.crmTotalAmount = crmTotalAmount; } /** * Gets the crmTotalItemAmount attribute. * @return Returns the crmTotalItemAmount. */ public KualiDecimal getCrmTotalItemAmount() { return crmTotalItemAmount; } /** * This method returns the crmTotalItemAmount as a currency formatted string. * @return String */ public String getCurrencyFormattedCrmTotalItemAmount() { return (String) new CurrencyFormatter().format(crmTotalItemAmount); } /** * Sets the crmTotalItemAmount attribute value. * @param crmTotalItemAmount The crmTotalItemAmount to set. */ public void setCrmTotalItemAmount(KualiDecimal crmTotalItemAmount) { this.crmTotalItemAmount = crmTotalItemAmount; } /** * Gets the crmTotalTaxAmount attribute. * @return Returns the crmTotalTaxAmount. */ public KualiDecimal getCrmTotalTaxAmount() { return crmTotalTaxAmount; } /** * This method returns the crmTotalTaxAmount as a currency formatted string. * @return String */ public String getCurrencyFormattedCrmTotalTaxAmount() { return (String) new CurrencyFormatter().format(crmTotalTaxAmount); } /** * Sets the crmTotalTaxAmount attribute value. * @param crmTotalTaxAmount The crmTotalTaxAmount to set. */ public void setCrmTotalTaxAmount(KualiDecimal crmTotalTaxAmount) { this.crmTotalTaxAmount = crmTotalTaxAmount; } /** * Gets the invOutstandingDays attribute. * @return Returns the invOutstandingDays. */ public Integer getInvOutstandingDays() { Timestamp invBillingDateTimestamp = new Timestamp(invoice.getBillingDate().getTime()); Timestamp todayDateTimestamp = new Timestamp(SpringContext.getBean(DateTimeService.class).getCurrentSqlDate().getTime()); double diffInDays = KfsDateUtils.getDifferenceInDays(invBillingDateTimestamp, todayDateTimestamp); invOutstandingDays = new Integer(new KualiDecimal(diffInDays).intValue()); return invOutstandingDays; } /** * Sets the invOutstandingDays attribute value. * @param invOutstandingDays The invOutstandingDays to set. */ public void setInvOutstandingDays(Integer invOutstandingDays) { this.invOutstandingDays = invOutstandingDays; } public void recalculateTotalsBasedOnChangedItemAmount(CustomerCreditMemoDetail customerCreditMemoDetail) { KualiDecimal duplicateCreditMemoItemTotalAmount = customerCreditMemoDetail.getDuplicateCreditMemoItemTotalAmount(); KualiDecimal creditMemoItemTotalAmount = customerCreditMemoDetail.getCreditMemoItemTotalAmount(); // substract the 'old' item amount, tax amount, and total amount accordingly from totals if (ObjectUtils.isNotNull(duplicateCreditMemoItemTotalAmount)) { prepareTotalsForUpdate(duplicateCreditMemoItemTotalAmount,getArTaxService().isCustomerInvoiceDetailTaxable(getInvoice(), customerCreditMemoDetail.getCustomerInvoiceDetail())); } recalculateTotals(creditMemoItemTotalAmount,getArTaxService().isCustomerInvoiceDetailTaxable(getInvoice(), customerCreditMemoDetail.getCustomerInvoiceDetail())); // update duplicate credit memo item amount with 'new' value customerCreditMemoDetail.setDuplicateCreditMemoItemTotalAmount(creditMemoItemTotalAmount); } public void recalculateTotals(CustomerCreditMemoDetail customerCreditMemoDetail) { KualiDecimal duplicateCreditMemoItemTotalAmount = customerCreditMemoDetail.getDuplicateCreditMemoItemTotalAmount(); // substract the 'old' item amount, tax amount, and total amount accordingly from totals if (ObjectUtils.isNotNull(duplicateCreditMemoItemTotalAmount)) { prepareTotalsForUpdate(duplicateCreditMemoItemTotalAmount,getArTaxService().isCustomerInvoiceDetailTaxable(getInvoice(), customerCreditMemoDetail.getCustomerInvoiceDetail())); customerCreditMemoDetail.setDuplicateCreditMemoItemTotalAmount(null); } } protected void prepareTotalsForUpdate(KualiDecimal oldItemAmount, boolean isTaxableItemFlag) { KualiDecimal oldItemTaxAmount = KualiDecimal.ZERO; if (isTaxableItemFlag) { oldItemTaxAmount = getTaxService().getTotalSalesTaxAmount(invoice.getBillingDate(), getPostalCode(), oldItemAmount); } crmTotalItemAmount = crmTotalItemAmount.subtract(oldItemAmount); crmTotalTaxAmount = crmTotalTaxAmount.subtract(oldItemTaxAmount); crmTotalAmount = crmTotalAmount.subtract(oldItemAmount.add(oldItemTaxAmount)); } public void resetTotals() { crmTotalItemAmount = KualiDecimal.ZERO; crmTotalTaxAmount = KualiDecimal.ZERO; crmTotalAmount = KualiDecimal.ZERO; } public void recalculateTotals(KualiDecimal itemAmount, boolean isTaxableItemFlag) { crmTotalItemAmount = crmTotalItemAmount.add(itemAmount); if (isTaxableItemFlag) { crmTotalTaxAmount = crmTotalTaxAmount.add(getTaxService().getTotalSalesTaxAmount(invoice.getBillingDate(), getPostalCode(), itemAmount)); } crmTotalAmount = crmTotalItemAmount.add(crmTotalTaxAmount); getFinancialSystemDocumentHeader().setFinancialDocumentTotalAmount(crmTotalAmount); } /* * populate customer credit memo details based on the invoice info */ public void populateCustomerCreditMemoDetails() { CustomerCreditMemoDetail customerCreditMemoDetail; KualiDecimal invItemTaxAmount, openInvoiceAmount; CustomerInvoiceDetailService customerInvoiceDetailService = SpringContext.getBean(CustomerInvoiceDetailService.class); setStatusCode(ArConstants.CustomerCreditMemoStatuses.IN_PROCESS); //set accounts receivable document header if not already set if (getAccountsReceivableDocumentHeader() == null){ AccountsReceivableDocumentHeader accountsReceivableDocumentHeader = SpringContext.getBean(AccountsReceivableDocumentHeaderService.class).getNewAccountsReceivableDocumentHeaderForCurrentUser(); accountsReceivableDocumentHeader.setDocumentNumber(getDocumentNumber()); accountsReceivableDocumentHeader.setCustomerNumber(invoice.getAccountsReceivableDocumentHeader().getCustomerNumber()); setAccountsReceivableDocumentHeader(accountsReceivableDocumentHeader); } List<CustomerInvoiceDetail> customerInvoiceDetails = invoice.getCustomerInvoiceDetailsWithoutDiscounts(); for (CustomerInvoiceDetail customerInvoiceDetail : customerInvoiceDetails) { customerCreditMemoDetail = new CustomerCreditMemoDetail(); if(ObjectUtils.isNull(customerInvoiceDetail.getInvoiceItemTaxAmount())){ customerInvoiceDetail.setInvoiceItemTaxAmount(KualiDecimal.ZERO); } customerCreditMemoDetail.setInvoiceLineTotalAmount(customerInvoiceDetail.getInvoiceItemTaxAmount(), customerInvoiceDetail.getInvoiceItemPreTaxAmount()); customerCreditMemoDetail.setReferenceInvoiceItemNumber(customerInvoiceDetail.getSequenceNumber()); openInvoiceAmount = customerInvoiceDetail.getAmountOpen(); customerCreditMemoDetail.setInvoiceOpenItemAmount(openInvoiceAmount); customerCreditMemoDetail.setInvoiceOpenItemQuantity(getInvoiceOpenItemQuantity(customerCreditMemoDetail, customerInvoiceDetail)); customerCreditMemoDetail.setDocumentNumber(this.documentNumber); customerCreditMemoDetail.setFinancialDocumentReferenceInvoiceNumber(this.financialDocumentReferenceInvoiceNumber); // this is a hookup for institution custom to update financial object code for prior year(s) invoice //customerInvoiceDetailService.updateFinancialObjectCode(customerCreditMemoDetail); creditMemoDetails.add(customerCreditMemoDetail); } } /** * This method populates credit memo details that aren't saved in database */ public void populateCustomerCreditMemoDetailsAfterLoad() { KualiDecimal openInvoiceAmount, invItemTaxAmount, creditMemoItemAmount, creditMemoTaxAmount, taxRate; CustomerInvoiceDetailService customerInvoiceDetailService = SpringContext.getBean(CustomerInvoiceDetailService.class); List<CustomerInvoiceDetail> customerInvoiceDetails = getInvoice().getCustomerInvoiceDetailsWithoutDiscounts(); for (CustomerCreditMemoDetail creditMemoDetail : creditMemoDetails) { creditMemoDetail.setFinancialDocumentReferenceInvoiceNumber(this.financialDocumentReferenceInvoiceNumber); CustomerInvoiceDetail customerInvoiceDetail = creditMemoDetail.getCustomerInvoiceDetail(); openInvoiceAmount = customerInvoiceDetail.getAmountOpen(); creditMemoDetail.setInvoiceOpenItemAmount(openInvoiceAmount); creditMemoDetail.setInvoiceOpenItemQuantity(getInvoiceOpenItemQuantity(creditMemoDetail, customerInvoiceDetail)); if(ObjectUtils.isNull(customerInvoiceDetail.getInvoiceItemTaxAmount())){ customerInvoiceDetail.setInvoiceItemTaxAmount(KualiDecimal.ZERO); } creditMemoDetail.setInvoiceLineTotalAmount(customerInvoiceDetail.getInvoiceItemTaxAmount(), customerInvoiceDetail.getInvoiceItemPreTaxAmount()); creditMemoItemAmount = creditMemoDetail.getCreditMemoItemTotalAmount(); creditMemoDetail.setDuplicateCreditMemoItemTotalAmount(creditMemoItemAmount); if (ObjectUtils.isNotNull(creditMemoItemAmount)) { if( getArTaxService().isCustomerInvoiceDetailTaxable(invoice, customerInvoiceDetail) ) { creditMemoTaxAmount = getTaxService().getTotalSalesTaxAmount(invoice.getBillingDate(), getPostalCode(), creditMemoItemAmount); } else { creditMemoTaxAmount = KualiDecimal.ZERO; } creditMemoDetail.setCreditMemoItemTaxAmount(creditMemoTaxAmount); creditMemoDetail.setCreditMemoLineTotalAmount(creditMemoItemAmount.add(creditMemoTaxAmount)); crmTotalItemAmount = crmTotalItemAmount.add(creditMemoItemAmount); crmTotalTaxAmount = crmTotalTaxAmount.add(creditMemoTaxAmount); crmTotalAmount = crmTotalAmount.add(creditMemoItemAmount.add(creditMemoTaxAmount)); } // this is a hookup for institution custom to update financial object code for prior year(s) invoice //customerInvoiceDetailService.updateFinancialObjectCode(creditMemoDetail); } } public BigDecimal getInvoiceOpenItemQuantity(CustomerCreditMemoDetail customerCreditMemoDetail,CustomerInvoiceDetail customerInvoiceDetail) { BigDecimal invoiceOpenItemQuantity; BigDecimal invoiceItemUnitPrice = customerInvoiceDetail.getInvoiceItemUnitPrice(); if (ObjectUtils.isNull(invoiceItemUnitPrice) || invoiceItemUnitPrice.equals(BigDecimal.ZERO)) { invoiceOpenItemQuantity = BigDecimal.ZERO; } else { KualiDecimal invoiceOpenItemAmount = customerCreditMemoDetail.getInvoiceOpenItemAmount(); KualiDecimal invoiceOpenItemPretaxAmount = invoiceOpenItemAmount; if( getArTaxService().isCustomerInvoiceDetailTaxable(getInvoice(), customerInvoiceDetail)) { invoiceOpenItemPretaxAmount = getCustomerInvoiceDetailOpenPretaxAmount(invoiceOpenItemAmount); } invoiceOpenItemQuantity = invoiceOpenItemPretaxAmount.bigDecimalValue().divide(invoiceItemUnitPrice, ArConstants.ITEM_QUANTITY_SCALE, BigDecimal.ROUND_HALF_UP); } return invoiceOpenItemQuantity; } protected KualiDecimal getCustomerInvoiceDetailOpenPretaxAmount(KualiDecimal openAmount) { Date dateOfTransaction = getInvoice().getBillingDate(); KualiDecimal pretaxAmount = SpringContext.getBean(TaxService.class).getPretaxAmount(dateOfTransaction, getPostalCode(), openAmount); return pretaxAmount; } /** * do all the calculations before the document gets saved * gets called for 'Submit', 'Save', and 'Blanket Approved' * @see org.kuali.rice.krad.document.Document#prepareForSave(org.kuali.rice.krad.rule.event.KualiDocumentEvent) */ @Override public void prepareForSave(KualiDocumentEvent event) { CustomerCreditMemoDocument customerCreditMemoDocument = (CustomerCreditMemoDocument)event.getDocument(); CustomerCreditMemoDocumentService customerCreditMemoDocumentService = SpringContext.getBean(CustomerCreditMemoDocumentService.class); customerCreditMemoDocumentService.recalculateCustomerCreditMemoDocument(customerCreditMemoDocument,false); // generate GLPEs if (!SpringContext.getBean(GeneralLedgerPendingEntryService.class).generateGeneralLedgerPendingEntries(this)) { logErrors(); throw new ValidationException("general ledger GLPE generation failed"); } super.prepareForSave(event); } /** * @see org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource#generateDocumentGeneralLedgerPendingEntries(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper) */ @Override public boolean generateDocumentGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySequenceHelper sequenceHelper) { boolean success = true; return success; } /** * @see org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource#isDebit(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail) */ @Override public boolean isDebit(GeneralLedgerPendingEntrySourceDetail postable) { return false; } /** * @see org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource#clearAnyGeneralLedgerPendingEntries() */ @Override public void clearAnyGeneralLedgerPendingEntries() { generalLedgerPendingEntries = new ArrayList<GeneralLedgerPendingEntry>(); } /** * @see org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource#getGeneralLedgerPostables() */ @Override public List<GeneralLedgerPendingEntrySourceDetail> getGeneralLedgerPendingEntrySourceDetails() { List<GeneralLedgerPendingEntrySourceDetail> generalLedgerPendingEntrySourceDetails = new ArrayList<GeneralLedgerPendingEntrySourceDetail>(); if (creditMemoDetails != null) { Iterator iter = creditMemoDetails.iterator(); CustomerCreditMemoDetail customerCreditMemoDetail; KualiDecimal amount; while (iter.hasNext()) { customerCreditMemoDetail = (CustomerCreditMemoDetail)iter.next(); amount = customerCreditMemoDetail.getCreditMemoItemTotalAmount(); // get only non empty credit memo details to generate GLPEs if (ObjectUtils.isNotNull(amount) && amount.isGreaterThan(KualiDecimal.ZERO)) { generalLedgerPendingEntrySourceDetails.add(customerCreditMemoDetail); } } } return generalLedgerPendingEntrySourceDetails; } /** * @see org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource#addPendingEntry(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry) */ @Override public void addPendingEntry(GeneralLedgerPendingEntry entry) { generalLedgerPendingEntries.add(entry); } /** * @see org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource#getGeneralLedgerPendingEntryAmountForGeneralLedgerPostable(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail) */ @Override public KualiDecimal getGeneralLedgerPendingEntryAmountForDetail(GeneralLedgerPendingEntrySourceDetail postable) { return postable.getAmount(); } /** * Returns the general ledger input type code for the given document, using the DataDictionaryService * @return the general ledger input type code for the given document */ @Override public String getFinancialDocumentTypeCode() { return SpringContext.getBean(DataDictionaryService.class).getDocumentTypeNameByClass(this.getClass()); } @Override public List<String> getWorkflowEngineDocumentIdsToLock() { // a credit memo wont always update the source invoice, but sometimes it will so we include it here if (StringUtils.isNotBlank(getFinancialDocumentReferenceInvoiceNumber())) { List<String> documentIds = new ArrayList<String>(); documentIds.add(getFinancialDocumentReferenceInvoiceNumber()); return documentIds; } return null; } /** * When document is processed do the following: * * 1) Apply amounts to writeoff invoice * 2) Mark off invoice indiciator * * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocumentBase#doRouteStatusChange() */ @Override public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent){ super.doRouteStatusChange(statusChangeEvent); if (getDocumentHeader().getWorkflowDocument().isProcessed()) { //have to populate because not all the customer credit memo details are populated while doc is in workflow populateCustomerCreditMemoDetailsAfterLoad(); // apply writeoff amounts by only retrieving only the invoice details that ARE NOT discounts CustomerCreditMemoDocumentService service = SpringContext.getBean(CustomerCreditMemoDocumentService.class); service.completeCustomerCreditMemo(this); } } /** * This method creates the following GLPE's for the customer credit memo * * 1. Credit to receivable object for total line amount (excluding sales tax) * 2. Debit to income object for total line amount (excluding sales tax) * 3. Credit to receivable object in sales tax account(if sales tax exists) * 4. Debit to liability object in sales tax account(if sales tax exists) * 5. Credit to receivable object in district tax account(if district tax exists) * 6. Debit to liability object code in district tax account(if district 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 CustomerInvoiceDetail invoiceDetail = ((CustomerCreditMemoDetail) glpeSourceDetail).getCustomerInvoiceDetail(); if( getArTaxService().isCustomerInvoiceDetailTaxable(getInvoice(), invoiceDetail) ) { addSalesTaxGLPEs( sequenceHelper, glpeSourceDetail); } return true; } /** * This method creates the receivable GLPEs for credit memo detail lines. * * @param poster * @param sequenceHelper * @param postable * @param explicitEntry */ protected void addReceivableGLPEs(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntrySourceDetail glpeSourceDetail) { CustomerCreditMemoDetail customerCreditMemoDetail = (CustomerCreditMemoDetail)glpeSourceDetail; CustomerInvoiceDetail customerInvoiceDetail = customerCreditMemoDetail.getCustomerInvoiceDetail(); ReceivableCustomerInvoiceDetail receivableCustomerInvoiceDetail = new ReceivableCustomerInvoiceDetail(customerInvoiceDetail, this.getInvoice()); boolean isDebit = false; AccountsReceivablePendingEntryService service = SpringContext.getBean(AccountsReceivablePendingEntryService.class); service.createAndAddGenericInvoiceRelatedGLPEs(this, receivableCustomerInvoiceDetail, sequenceHelper, isDebit, false, customerCreditMemoDetail.getCreditMemoItemTotalAmount()); } /** * 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) { CustomerCreditMemoDetail customerCreditMemoDetail = (CustomerCreditMemoDetail)glpeSourceDetail; boolean isDebit = true; AccountsReceivablePendingEntryService service = SpringContext.getBean(AccountsReceivablePendingEntryService.class); service.createAndAddGenericInvoiceRelatedGLPEs(this, customerCreditMemoDetail, sequenceHelper, isDebit, false, customerCreditMemoDetail.getCreditMemoItemTotalAmount()); } /** * 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){ CustomerCreditMemoDetail customerCreditMemoDetail = (CustomerCreditMemoDetail)glpeSourceDetail; boolean isDebit = false; String postalCode = getPostalCode(); Date dateOfTransaction = getInvoice().getBillingDate(); List<TaxDetail> salesTaxDetails = getTaxService().getSalesTaxDetails(dateOfTransaction, postalCode, customerCreditMemoDetail.getCreditMemoItemTotalAmount()); AccountsReceivablePendingEntryService service = SpringContext.getBean(AccountsReceivablePendingEntryService.class); SalesTaxCustomerCreditMemoDetail salesTaxCustomerCreditMemoDetail; ReceivableCustomerCreditMemoDetail receivableCustomerCreditMemoDetail; for( TaxDetail salesTaxDetail : salesTaxDetails ){ salesTaxCustomerCreditMemoDetail = new SalesTaxCustomerCreditMemoDetail( salesTaxDetail, customerCreditMemoDetail ); salesTaxCustomerCreditMemoDetail.setCustomerInvoiceDetail(customerCreditMemoDetail.getCustomerInvoiceDetail()); receivableCustomerCreditMemoDetail = new ReceivableCustomerCreditMemoDetail(salesTaxCustomerCreditMemoDetail, this); receivableCustomerCreditMemoDetail.setCustomerInvoiceDetail(customerCreditMemoDetail.getCustomerInvoiceDetail()); sequenceHelper.increment(); service.createAndAddGenericInvoiceRelatedGLPEs(this, receivableCustomerCreditMemoDetail, sequenceHelper, isDebit, false, salesTaxDetail.getTaxAmount()); sequenceHelper.increment(); service.createAndAddGenericInvoiceRelatedGLPEs(this, salesTaxCustomerCreditMemoDetail, sequenceHelper, !isDebit, false, salesTaxDetail.getTaxAmount()); } } @Override public KualiDecimal getTotalDollarAmount() { return getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount(); } public AccountsReceivableDocumentHeader getAccountsReceivableDocumentHeader() { return accountsReceivableDocumentHeader; } public void setAccountsReceivableDocumentHeader(AccountsReceivableDocumentHeader accountsReceivableDocumentHeader) { this.accountsReceivableDocumentHeader = accountsReceivableDocumentHeader; } public String getPostalCode() { String postalCode = getArTaxService().getPostalCodeForTaxation(getInvoice()); return postalCode; } /** * Gets the taxService attribute. * @return Returns the taxService. */ public TaxService getTaxService() { // lazy init the service if its been nullified by session-izing the document if (taxService == null) { taxService = SpringContext.getBean(TaxService.class); } return taxService; } /** * Gets the arTaxService attribute. * @return Returns the arTaxService. */ public AccountsReceivableTaxService getArTaxService() { // lazy init the service if its been nullified by session-izing the document if (arTaxService == null) { arTaxService = SpringContext.getBean(AccountsReceivableTaxService.class); } return arTaxService; } /** * @see org.kuali.kfs.integration.ar.AccountsReceivableCustomerCreditMemo#setAccountsReceivableDocumentHeader(org.kuali.kfs.integration.ar.AccountsRecievableDocumentHeader) */ @Override public void setAccountsReceivableDocumentHeader(org.kuali.kfs.integration.ar.AccountsReceivableDocumentHeader arDocHeader) { this.accountsReceivableDocumentHeader = (org.kuali.kfs.module.ar.businessobject.AccountsReceivableDocumentHeader) arDocHeader; } }