svn commit: r901070 - in /ofbiz/trunk/applications/accounting: script/org/ofbiz/accounting/ledger/GeneralLedgerServices.xml src/org/ofbiz/accounting/invoice/InvoiceWorker.java

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r901070 - in /ofbiz/trunk/applications/accounting: script/org/ofbiz/accounting/ledger/GeneralLedgerServices.xml src/org/ofbiz/accounting/invoice/InvoiceWorker.java

lektran
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);
+    }
 }