svn commit: r1042542 - in /ofbiz/trunk/applications: accounting/src/org/ofbiz/accounting/tax/ order/data/ order/entitydef/ order/src/org/ofbiz/order/order/ product/entitydef/ product/script/org/ofbiz/product/price/ product/servicedef/

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

svn commit: r1042542 - in /ofbiz/trunk/applications: accounting/src/org/ofbiz/accounting/tax/ order/data/ order/entitydef/ order/src/org/ofbiz/order/order/ product/entitydef/ product/script/org/ofbiz/product/price/ product/servicedef/

jonesde
Author: jonesde
Date: Mon Dec  6 08:05:44 2010
New Revision: 1042542

URL: http://svn.apache.org/viewvc?rev=1042542&view=rev
Log:
Implemented alternative way of saving ProductPrices with tax included in the price, and then calculating VAT tax as an exclusive instead of inclusive amount that goes on a new field on OrderAdjustment; also added a method to OrderReadHelper to get tax for display; there are various changes to service descriptions and entity fields to describe these changes

Modified:
    ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/tax/TaxAuthorityServices.java
    ofbiz/trunk/applications/order/data/OrderTypeData.xml
    ofbiz/trunk/applications/order/entitydef/entitymodel.xml
    ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java
    ofbiz/trunk/applications/product/entitydef/entitymodel.xml
    ofbiz/trunk/applications/product/script/org/ofbiz/product/price/PriceServices.xml
    ofbiz/trunk/applications/product/servicedef/services.xml

Modified: ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/tax/TaxAuthorityServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/tax/TaxAuthorityServices.java?rev=1042542&r1=1042541&r2=1042542&view=diff
==============================================================================
--- ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/tax/TaxAuthorityServices.java (original)
+++ ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/tax/TaxAuthorityServices.java Mon Dec  6 08:05:44 2010
@@ -391,11 +391,38 @@ public class TaxAuthorityServices {
                     // TODO: what to do if no TaxAuthorityGlAccount found? Use some default, or is that done elsewhere later on?
                 }
 
+                GenericValue productPrice = null;
+                if (product != null && taxAuthPartyId != null && taxAuthGeoId != null) {
+                    // find a ProductPrice for the productId and taxAuth* valxues, and see if it has a priceWithTax value
+                    Map<String, String> priceFindMap = UtilMisc.toMap("productId", product.getString("productId"),
+                            "taxAuthPartyId", taxAuthPartyId, "taxAuthGeoId", taxAuthGeoId,
+                            "productPriceTypeId", "DEFAULT_PRICE", "productPricePurposeId", "PURCHASE");
+                    List<GenericValue> productPriceList = delegator.findByAnd("ProductPrice", priceFindMap, UtilMisc.toList("-fromDate"));
+                    productPriceList = EntityUtil.filterByDate(productPriceList, true);
+                    productPrice = (productPriceList != null && productPriceList.size() > 0) ? productPriceList.get(0): null;
+                    //Debug.logInfo("=================== productId=" + product.getString("productId"), module);
+                    //Debug.logInfo("=================== productPrice=" + productPrice, module);
+                    
+                }
+
                 GenericValue taxAdjValue = delegator.makeValue("OrderAdjustment");
-                taxAdjValue.set("taxAuthorityRateSeqId", taxAuthorityRateProduct.getString("taxAuthorityRateSeqId"));
-                taxAdjValue.set("amount", taxAmount);
+
+                if ("Y".equals(productPrice.getString("taxInPrice"))) {
+                    // tax is in the price already, so we want the adjustment to be a VAT_TAX adjustment to be subtracted instead of a SALES_TAX adjustment to be added
+                    taxAdjValue.set("orderAdjustmentTypeId", "VAT_TAX");
+
+                    // the amount will be different because we want to figure out how much of the price was tax, and not how much tax needs to be added
+                    // the formula is: taxAmount = priceWithTax - (priceWithTax/(1+taxPercentage/100))
+                    BigDecimal taxAmountIncluded = itemAmount.subtract(itemAmount.divide(BigDecimal.ONE.add(taxRate.divide(PERCENT_SCALE, 4, BigDecimal.ROUND_HALF_UP)), 3, BigDecimal.ROUND_HALF_UP));
+                    taxAdjValue.set("amountAlreadyIncluded", taxAmountIncluded);
+                    taxAdjValue.set("amount", BigDecimal.ZERO);
+                } else {
+                    taxAdjValue.set("orderAdjustmentTypeId", "SALES_TAX");
+                    taxAdjValue.set("amount", taxAmount);
+                }
+                
                 taxAdjValue.set("sourcePercentage", taxRate);
-                taxAdjValue.set("orderAdjustmentTypeId", "SALES_TAX");
+                taxAdjValue.set("taxAuthorityRateSeqId", taxAuthorityRateProduct.getString("taxAuthorityRateSeqId"));
                 // the primary Geo should be the main jurisdiction that the tax is for, and the secondary would just be to define a parent or wrapping jurisdiction of the primary
                 taxAdjValue.set("primaryGeoId", taxAuthGeoId);
                 taxAdjValue.set("comments", taxAuthorityRateProduct.getString("description"));
@@ -421,62 +448,50 @@ public class TaxAuthorityServices {
                 }
 
                 adjustments.add(taxAdjValue);
-                
-                // for VAT taxes if the calculated total item price plus calculated taxes is different from what would be
-                // expected based on the original entered price with taxes (if the price was entered this way), then create
-                // an adjustment that corrects for the difference, and this correction will be effectively subtracted from the
-                // price and not from the tax (the tax is meant to be calculated based on Tax Authority rules and so should
-                // not be shorted)
-                
-                // TODO get this to work with price rules changing the default price (right now only works where itemPrice==defaultPrice
-                // TODO (don't think this is needed, but just to keep it in mind): get this to work with multiple VAT tax authorities instead of just one (right now will get incorrect totals if there are multiple taxes included in the price)
-                // TODO add constraint to ProductPrice lookup by any productStoreGroupId associated with the current productStore
-                
-                //Debug.logInfo("=================== itemQuantity=" + itemQuantity, module);
-                //Debug.logInfo("=================== taxAuthPartyId=" + taxAuthPartyId, module);
-                //Debug.logInfo("=================== taxAuthGeoId=" + taxAuthGeoId, module);
-                if (product != null && itemQuantity != null && taxAuthPartyId != null && taxAuthGeoId != null) {
-                    // find a ProductPrice for the productId and taxAuth* valxues, and see if it has a priceWithTax value
-                    Map<String, String> priceFindMap = UtilMisc.toMap("productId", product.getString("productId"),
-                            "taxAuthPartyId", taxAuthPartyId, "taxAuthGeoId", taxAuthGeoId,
-                            "productPriceTypeId", "DEFAULT_PRICE", "productPricePurposeId", "PURCHASE");
-                    List<GenericValue> productPriceList = delegator.findByAnd("ProductPrice", priceFindMap, UtilMisc.toList("-fromDate"));
-                    productPriceList = EntityUtil.filterByDate(productPriceList, true);
-                    GenericValue productPrice = (productPriceList != null && productPriceList.size() > 0) ? productPriceList.get(0): null;
-                    //Debug.logInfo("=================== productId=" + product.getString("productId"), module);
-                    //Debug.logInfo("=================== productPrice=" + productPrice, module);
+
+                if (productPrice != null && itemQuantity != null &&
+                        productPrice.getBigDecimal("priceWithTax") != null &&
+                        !"Y".equals(productPrice.getString("taxInPrice"))) {
+                    BigDecimal priceWithTax = productPrice.getBigDecimal("priceWithTax");
+                    BigDecimal price = productPrice.getBigDecimal("price");
+                    BigDecimal baseSubtotal = price.multiply(itemQuantity);
+                    BigDecimal baseTaxAmount = (baseSubtotal.multiply(taxRate)).divide(PERCENT_SCALE, salestaxCalcDecimals, salestaxRounding);
+                    //Debug.logInfo("=================== priceWithTax=" + priceWithTax, module);
+                    //Debug.logInfo("=================== enteredTotalPriceWithTax=" + enteredTotalPriceWithTax, module);
+                    //Debug.logInfo("=================== calcedTotalPriceWithTax=" + calcedTotalPriceWithTax, module);
+                    
+                    // tax is not already in price so we want to add it in, but this is a VAT situation so adjust to make it as accurate as possible
+
+                    // for VAT taxes if the calculated total item price plus calculated taxes is different from what would be
+                    // expected based on the original entered price with taxes (if the price was entered this way), then create
+                    // an adjustment that corrects for the difference, and this correction will be effectively subtracted from the
+                    // price and not from the tax (the tax is meant to be calculated based on Tax Authority rules and so should
+                    // not be shorted)
+                    
+                    // TODO (don't think this is needed, but just to keep it in mind): get this to work with multiple VAT tax authorities instead of just one (right now will get incorrect totals if there are multiple taxes included in the price)
+                    // TODO add constraint to ProductPrice lookup by any productStoreGroupId associated with the current productStore
                     
-                    if (productPrice != null && productPrice.getBigDecimal("priceWithTax") != null) {
-                        BigDecimal priceWithTax = productPrice.getBigDecimal("priceWithTax");
-                        BigDecimal price = productPrice.getBigDecimal("price");
-                        BigDecimal baseSubtotal = price.multiply(itemQuantity);
-                        BigDecimal baseTaxAmount = (baseSubtotal.multiply(taxRate)).divide(PERCENT_SCALE, salestaxCalcDecimals, salestaxRounding);
-                        BigDecimal enteredTotalPriceWithTax = priceWithTax.multiply(itemQuantity);
-                        BigDecimal calcedTotalPriceWithTax = (baseSubtotal).add(baseTaxAmount);
-                        //Debug.logInfo("=================== priceWithTax=" + priceWithTax, module);
-                        //Debug.logInfo("=================== enteredTotalPriceWithTax=" + enteredTotalPriceWithTax, module);
-                        //Debug.logInfo("=================== calcedTotalPriceWithTax=" + calcedTotalPriceWithTax, module);
+                    BigDecimal enteredTotalPriceWithTax = priceWithTax.multiply(itemQuantity);
+                    BigDecimal calcedTotalPriceWithTax = (baseSubtotal).add(baseTaxAmount);
+                    if (!enteredTotalPriceWithTax.equals(calcedTotalPriceWithTax)) {
+                        // if the calced amount is higher than the entered amount we want the value to be negative
+                        //     to get it down to match the entered amount
+                        // so, subtract the calced amount from the entered amount (ie: correction = entered - calced)
+                        BigDecimal correctionAmount = enteredTotalPriceWithTax.subtract(calcedTotalPriceWithTax);
+                        //Debug.logInfo("=================== correctionAmount=" + correctionAmount, module);
                         
-                        if (!enteredTotalPriceWithTax.equals(calcedTotalPriceWithTax)) {
-                            // if the calced amount is higher than the entered amount we want the value to be negative
-                            //     to get it down to match the entered amount
-                            // so, subtract the calced amount from the entered amount (ie: correction = entered - calced)
-                            BigDecimal correctionAmount = enteredTotalPriceWithTax.subtract(calcedTotalPriceWithTax);
-                            //Debug.logInfo("=================== correctionAmount=" + correctionAmount, module);
-                            
-                            GenericValue correctionAdjValue = delegator.makeValue("OrderAdjustment");
-                            correctionAdjValue.set("taxAuthorityRateSeqId", taxAuthorityRateProduct.getString("taxAuthorityRateSeqId"));
-                            correctionAdjValue.set("amount", correctionAmount);
-                            // don't set this, causes a doubling of the tax rate because calling code adds up all tax rates: correctionAdjValue.set("sourcePercentage", taxRate);
-                            correctionAdjValue.set("orderAdjustmentTypeId", "VAT_PRICE_CORRECT");
-                            // the primary Geo should be the main jurisdiction that the tax is for, and the secondary would just be to define a parent or wrapping jurisdiction of the primary
-                            correctionAdjValue.set("primaryGeoId", taxAuthGeoId);
-                            correctionAdjValue.set("comments", taxAuthorityRateProduct.getString("description"));
-                            if (taxAuthPartyId != null) correctionAdjValue.set("taxAuthPartyId", taxAuthPartyId);
-                            if (taxAuthGlAccountId != null) correctionAdjValue.set("overrideGlAccountId", taxAuthGlAccountId);
-                            if (taxAuthGeoId != null) correctionAdjValue.set("taxAuthGeoId", taxAuthGeoId);
-                            adjustments.add(correctionAdjValue);
-                        }
+                        GenericValue correctionAdjValue = delegator.makeValue("OrderAdjustment");
+                        correctionAdjValue.set("taxAuthorityRateSeqId", taxAuthorityRateProduct.getString("taxAuthorityRateSeqId"));
+                        correctionAdjValue.set("amount", correctionAmount);
+                        // don't set this, causes a doubling of the tax rate because calling code adds up all tax rates: correctionAdjValue.set("sourcePercentage", taxRate);
+                        correctionAdjValue.set("orderAdjustmentTypeId", "VAT_PRICE_CORRECT");
+                        // the primary Geo should be the main jurisdiction that the tax is for, and the secondary would just be to define a parent or wrapping jurisdiction of the primary
+                        correctionAdjValue.set("primaryGeoId", taxAuthGeoId);
+                        correctionAdjValue.set("comments", taxAuthorityRateProduct.getString("description"));
+                        if (taxAuthPartyId != null) correctionAdjValue.set("taxAuthPartyId", taxAuthPartyId);
+                        if (taxAuthGlAccountId != null) correctionAdjValue.set("overrideGlAccountId", taxAuthGlAccountId);
+                        if (taxAuthGeoId != null) correctionAdjValue.set("taxAuthGeoId", taxAuthGeoId);
+                        adjustments.add(correctionAdjValue);
                     }
                 }
             }

Modified: ofbiz/trunk/applications/order/data/OrderTypeData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/data/OrderTypeData.xml?rev=1042542&r1=1042541&r2=1042542&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/data/OrderTypeData.xml (original)
+++ ofbiz/trunk/applications/order/data/OrderTypeData.xml Mon Dec  6 08:05:44 2010
@@ -42,6 +42,7 @@ under the License.
     <OrderAdjustmentType description="Fee" hasTable="N" orderAdjustmentTypeId="FEE" parentTypeId=""/>
     <OrderAdjustmentType description="Miscellaneous Charges" hasTable="N" orderAdjustmentTypeId="MISCELLANEOUS_CHARGE" parentTypeId=""/>
     <OrderAdjustmentType description="Sales Tax" hasTable="N" orderAdjustmentTypeId="SALES_TAX" parentTypeId=""/>
+    <OrderAdjustmentType description="VAT Tax (not added to totals)" hasTable="N" orderAdjustmentTypeId="VAT_TAX" parentTypeId=""/>
     <OrderAdjustmentType description="VAT Price Correction" hasTable="N" orderAdjustmentTypeId="VAT_PRICE_CORRECT" parentTypeId=""/>
     <OrderAdjustmentType description="Shipping and Handling" hasTable="N" orderAdjustmentTypeId="SHIPPING_CHARGES" parentTypeId=""/>
     <OrderAdjustmentType description="Surcharge" hasTable="N" orderAdjustmentTypeId="SURCHARGE_ADJUSTMENT" parentTypeId=""/>

Modified: ofbiz/trunk/applications/order/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/entitydef/entitymodel.xml?rev=1042542&r1=1042541&r2=1042542&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/entitydef/entitymodel.xml (original)
+++ ofbiz/trunk/applications/order/entitydef/entitymodel.xml Mon Dec  6 08:05:44 2010
@@ -59,6 +59,7 @@ under the License.
       <field name="description" type="description"></field>
       <field name="amount" type="currency-precise"></field>
       <field name="recurringAmount" type="currency-precise"></field>
+      <field name="amountAlreadyIncluded" type="currency-precise"><description>The amount here is already represented in the price, such as VAT taxes.</description></field>
       <field name="productPromoId" type="id"></field>
       <field name="productPromoRuleId" type="id"></field>
       <field name="productPromoActionSeqId" type="id"></field>

Modified: ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java?rev=1042542&r1=1042541&r2=1042542&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java (original)
+++ ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java Mon Dec  6 08:05:44 2010
@@ -2920,4 +2920,62 @@ public class OrderReadHelper {
        result.put("taxGrandTotal", taxGrandTotal);
        return result;
    }
+
+   public static Map<String, Object> getOrderTaxByTaxAuthGeoAndPartyForDisplay(List<GenericValue> orderAdjustmentsOriginal) {
+       BigDecimal taxGrandTotal = BigDecimal.ZERO;
+       List<Map<String, Object>> taxByTaxAuthGeoAndPartyList = FastList.newInstance();
+       List<GenericValue> orderAdjustmentsToUse = FastList.newInstance();
+       if (UtilValidate.isNotEmpty(orderAdjustmentsOriginal)) {
+           // get orderAdjustment where orderAdjustmentTypeId is SALES_TAX.
+           orderAdjustmentsToUse.addAll(EntityUtil.filterByAnd(orderAdjustmentsOriginal, UtilMisc.toMap("orderAdjustmentTypeId", "SALES_TAX")));
+           orderAdjustmentsToUse.addAll(EntityUtil.filterByAnd(orderAdjustmentsOriginal, UtilMisc.toMap("orderAdjustmentTypeId", "VAT_TAX")));
+           orderAdjustmentsToUse = EntityUtil.orderBy(orderAdjustmentsToUse, UtilMisc.toList("taxAuthGeoId","taxAuthPartyId"));
+
+           // get the list of all distinct taxAuthGeoId and taxAuthPartyId. It is for getting the number of taxAuthGeo and taxAuthPartyId in adjustments.
+           List<String> distinctTaxAuthGeoIdList = EntityUtil.getFieldListFromEntityList(orderAdjustmentsToUse, "taxAuthGeoId", true);
+           List<String> distinctTaxAuthPartyIdList = EntityUtil.getFieldListFromEntityList(orderAdjustmentsToUse, "taxAuthPartyId", true);
+
+           // Keep a list of amount that have been added to make sure none are missed (if taxAuth* information is missing)
+           List<GenericValue> processedAdjustments = FastList.newInstance();
+           // For each taxAuthGeoId get and add amount from orderAdjustment
+           for (String taxAuthGeoId : distinctTaxAuthGeoIdList) {
+               for (String taxAuthPartyId : distinctTaxAuthPartyIdList) {
+                   //get all records for orderAdjustments filtered by taxAuthGeoId and taxAurhPartyId
+                   List<GenericValue> orderAdjByTaxAuthGeoAndPartyIds = EntityUtil.filterByAnd(orderAdjustmentsToUse, UtilMisc.toMap("taxAuthGeoId", taxAuthGeoId, "taxAuthPartyId", taxAuthPartyId));
+                   if (UtilValidate.isNotEmpty(orderAdjByTaxAuthGeoAndPartyIds)) {
+                       BigDecimal totalAmount = BigDecimal.ZERO;
+                       //Now for each orderAdjustment record get and add amount.
+                       for (GenericValue orderAdjustment : orderAdjByTaxAuthGeoAndPartyIds) {
+                           BigDecimal amount = orderAdjustment.getBigDecimal("amount");
+                           if (amount != null) {
+                               totalAmount = totalAmount.add(amount);
+                           }
+                           if ("VAT_TAX".equals(orderAdjustment.getString("orderAdjustmentTypeId")) &&
+                                   orderAdjustment.get("amountAlreadyIncluded") != null) {
+                               // this is the only case where the VAT_TAX amountAlreadyIncluded should be added in, and should just be for display and not to calculate the order grandTotal
+                               totalAmount = totalAmount.add(orderAdjustment.getBigDecimal("amountAlreadyIncluded"));
+                           }
+                           totalAmount = totalAmount.setScale(taxCalcScale, taxRounding);
+                           processedAdjustments.add(orderAdjustment);
+                       }
+                       totalAmount = totalAmount.setScale(taxFinalScale, taxRounding);
+                       taxByTaxAuthGeoAndPartyList.add(UtilMisc.<String, Object>toMap("taxAuthPartyId", taxAuthPartyId, "taxAuthGeoId", taxAuthGeoId, "totalAmount", totalAmount));
+                       taxGrandTotal = taxGrandTotal.add(totalAmount);
+                   }
+               }
+           }
+           // Process any adjustments that got missed
+           List<GenericValue> missedAdjustments = FastList.newInstance();
+           missedAdjustments.addAll(orderAdjustmentsToUse);
+           missedAdjustments.removeAll(processedAdjustments);
+           for (GenericValue orderAdjustment : missedAdjustments) {
+               taxGrandTotal = taxGrandTotal.add(orderAdjustment.getBigDecimal("amount").setScale(taxCalcScale, taxRounding));
+           }
+           taxGrandTotal = taxGrandTotal.setScale(taxFinalScale, taxRounding);
+       }
+       Map<String, Object> result = FastMap.newInstance();
+       result.put("taxByTaxAuthGeoAndPartyList", taxByTaxAuthGeoAndPartyList);
+       result.put("taxGrandTotal", taxGrandTotal);
+       return result;
+   }
 }

Modified: ofbiz/trunk/applications/product/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/entitydef/entitymodel.xml?rev=1042542&r1=1042541&r2=1042542&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/entitydef/entitymodel.xml (original)
+++ ofbiz/trunk/applications/product/entitydef/entitymodel.xml Mon Dec  6 08:05:44 2010
@@ -2375,11 +2375,13 @@ under the License.
       <field name="price" type="currency-precise"></field>
       <field name="termUomId" type="id"><description>Mainly used for recurring and usage prices to specify a time/freq measure, or a usage unit measure (bits, minutes, etc)</description></field>
       <field name="customPriceCalcService" type="id"><description>Points to a CustomMethod used to specify a service for the calculation of the unit price of the product (NOTE: a better name for this field might be priceCalcCustomMethodId)</description></field>
-      <field name="priceWithTax" type="currency-precise"/>
+      <field name="priceWithoutTax" type="currency-precise"><description>Always without tax if populated, regardless of if price does or does not include tax.</description></field>
+      <field name="priceWithTax" type="currency-precise"><description>Always with tax if populated, regardless of if price does or does not include tax.</description></field>
       <field name="taxAmount" type="currency-precise"/>
       <field name="taxPercentage" type="fixed-point"/>
       <field name="taxAuthPartyId" type="id-ne"/>
       <field name="taxAuthGeoId" type="id-ne"/>
+      <field name="taxInPrice" type="indicator"><description>If Y the price field has tax included for the given taxAuthPartyId/taxAuthGeoId at the taxPercentage.</description></field>
       <field name="createdDate" type="date-time"></field>
       <field name="createdByUserLogin" type="id-vlong"></field>
       <field name="lastModifiedDate" type="date-time"></field>

Modified: ofbiz/trunk/applications/product/script/org/ofbiz/product/price/PriceServices.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/script/org/ofbiz/product/price/PriceServices.xml?rev=1042542&r1=1042541&r2=1042542&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/script/org/ofbiz/product/price/PriceServices.xml (original)
+++ ofbiz/trunk/applications/product/script/org/ofbiz/product/price/PriceServices.xml Mon Dec  6 08:05:44 2010
@@ -106,6 +106,7 @@ under the License.
             </condition>
             <then>
                 <set field="parameters.priceWithTax" from-field="parameters.price"/>
+                
                 <!-- if taxPercentage not passed in look it up based on taxAuthGeoId and taxAuthPartyId -->
                 <if-empty field="parameters.taxPercentage">
                     <!-- we only have basic data to constrain by here, so assume that if it is a VAT tax setup it should be pretty simple -->
@@ -127,6 +128,7 @@ under the License.
                     <check-errors/>
                 </if-empty>
                 
+                <!-- in short the formula is: taxAmount = priceWithTax - (priceWithTax/(1+taxPercentage/100)) -->
                 <calculate field="parameters.taxAmount" type="BigDecimal" decimal-scale="3" rounding-mode="HalfUp">
                     <calcop operator="subtract">
                         <calcop operator="get" field="parameters.priceWithTax"/>
@@ -142,12 +144,23 @@ under the License.
                         </calcop>
                     </calcop>
                 </calculate>
-                <calculate field="parameters.price" type="BigDecimal" decimal-scale="3" rounding-mode="HalfUp">
+                
+                <calculate field="parameters.priceWithoutTax" type="BigDecimal" decimal-scale="3" rounding-mode="HalfUp">
                     <calcop operator="subtract">
                         <calcop operator="get" field="parameters.priceWithTax"/>
                         <calcop operator="get" field="parameters.taxAmount"></calcop>
                     </calcop>
                 </calculate>
+                
+                <if-compare field="parameters.taxInPrice" operator="equals" value="Y">
+                    <!-- the price passed in has tax included, and we want to store it with tax included -->
+                    <set field="parameters.price" from-field="parameters.priceWithTax"/>
+                    
+                    <else>
+                        <!-- the price passed in has tax included, but we want to store it without tax included -->
+                        <set field="parameters.price" from-field="parameters.priceWithoutTax"/>
+                    </else>
+                </if-compare>
             </then>
         </if>
     </simple-method>

Modified: ofbiz/trunk/applications/product/servicedef/services.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/servicedef/services.xml?rev=1042542&r1=1042541&r2=1042542&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/servicedef/services.xml (original)
+++ ofbiz/trunk/applications/product/servicedef/services.xml Mon Dec  6 08:05:44 2010
@@ -242,12 +242,15 @@ under the License.
         <description>
             Create an ProductPrice.
             Price is always stored without tax.
-            If a taxAuthGeoId and taxAuthPartyId are (or taxAuthCombinedId is) passed in then the price will be considered a price
-                with tax included and the tax will be removed before storing to the database
-                (the priceWithTax, taxAmount, and taxPercentage fields will also be populated).
+            If taxAuthGeoId and taxAuthPartyId are (or taxAuthCombinedId is) passed in then the price will be considered a price
+            with tax included (the priceWithoutTax, priceWithTax, taxAmount, and taxPercentage fields will also be populated).
+            If the taxInPrice field is 'Y' then the price field will be left with the price included (price will be equal to priceWithTax),
+            otherwise tax will be removed from the passed in price and the price field will be equal to the priceWithoutTax field.
+            If taxAuthGeoId or taxAuthPartyId empty, and taxAuthCombinedId is empty, then the taxInPrice field will be ignored.
         </description>
         <auto-attributes include="pk" mode="IN" optional="false"/>
         <auto-attributes include="nonpk" mode="IN" optional="true">
+            <exclude field-name="priceWithoutTax"/>
             <exclude field-name="priceWithTax"/>
             <exclude field-name="taxAmount"/>
             <exclude field-name="createdDate"/>
@@ -264,6 +267,7 @@ under the License.
         <description>Update an ProductPrice</description>
         <auto-attributes include="pk" mode="IN" optional="false"/>
         <auto-attributes include="nonpk" mode="IN" optional="true">
+            <exclude field-name="priceWithoutTax"/>
             <exclude field-name="priceWithTax"/>
             <exclude field-name="taxAmount"/>
             <exclude field-name="createdDate"/>