/*
* 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;
}
}