|
Author: lektran
Date: Wed Jan 20 05:53:22 2010 New Revision: 901070 URL: http://svn.apache.org/viewvc?rev=901070&view=rev Log: Rewrote the invoice tax calculation methods, now takes into account tax invoice items that do not have a taxAuthPartyId set and generally makes things a little more comprehendible. Resolves OFBIZ-3318 reported by Willem Janssen. Modified: ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/ledger/GeneralLedgerServices.xml ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceWorker.java Modified: ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/ledger/GeneralLedgerServices.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/ledger/GeneralLedgerServices.xml?rev=901070&r1=901069&r2=901070&view=diff ============================================================================== --- ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/ledger/GeneralLedgerServices.xml (original) +++ ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/ledger/GeneralLedgerServices.xml Wed Jan 20 05:53:22 2010 @@ -1790,25 +1790,41 @@ <set field="acctgTransEntries[]" from-field="debitEntry" type="Object"/> </iterate> <!-- debit entry for SALES_TAX--> - <call-class-method method-name="getInvoiceTaxByTaxAuthGeoAndParty" class-name="org.ofbiz.accounting.invoice.InvoiceWorker" - ret-field="invoiceTaxByTaxAuthGeoAndPartyResult"> + <call-class-method method-name="getInvoiceTaxAuthPartyAndGeos" class-name="org.ofbiz.accounting.invoice.InvoiceWorker" + ret-field="taxAuthPartyAndGeos"> <field field="invoice" type="org.ofbiz.entity.GenericValue"/> </call-class-method> - <set field="taxByTaxAuthGeoAndPartyList" from-field="invoiceTaxByTaxAuthGeoAndPartyResult.taxByTaxAuthGeoAndPartyList"/> - <set field="invoiceTaxTotal" from-field="invoiceTaxByTaxAuthGeoAndPartyResult.taxGrandTotal"/> - <iterate list="taxByTaxAuthGeoAndPartyList" entry="taxByTaxAuthGeoAndParty"> - <clear-field field="creditEntry"/> - <make-value entity-name="AcctgTransEntry" value-field="creditEntry"/> - <set field="creditEntry.debitCreditFlag" value="D"/> - <set field="creditEntry.organizationPartyId" from-field="invoice.partyIdFrom"/> - <set field="creditEntry.origAmount" from-field="taxByTaxAuthGeoAndParty.totalAmount"/> - <set field="creditEntry.origCurrencyUomId" from-field="invoice.currencyUomId"/> - <if-not-empty field="taxByTaxAuthGeoAndParty.taxAuthPartyId"> - <set field="creditEntry.partyId" from-field="taxByTaxAuthGeoAndParty.taxAuthPartyId"/> - <set field="creditEntry.roleTypeId" value="TAX_AUTHORITY"/> - </if-not-empty> - <set field="acctgTransEntries[]" from-field="creditEntry" type="Object"/> - </iterate> + <iterate-map key="taxAuthPartyId" value="taxAuthGeoIds" map="taxAuthPartyAndGeos"> + <iterate entry="taxAuthGeoId" list="taxAuthGeoIds"> + <clear-field field="debitEntry"/> + <make-value entity-name="AcctgTransEntry" value-field="debitEntry"/> + <set field="debitEntry.debitCreditFlag" value="D"/> + <set field="debitEntry.organizationPartyId" from-field="invoice.partyIdFrom"/> + <call-class-method method-name="getInvoiceTaxTotalForTaxAuthPartyAndGeo" class-name="org.ofbiz.accounting.invoice.InvoiceWorker" + ret-field="taxAmount"> + <field field="invoice" type="GenericValue"/> + <field field="taxAuthPartyId" type="String"/> + <field field="taxAuthGeoId" type="String"/> + </call-class-method> + <set field="debitEntry.origAmount" from-field="taxAmount"/> + <set field="debitEntry.origCurrencyUomId" from-field="invoice.currencyUomId"/> + <set field="debitEntry.partyId" from-field="taxAuthPartyId"/> + <set field="debitEntry.roleTypeId" value="TAX_AUTHORITY"/> + <set field="acctgTransEntries[]" from-field="debitEntry" type="Object"/> + </iterate> + </iterate-map> + <!-- Another entry for tax not attributed to a taxAuthPartyId --> + <clear-field field="debitEntry"/> + <make-value entity-name="AcctgTransEntry" value-field="debitEntry"/> + <set field="debitEntry.debitCreditFlag" value="D"/> + <set field="debitEntry.organizationPartyId" from-field="invoice.partyIdFrom"/> + <call-class-method method-name="getInvoiceUnattributedTaxTotal" class-name="org.ofbiz.accounting.invoice.InvoiceWorker" + ret-field="taxAmount"> + <field field="invoice" type="GenericValue"/> + </call-class-method> + <set field="debitEntry.origAmount" from-field="taxAmount"/> + <set field="debitEntry.origCurrencyUomId" from-field="invoice.currencyUomId"/> + <set field="acctgTransEntries[]" from-field="debitEntry" type="Object"/> <!-- Credit --> <make-value entity-name="AcctgTransEntry" value-field="creditEntry"/> @@ -1889,25 +1905,41 @@ </iterate> <!-- credit entry for SALES_TAX--> - <call-class-method method-name="getInvoiceTaxByTaxAuthGeoAndParty" class-name="org.ofbiz.accounting.invoice.InvoiceWorker" - ret-field="invoiceTaxByTaxAuthGeoAndPartyResult"> + <call-class-method method-name="getInvoiceTaxAuthPartyAndGeos" class-name="org.ofbiz.accounting.invoice.InvoiceWorker" + ret-field="taxAuthPartyAndGeos"> <field field="invoice" type="org.ofbiz.entity.GenericValue"/> </call-class-method> - <set field="taxByTaxAuthGeoAndPartyList" from-field="invoiceTaxByTaxAuthGeoAndPartyResult.taxByTaxAuthGeoAndPartyList"/> - <set field="invoiceTaxTotal" from-field="invoiceTaxByTaxAuthGeoAndPartyResult.taxGrandTotal"/> - <iterate list="taxByTaxAuthGeoAndPartyList" entry="taxByTaxAuthGeoAndParty"> - <clear-field field="creditEntry"/> - <make-value entity-name="AcctgTransEntry" value-field="creditEntry"/> - <set field="creditEntry.debitCreditFlag" value="C"/> - <set field="creditEntry.organizationPartyId" from-field="invoice.partyIdFrom"/> - <set field="creditEntry.origAmount" from-field="taxByTaxAuthGeoAndParty.totalAmount"/> - <set field="creditEntry.origCurrencyUomId" from-field="invoice.currencyUomId"/> - <if-not-empty field="taxByTaxAuthGeoAndParty.taxAuthPartyId"> - <set field="creditEntry.partyId" from-field="taxByTaxAuthGeoAndParty.taxAuthPartyId"/> + <iterate-map key="taxAuthPartyId" value="taxAuthGeoIds" map="taxAuthPartyAndGeos"> + <iterate entry="taxAuthGeoId" list="taxAuthGeoIds"> + <clear-field field="creditEntry"/> + <make-value entity-name="AcctgTransEntry" value-field="creditEntry"/> + <set field="creditEntry.debitCreditFlag" value="C"/> + <set field="creditEntry.organizationPartyId" from-field="invoice.partyIdFrom"/> + <call-class-method method-name="getInvoiceTaxTotalForTaxAuthPartyAndGeo" class-name="org.ofbiz.accounting.invoice.InvoiceWorker" + ret-field="taxAmount"> + <field field="invoice" type="GenericValue"/> + <field field="taxAuthPartyId" type="String"/> + <field field="taxAuthGeoId" type="String"/> + </call-class-method> + <set field="creditEntry.origAmount" from-field="taxAmount"/> + <set field="creditEntry.origCurrencyUomId" from-field="invoice.currencyUomId"/> + <set field="creditEntry.partyId" from-field="taxAuthPartyId"/> <set field="creditEntry.roleTypeId" value="TAX_AUTHORITY"/> - </if-not-empty> - <set field="acctgTransEntries[]" from-field="creditEntry" type="Object"/> - </iterate> + <set field="acctgTransEntries[]" from-field="creditEntry" type="Object"/> + </iterate> + </iterate-map> + <!-- Another entry for tax not attributed to a taxAuthPartyId --> + <clear-field field="creditEntry"/> + <make-value entity-name="AcctgTransEntry" value-field="creditEntry"/> + <set field="creditEntry.debitCreditFlag" value="C"/> + <set field="creditEntry.organizationPartyId" from-field="invoice.partyIdFrom"/> + <call-class-method method-name="getInvoiceUnattributedTaxTotal" class-name="org.ofbiz.accounting.invoice.InvoiceWorker" + ret-field="taxAmount"> + <field field="invoice" type="GenericValue"/> + </call-class-method> + <set field="creditEntry.origAmount" from-field="taxAmount"/> + <set field="creditEntry.origCurrencyUomId" from-field="invoice.currencyUomId"/> + <set field="acctgTransEntries[]" from-field="creditEntry" type="Object"/> <!-- Debit --> <make-value entity-name="AcctgTransEntry" value-field="debitEntry"/> Modified: ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceWorker.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceWorker.java?rev=901070&r1=901069&r2=901070&view=diff ============================================================================== --- ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceWorker.java (original) +++ ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceWorker.java Wed Jan 20 05:53:22 2010 @@ -23,9 +23,11 @@ import java.sql.Timestamp; import java.util.List; import java.util.Map; +import java.util.Set; import javolution.util.FastList; import javolution.util.FastMap; +import javolution.util.FastSet; import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.UtilDateTime; @@ -102,7 +104,11 @@ if (quantity == null) { quantity = BigDecimal.ONE; } - return quantity.multiply(invoiceItem.getBigDecimal("amount")).setScale(decimals, rounding); + 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. */ @@ -116,35 +122,16 @@ } public static BigDecimal getInvoiceTaxTotal(GenericValue invoice) { - BigDecimal invoiceTaxTotal = ZERO; - BigDecimal ONE = BigDecimal.ONE; - - if (invoice == null) - throw new IllegalArgumentException("The invoiceId passed does not match an existing invoice"); - List<GenericValue> invoiceTaxItems = null; - try { - Delegator delegator = invoice.getDelegator(); - EntityConditionList<EntityExpr> condition = EntityCondition.makeCondition(UtilMisc.toList( - EntityCondition.makeCondition("invoiceId", invoice.getString("invoiceId")), - EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.IN, getTaxableInvoiceItemTypeIds(delegator))), - EntityOperator.AND); - invoiceTaxItems = delegator.findList("InvoiceItem", condition, null, null, null, false); - } catch (GenericEntityException e) { - Debug.logError(e, "Trouble getting InvoiceItem list", module); - } - if (invoiceTaxItems != null) { - for (GenericValue invoiceItem : invoiceTaxItems) { - BigDecimal amount = invoiceItem.getBigDecimal("amount"); - BigDecimal quantity = invoiceItem.getBigDecimal("quantity"); - if (amount == null) - amount = ZERO; - if (quantity == null) - quantity = ONE; - invoiceTaxTotal = invoiceTaxTotal.add(amount.multiply(quantity)).setScale(decimals + 1, rounding); + 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)); } } - return invoiceTaxTotal.setScale(decimals, rounding); - + taxTotal = taxTotal.add(InvoiceWorker.getInvoiceUnattributedTaxTotal(invoice)); + return taxTotal; } public static BigDecimal getInvoiceNoTaxTotal(GenericValue invoice) { @@ -172,35 +159,21 @@ public static BigDecimal getInvoiceTotal(GenericValue invoice, Boolean actualCurrency) { BigDecimal invoiceTotal = ZERO; BigDecimal invoiceTaxTotal = ZERO; - Map<String, Object> invoiceTaxByTaxAuthGeoAndPartyResult = getInvoiceTaxByTaxAuthGeoAndParty(invoice); - invoiceTaxTotal = (BigDecimal) invoiceTaxByTaxAuthGeoAndPartyResult.get("taxGrandTotal"); + invoiceTaxTotal = InvoiceWorker.getInvoiceTaxTotal(invoice); List<GenericValue> invoiceItems = null; try { invoiceItems = invoice.getRelated("InvoiceItem"); - if ("SALES_INVOICE".equals(invoice.getString("invoiceTypeId"))) { - invoiceItems = EntityUtil.filterByAnd( - invoiceItems, UtilMisc.toList( - EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.NOT_EQUAL, "INV_SALES_TAX"), - EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.NOT_EQUAL, "ITM_SALES_TAX"))); - } else if (("PURCHASE_INVOICE".equals(invoice.getString("invoiceTypeId")))) { - invoiceItems = EntityUtil.filterByAnd( - invoiceItems, UtilMisc.toList( - EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.NOT_EQUAL, "PINV_SALES_TAX"), - EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.NOT_EQUAL, "PITM_SALES_TAX"))); - } + 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) { - BigDecimal amount = invoiceItem.getBigDecimal("amount"); - BigDecimal quantity = invoiceItem.getBigDecimal("quantity"); - if (amount == null) - amount = ZERO; - if (quantity == null) - quantity = BigDecimal.ONE; - invoiceTotal = invoiceTotal.add( amount.multiply(quantity)).setScale(decimals,rounding); + invoiceTotal = invoiceTotal.add(getInvoiceItemTotal(invoiceItem)).setScale(decimals,rounding); } } invoiceTotal = invoiceTotal.add(invoiceTaxTotal).setScale(decimals, rounding); @@ -596,6 +569,7 @@ * @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 = FastList.newInstance(); @@ -651,4 +625,116 @@ 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 = FastMap.newInstance(); + + if (invoice == null) + throw new IllegalArgumentException("Invoice cannot be null."); + List<GenericValue> invoiceTaxItems = null; + try { + Delegator delegator = invoice.getDelegator(); + EntityConditionList<EntityExpr> condition = EntityCondition.makeCondition(UtilMisc.toList( + EntityCondition.makeCondition("invoiceId", invoice.getString("invoiceId")), + EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.IN, getTaxableInvoiceItemTypeIds(delegator))), + EntityOperator.AND); + invoiceTaxItems = delegator.findList("InvoiceItem", condition, null, null, null, false); + } 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 = FastSet.newInstance(); + 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(); + EntityConditionList<EntityExpr> condition = EntityCondition.makeCondition(UtilMisc.toList( + EntityCondition.makeCondition("invoiceId", invoice.getString("invoiceId")), + EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.IN, getTaxableInvoiceItemTypeIds(delegator)), + EntityCondition.makeCondition("taxAuthPartyId", taxAuthPartyId), + EntityCondition.makeCondition("taxAuthGeoId", taxAuthGeoId)), + EntityOperator.AND); + invoiceTaxItems = delegator.findList("InvoiceItem", condition, null, null, null, false); + } 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 + */ + public static BigDecimal getInvoiceUnattributedTaxTotal(GenericValue invoice) { + List<GenericValue> invoiceTaxItems = null; + try { + Delegator delegator = invoice.getDelegator(); + EntityConditionList<EntityExpr> condition = EntityCondition.makeCondition(UtilMisc.toList( + EntityCondition.makeCondition("invoiceId", invoice.getString("invoiceId")), + EntityCondition.makeCondition("invoiceItemTypeId", EntityOperator.IN, getTaxableInvoiceItemTypeIds(delegator)), + EntityCondition.makeCondition("taxAuthPartyId", null)), + EntityOperator.AND); + invoiceTaxItems = delegator.findList("InvoiceItem", condition, null, null, null, false); + } 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); + } } |
| Free forum by Nabble | Edit this page |
