blob: 0c4c88832c93a4c01eb930ac51a0f29841386c42 [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*******************************************************************************/
package org.apache.ofbiz.accounting.invoice;
import java.math.BigDecimal;
import java.math.MathContext;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.UtilDateTime;
import org.apache.ofbiz.base.util.UtilMisc;
import org.apache.ofbiz.base.util.UtilNumber;
import org.apache.ofbiz.base.util.UtilValidate;
import org.apache.ofbiz.entity.Delegator;
import org.apache.ofbiz.entity.GenericEntityException;
import org.apache.ofbiz.entity.GenericValue;
import org.apache.ofbiz.entity.condition.EntityCondition;
import org.apache.ofbiz.entity.condition.EntityConditionList;
import org.apache.ofbiz.entity.condition.EntityExpr;
import org.apache.ofbiz.entity.condition.EntityOperator;
import org.apache.ofbiz.entity.util.EntityQuery;
import org.apache.ofbiz.entity.util.EntityUtil;
import org.apache.ofbiz.entity.util.EntityUtilProperties;
/**
* InvoiceWorker - Worker methods of invoices
*/
public final class InvoiceWorker {
public static final String module = InvoiceWorker.class.getName();
private static final BigDecimal ZERO = BigDecimal.ZERO;
private static final int decimals = UtilNumber.getBigDecimalScale("invoice.decimals");
private static final int rounding = UtilNumber.getBigDecimalRoundingMode("invoice.rounding");
private static final int taxDecimals = UtilNumber.getBigDecimalScale("salestax.calc.decimals");
private static final int taxRounding = UtilNumber.getBigDecimalRoundingMode("salestax.rounding");
private InvoiceWorker () {}
/**
* Return the total amount of the invoice (including tax) using the the invoiceId as input.
* @param delegator the delegator
* @param invoiceId the invoice id
* @return Return the total amount of the invoice
*/
public static BigDecimal getInvoiceTotal(Delegator delegator, String invoiceId) {
return getInvoiceTotal(delegator, invoiceId, Boolean.TRUE);
}
/**
* Return the total amount of the invoice (including tax) using the the invoiceId as input.
* with the ability to specify if the actual currency is required.
* @param delegator the delegator
* @param invoiceId the invoice Id
* @param actualCurrency true: provide the actual currency of the invoice (could be different from the system currency)
* false: if required convert the actual currency into the system currency.
* @return Return the total amount of the invoice
*/
public static BigDecimal getInvoiceTotal(Delegator delegator, String invoiceId, Boolean actualCurrency) {
if (delegator == null) {
throw new IllegalArgumentException("Null delegator is not allowed in this method");
}
GenericValue invoice = null;
try {
invoice = EntityQuery.use(delegator).from("Invoice").where("invoiceId", invoiceId).queryOne();
} catch (GenericEntityException e) {
Debug.logError(e, "Problem getting Invoice", module);
}
if (invoice == null) {
throw new IllegalArgumentException("The passed invoiceId [" +invoiceId + "] does not match an existing invoice");
}
return getInvoiceTotal(invoice, actualCurrency);
}
/**
* Method to return the total amount of an invoice item i.e. quantity * amount
* @param invoiceItem GenericValue object of the invoice item
* @return the invoice total as BigDecimal
*/
public static BigDecimal getInvoiceItemTotal(GenericValue invoiceItem) {
BigDecimal quantity = invoiceItem.getBigDecimal("quantity");
if (quantity == null) {
quantity = BigDecimal.ONE;
}
BigDecimal amount = invoiceItem.getBigDecimal("amount");
if (amount == null) {
amount = ZERO;
}
return quantity.multiply(amount).setScale(decimals, rounding);
}
/** Method to get the taxable invoice item types as a List of invoiceItemTypeIds. These are identified in Enumeration with enumTypeId TAXABLE_INV_ITM_TY. */
public static List<String> getTaxableInvoiceItemTypeIds(Delegator delegator) throws GenericEntityException {
List<String> typeIds = new LinkedList<String>();
List<GenericValue> invoiceItemTaxTypes = EntityQuery.use(delegator).from("Enumeration").where("enumTypeId", "TAXABLE_INV_ITM_TY")
.cache().queryList();
for (GenericValue invoiceItemTaxType : invoiceItemTaxTypes) {
typeIds.add(invoiceItemTaxType.getString("enumId"));
}
return typeIds;
}
public static BigDecimal getInvoiceTaxTotal(GenericValue invoice) {
BigDecimal taxTotal = ZERO;
Map<String, Set<String>> taxAuthPartyAndGeos = InvoiceWorker.getInvoiceTaxAuthPartyAndGeos(invoice);
for (Map.Entry<String, Set<String>> taxAuthPartyGeos : taxAuthPartyAndGeos.entrySet()) {
String taxAuthPartyId = taxAuthPartyGeos.getKey();
for (String taxAuthGeoId : taxAuthPartyGeos.getValue()) {
taxTotal = taxTotal.add(InvoiceWorker.getInvoiceTaxTotalForTaxAuthPartyAndGeo(invoice, taxAuthPartyId, taxAuthGeoId));
}
}
taxTotal = taxTotal.add(InvoiceWorker.getInvoiceUnattributedTaxTotal(invoice));
return taxTotal;
}
public static BigDecimal getInvoiceNoTaxTotal(GenericValue invoice) {
return getInvoiceTotal(invoice, Boolean.TRUE).subtract(getInvoiceTaxTotal(invoice));
}
/**
* Method to return the total amount of an invoice
* @param invoice GenericValue object of the Invoice
* @return the invoice total as BigDecimal
*/
public static BigDecimal getInvoiceTotal(GenericValue invoice) {
return getInvoiceTotal(invoice, Boolean.TRUE);
}
/**
*
* Return the total amount of the invoice (including tax) using the the invoice GenericValue as input.
* with the ability to specify if the actual currency is required.
* @param invoice GenericValue object of the Invoice
* @param actualCurrency true: provide the actual currency of the invoice (could be different from the system currency)
* false: if required convert the actual currency into the system currency.
* @return Return the total amount of the invoice
*/
public static BigDecimal getInvoiceTotal(GenericValue invoice, Boolean actualCurrency) {
BigDecimal invoiceTotal = ZERO;
BigDecimal invoiceTaxTotal = ZERO;
invoiceTaxTotal = InvoiceWorker.getInvoiceTaxTotal(invoice);
List<GenericValue> invoiceItems = null;
try {
invoiceItems = invoice.getRelated("InvoiceItem", null, null, false);
invoiceItems = EntityUtil.filterByAnd(
invoiceItems, UtilMisc.toList(
EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.NOT_IN, getTaxableInvoiceItemTypeIds(invoice.getDelegator()))
));
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting InvoiceItem list", module);
}
if (invoiceItems != null) {
for (GenericValue invoiceItem : invoiceItems) {
invoiceTotal = invoiceTotal.add(getInvoiceItemTotal(invoiceItem)).setScale(decimals,rounding);
}
}
invoiceTotal = invoiceTotal.add(invoiceTaxTotal).setScale(decimals, rounding);
if (UtilValidate.isNotEmpty(invoiceTotal) && !actualCurrency) {
invoiceTotal = invoiceTotal.multiply(getInvoiceCurrencyConversionRate(invoice)).setScale(decimals,rounding);
}
return invoiceTotal;
}
/**
* Method to obtain the bill to party for an invoice. Note that invoice.partyId is the bill to party.
* @param invoice GenericValue object of the Invoice
* @return GenericValue object of the Party
*/
public static GenericValue getBillToParty(GenericValue invoice) {
try {
GenericValue billToParty = invoice.getRelatedOne("Party", false);
if (billToParty != null) {
return billToParty;
}
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting Party from Invoice", module);
}
// remaining code is the old method, which we leave here for compatibility purposes
List<GenericValue> billToRoles = null;
try {
billToRoles = invoice.getRelated("InvoiceRole", UtilMisc.toMap("roleTypeId", "BILL_TO_CUSTOMER"), UtilMisc.toList("-datetimePerformed"), false);
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting InvoiceRole list", module);
}
if (billToRoles != null) {
GenericValue role = EntityUtil.getFirst(billToRoles);
GenericValue party = null;
try {
party = role.getRelatedOne("Party", false);
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting Party from InvoiceRole", module);
}
if (party != null)
return party;
}
return null;
}
/** Convenience method to obtain the bill from party for an invoice. Note that invoice.partyIdFrom is the bill from party. */
public static GenericValue getBillFromParty(GenericValue invoice) {
try {
return invoice.getRelatedOne("FromParty", false);
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting FromParty from Invoice", module);
}
return null;
}
/**
* Method to obtain the send from party for an invoice
* @param invoice GenericValue object of the Invoice
* @return GenericValue object of the Party
*/
public static GenericValue getSendFromParty(GenericValue invoice) {
GenericValue billFromParty = getBillFromParty(invoice);
if (billFromParty != null) {
return billFromParty;
}
// remaining code is the old method, which we leave here for compatibility purposes
List<GenericValue> sendFromRoles = null;
try {
sendFromRoles = invoice.getRelated("InvoiceRole", UtilMisc.toMap("roleTypeId", "BILL_FROM_VENDOR"), UtilMisc.toList("-datetimePerformed"), false);
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting InvoiceRole list", module);
}
if (sendFromRoles != null) {
GenericValue role = EntityUtil.getFirst(sendFromRoles);
GenericValue party = null;
try {
party = role.getRelatedOne("Party", false);
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting Party from InvoiceRole", module);
}
if (party != null)
return party;
}
return null;
}
/**
* Method to obtain the billing address for an invoice
* @param invoice GenericValue object of the Invoice
* @return GenericValue object of the PostalAddress
*/
public static GenericValue getBillToAddress(GenericValue invoice) {
return getInvoiceAddressByType(invoice, "BILLING_LOCATION");
}
/**
* Method to obtain the sending address for an invoice
* @param invoice GenericValue object of the Invoice
* @return GenericValue object of the PostalAddress
*/
public static GenericValue getSendFromAddress(GenericValue invoice) {
return getInvoiceAddressByType(invoice, "PAYMENT_LOCATION");
}
public static GenericValue getInvoiceAddressByType(GenericValue invoice, String contactMechPurposeTypeId) {
return getInvoiceAddressByType(invoice, contactMechPurposeTypeId, true);
}
public static GenericValue getInvoiceAddressByType(GenericValue invoice, String contactMechPurposeTypeId, boolean fetchPartyAddress) {
Delegator delegator = invoice.getDelegator();
List<GenericValue> locations = null;
// first try InvoiceContactMech to see if we can find the address needed
try {
locations = invoice.getRelated("InvoiceContactMech", UtilMisc.toMap("contactMechPurposeTypeId", contactMechPurposeTypeId), null, false);
} catch (GenericEntityException e) {
Debug.logError("Touble getting InvoiceContactMech entity list", module);
}
if (UtilValidate.isEmpty(locations) && fetchPartyAddress) {
// if no locations found get it from the PartyAndContactMech using the from and to party on the invoice
String destinationPartyId = null;
Timestamp now = UtilDateTime.nowTimestamp();
if (invoice.getString("invoiceTypeId").equals("SALES_INVOICE"))
destinationPartyId = invoice.getString("partyId");
if (invoice.getString("invoiceTypeId").equals("PURCHASE_INVOICE"))
destinationPartyId = invoice.getString("partyId");
try {
locations = EntityQuery.use(delegator).from("PartyContactWithPurpose")
.where("partyId", destinationPartyId, "contactMechPurposeTypeId", contactMechPurposeTypeId).queryList();
locations = EntityUtil.filterByDate(locations, now, "contactFromDate", "contactThruDate", true);
locations = EntityUtil.filterByDate(locations, now, "purposeFromDate", "purposeThruDate", true);
} catch (GenericEntityException e) {
Debug.logError("Trouble getting contact party purpose list", module);
}
//if still not found get it from the general location
if (UtilValidate.isEmpty(locations)) {
try {
locations = EntityQuery.use(delegator).from("PartyContactWithPurpose")
.where("partyId", destinationPartyId, "contactMechPurposeTypeId", "GENERAL_LOCATION").queryList();
locations = EntityUtil.filterByDate(locations, now, "contactFromDate", "contactThruDate", true);
locations = EntityUtil.filterByDate(locations, now, "purposeFromDate", "purposeThruDate", true);
} catch (GenericEntityException e) {
Debug.logError("Trouble getting contact party purpose list", module);
}
}
}
// now return the first PostalAddress from the locations
GenericValue postalAddress = null;
GenericValue contactMech = null;
if (UtilValidate.isNotEmpty(locations)) {
try {
contactMech = locations.get(0).getRelatedOne("ContactMech", false);
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting Contact for contactMechId: " + locations.get(0).getString("contactMechId"), module);
}
if (contactMech != null && contactMech.getString("contactMechTypeId").equals("POSTAL_ADDRESS")) {
try {
postalAddress = contactMech.getRelatedOne("PostalAddress", false);
return postalAddress;
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting PostalAddress for contactMechId: " + contactMech.getString("contactMechId"), module);
}
}
}
return contactMech;
}
/**
* Method to return the total amount of an invoice which is not yet applied to a payment
* @param delegator the delegator
* @param invoiceId the invoice id
* @param actualCurrency the currency
* @return the invoice total as BigDecimal
*/
public static BigDecimal getInvoiceNotApplied(Delegator delegator, String invoiceId, Boolean actualCurrency) {
return InvoiceWorker.getInvoiceTotal(delegator, invoiceId, actualCurrency).subtract(getInvoiceApplied(delegator, invoiceId, UtilDateTime.nowTimestamp(), actualCurrency));
}
public static BigDecimal getInvoiceNotApplied(Delegator delegator, String invoiceId) {
return InvoiceWorker.getInvoiceTotal(delegator, invoiceId).subtract(getInvoiceApplied(delegator, invoiceId));
}
public static BigDecimal getInvoiceNotApplied(GenericValue invoice) {
return InvoiceWorker.getInvoiceTotal(invoice, Boolean.TRUE).subtract(getInvoiceApplied(invoice));
}
public static BigDecimal getInvoiceNotApplied(GenericValue invoice, Boolean actualCurrency) {
return InvoiceWorker.getInvoiceTotal(invoice, actualCurrency).subtract(getInvoiceApplied(invoice, actualCurrency));
}
/**
* Returns amount not applied (i.e., still outstanding) of an invoice at an asOfDate, based on Payment.effectiveDate &lt;= asOfDateTime
*
* @param invoice GenericValue object of the invoice
* @param asOfDateTime the date to use
* @return Returns amount not applied of the invoice
*/
public static BigDecimal getInvoiceNotApplied(GenericValue invoice, Timestamp asOfDateTime) {
return InvoiceWorker.getInvoiceTotal(invoice, Boolean.TRUE).subtract(getInvoiceApplied(invoice, asOfDateTime));
}
/**
* Method to return the total amount of an invoice which is applied to a payment
* @param delegator the delegator
* @param invoiceId the invoice id
* @return the invoice total as BigDecimal
*/
public static BigDecimal getInvoiceApplied(Delegator delegator, String invoiceId) {
return getInvoiceApplied(delegator, invoiceId, UtilDateTime.nowTimestamp(), Boolean.TRUE);
}
/**
* Returns amount applied to invoice before an asOfDateTime, based on Payment.effectiveDate &lt;= asOfDateTime
*
* @param delegator the delegator
* @param invoiceId the invoice id
* @param asOfDateTime - a Timestamp
* @return returns amount applied to invoice before an asOfDateTime
*/
public static BigDecimal getInvoiceApplied(Delegator delegator, String invoiceId, Timestamp asOfDateTime, Boolean actualCurrency) {
if (delegator == null) {
throw new IllegalArgumentException("Null delegator is not allowed in this method");
}
BigDecimal invoiceApplied = ZERO;
List<GenericValue> paymentApplications = null;
// lookup payment applications which took place before the asOfDateTime for this invoice
EntityConditionList<EntityExpr> dateCondition = EntityCondition.makeCondition(UtilMisc.toList(
EntityCondition.makeCondition("effectiveDate", EntityOperator.EQUALS, null),
EntityCondition.makeCondition("effectiveDate", EntityOperator.LESS_THAN_EQUAL_TO, asOfDateTime)), EntityOperator.OR);
EntityConditionList<EntityCondition> conditions = EntityCondition.makeCondition(UtilMisc.toList(
dateCondition,
EntityCondition.makeCondition("invoiceId", EntityOperator.EQUALS, invoiceId)),
EntityOperator.AND);
try {
paymentApplications = EntityQuery.use(delegator).from("PaymentAndApplication")
.where(conditions).orderBy("effectiveDate").queryList();
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting paymentApplicationlist", module);
}
if (paymentApplications != null) {
for (GenericValue paymentApplication : paymentApplications) {
invoiceApplied = invoiceApplied.add(paymentApplication.getBigDecimal("amountApplied")).setScale(decimals,rounding);
}
}
if (UtilValidate.isNotEmpty(invoiceApplied) && !actualCurrency) {
invoiceApplied = invoiceApplied.multiply(getInvoiceCurrencyConversionRate(delegator, invoiceId)).setScale(decimals,rounding);
}
return invoiceApplied;
}
/**
* Method to return the total amount of an invoice which is applied to a payment
* @param invoice GenericValue object of the invoice
* @return the applied total as BigDecimal
*/
public static BigDecimal getInvoiceApplied(GenericValue invoice) {
return getInvoiceApplied(invoice, UtilDateTime.nowTimestamp());
}
/**
* Return the amount applied to the invoice
* @param invoice GenericValue object of the invoice
* @param actualCurrency the currency of the invoice
* @return returns the amount applied to the invoice
*/
public static BigDecimal getInvoiceApplied(GenericValue invoice, Boolean actualCurrency) {
return getInvoiceApplied(invoice.getDelegator(), invoice.getString("invoiceId"), UtilDateTime.nowTimestamp(), actualCurrency);
}
public static BigDecimal getInvoiceApplied(GenericValue invoice, Timestamp asOfDateTime) {
return getInvoiceApplied(invoice.getDelegator(), invoice.getString("invoiceId"), asOfDateTime, Boolean.TRUE);
}
/**
* Method to return the amount of an invoiceItem which is applied to a payment
* @param delegator the delegator
* @param invoiceId the invoice id
* @param invoiceItemSeqId the invoice item id
* @return the invoice total as BigDecimal
*/
public static BigDecimal getInvoiceItemApplied(Delegator delegator, String invoiceId, String invoiceItemSeqId) {
if (delegator == null) {
throw new IllegalArgumentException("Null delegator is not allowed in this method");
}
GenericValue invoiceItem = null;
try {
invoiceItem = EntityQuery.use(delegator).from("Invoice").where("invoiceId", invoiceId,"invoiceItemSeqId", invoiceItemSeqId).queryOne();
} catch (GenericEntityException e) {
Debug.logError(e, "Problem getting InvoiceItem", module);
}
if (invoiceItem == null) {
throw new IllegalArgumentException("The invoiceId/itemSeqId passed does not match an existing invoiceItem");
}
return getInvoiceItemApplied(invoiceItem);
}
/**
* Method to return the total amount of an invoiceItem which is applied to a payment
* @param invoiceItem GenericValue object of the invoice item
* @return the applied total as BigDecimal
*/
public static BigDecimal getInvoiceItemApplied(GenericValue invoiceItem) {
BigDecimal invoiceItemApplied = ZERO;
List<GenericValue> paymentApplications = null;
try {
paymentApplications = invoiceItem.getRelated("PaymentApplication", null, null, false);
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting paymentApplicationlist", module);
}
if (paymentApplications != null) {
for (GenericValue paymentApplication : paymentApplications) {
invoiceItemApplied = invoiceItemApplied.add(paymentApplication.getBigDecimal("amountApplied")).setScale(decimals,rounding);
}
}
return invoiceItemApplied;
}
public static BigDecimal getInvoiceCurrencyConversionRate(GenericValue invoice) {
BigDecimal conversionRate = null;
Delegator delegator = invoice.getDelegator();
String otherCurrencyUomId = null;
// find the organization party currencyUomId which different from the invoice currency
try {
GenericValue party = EntityQuery.use(delegator).from("PartyAcctgPreference").where("partyId", invoice.get("partyIdFrom")).queryOne();
if (UtilValidate.isEmpty(party) || party.getString("baseCurrencyUomId").equals(invoice.getString("currencyUomId"))) {
party = EntityQuery.use(delegator).from("PartyAcctgPreference").where("partyId", invoice.get("partyId")).queryOne();
}
if (UtilValidate.isNotEmpty(party) && party.getString("baseCurrencyUomId") != null) {
otherCurrencyUomId = party.getString("baseCurrencyUomId");
} else {
otherCurrencyUomId = EntityUtilProperties.getPropertyValue("general", "currency.uom.id.default", delegator);
}
if (otherCurrencyUomId == null) {
otherCurrencyUomId = "USD"; // final default
}
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting database records....", module);
}
if (invoice.getString("currencyUomId").equals(otherCurrencyUomId)) {
return BigDecimal.ONE; // organization party has the same currency so conversion not required.
}
try {
// check if the invoice is posted and get the conversion from there
List<GenericValue> acctgTransEntries = invoice.getRelated("AcctgTrans", null, null, false);
if (UtilValidate.isNotEmpty(acctgTransEntries)) {
GenericValue acctgTransEntry = (acctgTransEntries.get(0)).getRelated("AcctgTransEntry", null, null, false).get(0);
BigDecimal origAmount = acctgTransEntry.getBigDecimal("origAmount");
if (origAmount.compareTo(ZERO) == 1) {
conversionRate = acctgTransEntry.getBigDecimal("amount").divide(acctgTransEntry.getBigDecimal("origAmount"), new MathContext(100)).setScale(decimals,rounding);
}
}
// check if a payment is applied and use the currency conversion from there
if (UtilValidate.isEmpty(conversionRate)) {
List<GenericValue> paymentAppls = invoice.getRelated("PaymentApplication", null, null, false);
for (GenericValue paymentAppl : paymentAppls) {
GenericValue payment = paymentAppl.getRelatedOne("Payment", false);
if (UtilValidate.isNotEmpty(payment.getBigDecimal("actualCurrencyAmount"))) {
if (UtilValidate.isEmpty(conversionRate)) {
conversionRate = payment.getBigDecimal("amount").divide(payment.getBigDecimal("actualCurrencyAmount"),new MathContext(100)).setScale(decimals,rounding);
} else {
conversionRate = conversionRate.add(payment.getBigDecimal("amount").divide(payment.getBigDecimal("actualCurrencyAmount"),new MathContext(100))).divide(new BigDecimal("2"),new MathContext(100)).setScale(decimals,rounding);
}
}
}
}
// use the dated conversion entity
if (UtilValidate.isEmpty(conversionRate)) {
GenericValue rate = EntityQuery.use(delegator).from("UomConversionDated").where("uomIdTo", invoice.get("currencyUomId"), "uomId", otherCurrencyUomId).filterByDate(invoice.getTimestamp("invoiceDate")).queryFirst();
if (rate != null) {
conversionRate = BigDecimal.ONE.divide(rate.getBigDecimal("conversionFactor"), new MathContext(100)).setScale(decimals,rounding);
} else {
Debug.logError("Could not find conversionrate for invoice: " + invoice.getString("invoiceId"), module);
return new BigDecimal("1");
}
}
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting database records....", module);
}
return(conversionRate);
}
public static BigDecimal getInvoiceCurrencyConversionRate(Delegator delegator, String invoiceId) {
if (delegator == null) {
throw new IllegalArgumentException("Null delegator is not allowed in this method");
}
GenericValue invoice = null;
try {
invoice = EntityQuery.use(delegator).from("Invoice").where("invoiceId", invoiceId).queryOne();
} catch (GenericEntityException e) {
Debug.logError(e, "Problem getting Invoice", module);
}
if (invoice == null) {
throw new IllegalArgumentException("The invoiceId passed does not match an existing invoice");
}
return getInvoiceCurrencyConversionRate(invoice);
}
/**
* Return a list of taxes separated by Geo and party and return the tax grand total
* @param invoice Generic Value
* @return Map: taxByTaxAuthGeoAndPartyList(List) and taxGrandTotal(BigDecimal)
*/
@Deprecated
public static Map<String, Object> getInvoiceTaxByTaxAuthGeoAndParty(GenericValue invoice) {
BigDecimal taxGrandTotal = ZERO;
List<Map<String, Object>> taxByTaxAuthGeoAndPartyList = new LinkedList<Map<String,Object>>();
List<GenericValue> invoiceItems = null;
if (invoice != null) {
try {
invoiceItems = invoice.getRelated("InvoiceItem", null, null, false);
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting InvoiceItem list", module);
}
if ("SALES_INVOICE".equals(invoice.getString("invoiceTypeId"))) {
invoiceItems = EntityUtil.filterByOr(
invoiceItems, UtilMisc.toList(
EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.EQUALS, "INV_SALES_TAX"),
EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.EQUALS, "ITM_SALES_TAX")));
} else if (("PURCHASE_INVOICE".equals(invoice.getString("invoiceTypeId")))) {
invoiceItems = EntityUtil.filterByOr(
invoiceItems, UtilMisc.toList(
EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.EQUALS, "PINV_SALES_TAX"),
EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.EQUALS, "PITM_SALES_TAX")));
} else {
invoiceItems = null;
}
if (UtilValidate.isNotEmpty(invoiceItems)) {
invoiceItems = EntityUtil.orderBy(invoiceItems, UtilMisc.toList("taxAuthGeoId","taxAuthPartyId"));
// get the list of all distinct taxAuthGeoId and taxAuthPartyId. It is for getting the number of taxAuthGeoId and taxAuthPartyId in invoiceItems.
List<String> distinctTaxAuthGeoIdList = EntityUtil.getFieldListFromEntityList(invoiceItems, "taxAuthGeoId", true);
List<String> distinctTaxAuthPartyIdList = EntityUtil.getFieldListFromEntityList(invoiceItems, "taxAuthPartyId", true);
for (String taxAuthGeoId : distinctTaxAuthGeoIdList ) {
for (String taxAuthPartyId : distinctTaxAuthPartyIdList) {
//get all records for invoices filtered by taxAuthGeoId and taxAurhPartyId
List<GenericValue> invoiceItemsByTaxAuthGeoAndPartyIds = EntityUtil.filterByAnd(invoiceItems, UtilMisc.toMap("taxAuthGeoId", taxAuthGeoId, "taxAuthPartyId", taxAuthPartyId));
if (UtilValidate.isNotEmpty(invoiceItemsByTaxAuthGeoAndPartyIds)) {
BigDecimal totalAmount = ZERO;
//Now for each invoiceItem record get and add amount.
for (GenericValue invoiceItem : invoiceItemsByTaxAuthGeoAndPartyIds) {
BigDecimal amount = invoiceItem.getBigDecimal("amount");
if (amount == null) {
amount = ZERO;
}
totalAmount = totalAmount.add(amount).setScale(taxDecimals, taxRounding);
}
totalAmount = totalAmount.setScale(UtilNumber.getBigDecimalScale("salestax.calc.decimals"), UtilNumber.getBigDecimalRoundingMode("salestax.rounding"));
taxByTaxAuthGeoAndPartyList.add(UtilMisc.<String, Object>toMap("taxAuthPartyId", taxAuthPartyId, "taxAuthGeoId", taxAuthGeoId, "totalAmount", totalAmount));
taxGrandTotal = taxGrandTotal.add(totalAmount);
}
}
}
}
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("taxByTaxAuthGeoAndPartyList", taxByTaxAuthGeoAndPartyList);
result.put("taxGrandTotal", taxGrandTotal);
return result;
}
/**
* Returns a List of the TaxAuthority Party and Geos for the given Invoice.
* @param invoice GenericValue object representing the Invoice
* @return A Map containing the each taxAuthPartyId as a key and a Set of taxAuthGeoIds for that taxAuthPartyId as the values. Note this method
* will not account for tax lines that do not contain a taxAuthPartyId
*/
public static Map<String, Set<String>> getInvoiceTaxAuthPartyAndGeos (GenericValue invoice) {
Map<String, Set<String>> result = new HashMap<String, Set<String>>();
if (invoice == null)
throw new IllegalArgumentException("Invoice cannot be null.");
List<GenericValue> invoiceTaxItems = null;
try {
Delegator delegator = invoice.getDelegator();
invoiceTaxItems = EntityQuery.use(delegator).from("InvoiceItem")
.where(EntityCondition.makeCondition("invoiceId", invoice.getString("invoiceId")),
EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.IN, getTaxableInvoiceItemTypeIds(delegator))
).queryList();
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting InvoiceItem list", module);
return null;
}
if (invoiceTaxItems != null) {
for (GenericValue invoiceItem : invoiceTaxItems) {
String taxAuthPartyId = invoiceItem.getString("taxAuthPartyId");
String taxAuthGeoId = invoiceItem.getString("taxAuthGeoId");
if (UtilValidate.isNotEmpty(taxAuthPartyId)) {
if (!result.containsKey(taxAuthPartyId)) {
Set<String> taxAuthGeos = new HashSet<String>();
taxAuthGeos.add(taxAuthGeoId);
result.put(taxAuthPartyId, taxAuthGeos);
} else {
Set<String> taxAuthGeos = result.get(taxAuthPartyId);
taxAuthGeos.add(taxAuthGeoId);
}
}
}
}
return result;
}
/**
* @param invoice GenericValue object representing the invoice
* @param taxAuthPartyId
* @param taxAuthGeoId
* @return The invoice tax total for a given tax authority and geo location
*/
public static BigDecimal getInvoiceTaxTotalForTaxAuthPartyAndGeo(GenericValue invoice, String taxAuthPartyId, String taxAuthGeoId) {
List<GenericValue> invoiceTaxItems = null;
try {
Delegator delegator = invoice.getDelegator();
invoiceTaxItems = EntityQuery.use(delegator).from("InvoiceItem")
.where(EntityCondition.makeCondition("invoiceId", invoice.getString("invoiceId")),
EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.IN, getTaxableInvoiceItemTypeIds(delegator)),
EntityCondition.makeCondition("taxAuthPartyId", taxAuthPartyId),
EntityCondition.makeCondition("taxAuthGeoId", taxAuthGeoId)
).queryList();
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting InvoiceItem list", module);
return null;
}
return getTaxTotalForInvoiceItems(invoiceTaxItems);
}
/** Returns the invoice tax total for unattributed tax items, that is items which have no taxAuthPartyId value
* @param invoice GenericValue object representing the invoice
* @return Returns the invoice tax total for unattributed tax items
*/
public static BigDecimal getInvoiceUnattributedTaxTotal(GenericValue invoice) {
List<GenericValue> invoiceTaxItems = null;
try {
Delegator delegator = invoice.getDelegator();
invoiceTaxItems = EntityQuery.use(delegator).from("InvoiceItem")
.where(EntityCondition.makeCondition("invoiceId", invoice.get("invoiceId")),
EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.IN, getTaxableInvoiceItemTypeIds(delegator)),
EntityCondition.makeCondition("taxAuthPartyId", null)
).queryList();
} catch (GenericEntityException e) {
Debug.logError(e, "Trouble getting InvoiceItem list", module);
return null;
}
return getTaxTotalForInvoiceItems(invoiceTaxItems);
}
/** Returns the tax total for a given list of tax typed InvoiceItem records
* @param taxInvoiceItems
* @return
*/
private static BigDecimal getTaxTotalForInvoiceItems(List<GenericValue> taxInvoiceItems) {
if (taxInvoiceItems == null) {
return ZERO;
}
BigDecimal taxTotal = ZERO;
for (GenericValue taxInvoiceItem : taxInvoiceItems) {
BigDecimal amount = taxInvoiceItem.getBigDecimal("amount");
if (amount == null) {
amount = ZERO;
}
BigDecimal quantity = taxInvoiceItem.getBigDecimal("quantity");
if (quantity == null) {
quantity = BigDecimal.ONE;
}
amount = amount.multiply(quantity);
amount = amount.setScale(taxDecimals, taxRounding);
taxTotal = taxTotal.add(amount);
}
return taxTotal.setScale(decimals, rounding);
}
}