Price Agreements with customers

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

Price Agreements with customers

Jacopo Cappellato
Hi all,

I've implemented a new price list feature that can be used to set up
price lists for specific customers. It is based on the Agreement data model.
There are only two relevant changes (please see the attached patch)
needed, and I'd really love to get your feedback about them before
committing:

a) added a new price field to the AgreementProductAppl entity
b) added a new optional input parameter, "agreementId", to the
calculateProductPrice service; if the agreementId is passed, and if a
valid price for the product is found in the AgreementProductAppl entity,
this price overrides the default price in the ProductPrice entity.

Here are the steps needed to test this stuff:

* create an agreement (of type sales) between the Company and the customer
* create an agreement item of type price list for a given currency
* associate products to the price list (agreement item) and set the
price there (this is a new field AgreementProductAppl.price)
* when you start a sales order, select the agreement

Jacopo

Index: applications/party/entitydef/entitymodel.xml
===================================================================
--- applications/party/entitydef/entitymodel.xml (revision 427048)
+++ applications/party/entitydef/entitymodel.xml (working copy)
@@ -242,6 +242,7 @@
       <field name="agreementId" type="id-ne"></field>
       <field name="agreementItemSeqId" type="id-ne"></field>
       <field name="productId" type="id-ne"></field>
+      <field name="price" type="currency-precise"></field>
       <prim-key field="agreementId"/>
       <prim-key field="agreementItemSeqId"/>
       <prim-key field="productId"/>
Index: applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
===================================================================
--- applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java (revision 427048)
+++ applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java (working copy)
@@ -876,6 +876,7 @@
                     priceContext.put("prodCatalogId", this.getProdCatalogId());
                     priceContext.put("webSiteId", cart.getWebSiteId());
                     priceContext.put("productStoreId", cart.getProductStoreId());
+                    priceContext.put("agreementId", cart.getAgreementId());
                     Map priceResult = dispatcher.runSync("calculateProductPrice", priceContext);
                     if (ServiceUtil.isError(priceResult)) {
                         throw new CartItemModifyException("There was an error while calculating the price: " + ServiceUtil.getErrorMessage(priceResult));
Index: applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh
===================================================================
--- applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh (revision 427048)
+++ applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh (working copy)
@@ -85,6 +85,7 @@
         priceContext.put("webSiteId", webSiteId);
         priceContext.put("prodCatalogId", catalogId);
         priceContext.put("productStoreId", productStoreId);
+        priceContext.put("agreementId", cart.getAgreementId());
         priceContext.put("checkIncludeVat", "Y");
         priceMap = dispatcher.runSync("calculateProductPrice", priceContext);
 
Index: applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh
===================================================================
--- applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh (revision 427048)
+++ applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh (working copy)
@@ -170,6 +170,7 @@
         priceContext.put("webSiteId", webSiteId);
         priceContext.put("productStoreId", productStoreId);
         priceContext.put("checkIncludeVat", "Y");
+        priceContext.put("agreementId", cart.getAgreementId());
         priceMap = dispatcher.runSync("calculateProductPrice", priceContext);
         context.put("priceMap", priceMap);
     } else {
Index: applications/product/servicedef/services_pricepromo.xml
===================================================================
--- applications/product/servicedef/services_pricepromo.xml (revision 427048)
+++ applications/product/servicedef/services_pricepromo.xml (working copy)
@@ -32,6 +32,7 @@
         <attribute name="partyId" type="String" mode="IN" optional="true"/>
         <attribute name="productStoreId" type="String" mode="IN" optional="true"/>
         <attribute name="productStoreGroupId" type="String" mode="IN" optional="true"/>
+        <attribute name="agreementId" type="String" mode="IN" optional="true"/>
         <attribute name="quantity" type="Double" mode="IN" optional="true"/>
         <attribute name="currencyUomId" type="String" mode="IN" optional="true"/>
         <attribute name="productPricePurposeId" type="String" mode="IN" optional="true"><!-- defaults to PURCHASE --></attribute>
Index: applications/product/src/org/ofbiz/product/price/PriceServices.java
===================================================================
--- applications/product/src/org/ofbiz/product/price/PriceServices.java (revision 427192)
+++ applications/product/src/org/ofbiz/product/price/PriceServices.java (working copy)
@@ -70,6 +70,7 @@
      *   <li>webSiteId
      *   <li>productStoreId
      *   <li>productStoreGroupId
+     *   <li>agreementId
      *   <li>quantity
      *   <li>currencyUomId
      *   <li>checkIncludeVat
@@ -96,6 +97,8 @@
         String webSiteId = (String) context.get("webSiteId");
         String checkIncludeVat = (String) context.get("checkIncludeVat");
 
+        String agreementId = (String) context.get("agreementId");
+
         String productStoreId = (String) context.get("productStoreId");
         String productStoreGroupId = (String) context.get("productStoreGroupId");
         GenericValue productStore = null;
@@ -230,6 +233,23 @@
             if (Debug.infoOn()) Debug.logInfo("There is more than one DEFAULT_PRICE with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + defaultPriceValue.getDouble("price"), module);
         }
 
+        // If there is an agreement between the company and the client, and there is
+        // a price for the product in it, it will override the default price of the
+        // ProductPrice entity.
+        if (UtilValidate.isNotEmpty(agreementId)) {
+            try {
+                List agreementPrices = delegator.findByAnd("AgreementItemAndProductAppl", UtilMisc.toMap("agreementId", agreementId, "productId", productId, "currencyUomId", currencyUomId));
+                GenericValue agreementPriceValue = EntityUtil.getFirst(agreementPrices);
+                if (agreementPriceValue != null && agreementPriceValue.get("price") != null) {
+                    defaultPriceValue = agreementPriceValue;
+                }
+            } catch (GenericEntityException e) {
+                String errMsg = "Error getting agreement info from the database while calculating price" + e.toString();
+                Debug.logError(e, errMsg, module);
+                return ServiceUtil.returnError(errMsg);
+            }
+        }
+
         List competitivePrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "COMPETITIVE_PRICE"));
         GenericValue competitivePriceValue = EntityUtil.getFirst(competitivePrices);
         if (competitivePrices != null && competitivePrices.size() > 1) {
Reply | Threaded
Open this post in threaded view
|

Re: Price Agreements with customers

Jacopo Cappellato
Can I go on and commit the patch?

Jacopo

Jacopo Cappellato wrote:

> Hi all,
>
> I've implemented a new price list feature that can be used to set up
> price lists for specific customers. It is based on the Agreement data
> model.
> There are only two relevant changes (please see the attached patch)
> needed, and I'd really love to get your feedback about them before
> committing:
>
> a) added a new price field to the AgreementProductAppl entity
> b) added a new optional input parameter, "agreementId", to the
> calculateProductPrice service; if the agreementId is passed, and if a
> valid price for the product is found in the AgreementProductAppl entity,
> this price overrides the default price in the ProductPrice entity.
>
> Here are the steps needed to test this stuff:
>
> * create an agreement (of type sales) between the Company and the customer
> * create an agreement item of type price list for a given currency
> * associate products to the price list (agreement item) and set the
> price there (this is a new field AgreementProductAppl.price)
> * when you start a sales order, select the agreement
>
> Jacopo
>
>
> ------------------------------------------------------------------------
>
> Index: applications/party/entitydef/entitymodel.xml
> ===================================================================
> --- applications/party/entitydef/entitymodel.xml (revision 427048)
> +++ applications/party/entitydef/entitymodel.xml (working copy)
> @@ -242,6 +242,7 @@
>        <field name="agreementId" type="id-ne"></field>
>        <field name="agreementItemSeqId" type="id-ne"></field>
>        <field name="productId" type="id-ne"></field>
> +      <field name="price" type="currency-precise"></field>
>        <prim-key field="agreementId"/>
>        <prim-key field="agreementItemSeqId"/>
>        <prim-key field="productId"/>
> Index: applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
> ===================================================================
> --- applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java (revision 427048)
> +++ applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java (working copy)
> @@ -876,6 +876,7 @@
>                      priceContext.put("prodCatalogId", this.getProdCatalogId());
>                      priceContext.put("webSiteId", cart.getWebSiteId());
>                      priceContext.put("productStoreId", cart.getProductStoreId());
> +                    priceContext.put("agreementId", cart.getAgreementId());
>                      Map priceResult = dispatcher.runSync("calculateProductPrice", priceContext);
>                      if (ServiceUtil.isError(priceResult)) {
>                          throw new CartItemModifyException("There was an error while calculating the price: " + ServiceUtil.getErrorMessage(priceResult));
> Index: applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh
> ===================================================================
> --- applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh (revision 427048)
> +++ applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh (working copy)
> @@ -85,6 +85,7 @@
>          priceContext.put("webSiteId", webSiteId);
>          priceContext.put("prodCatalogId", catalogId);
>          priceContext.put("productStoreId", productStoreId);
> +        priceContext.put("agreementId", cart.getAgreementId());
>          priceContext.put("checkIncludeVat", "Y");
>          priceMap = dispatcher.runSync("calculateProductPrice", priceContext);
>  
> Index: applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh
> ===================================================================
> --- applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh (revision 427048)
> +++ applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh (working copy)
> @@ -170,6 +170,7 @@
>          priceContext.put("webSiteId", webSiteId);
>          priceContext.put("productStoreId", productStoreId);
>          priceContext.put("checkIncludeVat", "Y");
> +        priceContext.put("agreementId", cart.getAgreementId());
>          priceMap = dispatcher.runSync("calculateProductPrice", priceContext);
>          context.put("priceMap", priceMap);
>      } else {
> Index: applications/product/servicedef/services_pricepromo.xml
> ===================================================================
> --- applications/product/servicedef/services_pricepromo.xml (revision 427048)
> +++ applications/product/servicedef/services_pricepromo.xml (working copy)
> @@ -32,6 +32,7 @@
>          <attribute name="partyId" type="String" mode="IN" optional="true"/>
>          <attribute name="productStoreId" type="String" mode="IN" optional="true"/>
>          <attribute name="productStoreGroupId" type="String" mode="IN" optional="true"/>
> +        <attribute name="agreementId" type="String" mode="IN" optional="true"/>
>          <attribute name="quantity" type="Double" mode="IN" optional="true"/>
>          <attribute name="currencyUomId" type="String" mode="IN" optional="true"/>
>          <attribute name="productPricePurposeId" type="String" mode="IN" optional="true"><!-- defaults to PURCHASE --></attribute>
> Index: applications/product/src/org/ofbiz/product/price/PriceServices.java
> ===================================================================
> --- applications/product/src/org/ofbiz/product/price/PriceServices.java (revision 427192)
> +++ applications/product/src/org/ofbiz/product/price/PriceServices.java (working copy)
> @@ -70,6 +70,7 @@
>       *   <li>webSiteId
>       *   <li>productStoreId
>       *   <li>productStoreGroupId
> +     *   <li>agreementId
>       *   <li>quantity
>       *   <li>currencyUomId
>       *   <li>checkIncludeVat
> @@ -96,6 +97,8 @@
>          String webSiteId = (String) context.get("webSiteId");
>          String checkIncludeVat = (String) context.get("checkIncludeVat");
>  
> +        String agreementId = (String) context.get("agreementId");
> +
>          String productStoreId = (String) context.get("productStoreId");
>          String productStoreGroupId = (String) context.get("productStoreGroupId");
>          GenericValue productStore = null;
> @@ -230,6 +233,23 @@
>              if (Debug.infoOn()) Debug.logInfo("There is more than one DEFAULT_PRICE with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + defaultPriceValue.getDouble("price"), module);
>          }
>  
> +        // If there is an agreement between the company and the client, and there is
> +        // a price for the product in it, it will override the default price of the
> +        // ProductPrice entity.
> +        if (UtilValidate.isNotEmpty(agreementId)) {
> +            try {
> +                List agreementPrices = delegator.findByAnd("AgreementItemAndProductAppl", UtilMisc.toMap("agreementId", agreementId, "productId", productId, "currencyUomId", currencyUomId));
> +                GenericValue agreementPriceValue = EntityUtil.getFirst(agreementPrices);
> +                if (agreementPriceValue != null && agreementPriceValue.get("price") != null) {
> +                    defaultPriceValue = agreementPriceValue;
> +                }
> +            } catch (GenericEntityException e) {
> +                String errMsg = "Error getting agreement info from the database while calculating price" + e.toString();
> +                Debug.logError(e, errMsg, module);
> +                return ServiceUtil.returnError(errMsg);
> +            }
> +        }
> +
>          List competitivePrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "COMPETITIVE_PRICE"));
>          GenericValue competitivePriceValue = EntityUtil.getFirst(competitivePrices);
>          if (competitivePrices != null && competitivePrices.size() > 1) {

Reply | Threaded
Open this post in threaded view
|

Re: Price Agreements with customers

cjhowe
Can't this already be done using the price rules?
Better screens need to be made, but this functionality
is there with a lot more flexibility.

--- Jacopo Cappellato <[hidden email]> wrote:

> Can I go on and commit the patch?
>
> Jacopo
>
> Jacopo Cappellato wrote:
> > Hi all,
> >
> > I've implemented a new price list feature that can
> be used to set up
> > price lists for specific customers. It is based on
> the Agreement data
> > model.
> > There are only two relevant changes (please see
> the attached patch)
> > needed, and I'd really love to get your feedback
> about them before
> > committing:
> >
> > a) added a new price field to the
> AgreementProductAppl entity
> > b) added a new optional input parameter,
> "agreementId", to the
> > calculateProductPrice service; if the agreementId
> is passed, and if a
> > valid price for the product is found in the
> AgreementProductAppl entity,
> > this price overrides the default price in the
> ProductPrice entity.
> >
> > Here are the steps needed to test this stuff:
> >
> > * create an agreement (of type sales) between the
> Company and the customer
> > * create an agreement item of type price list for
> a given currency
> > * associate products to the price list (agreement
> item) and set the
> > price there (this is a new field
> AgreementProductAppl.price)
> > * when you start a sales order, select the
> agreement
> >
> > Jacopo
> >
> >
> >
>
------------------------------------------------------------------------
> >
> > Index:
> applications/party/entitydef/entitymodel.xml
> >
>
===================================================================

> > --- applications/party/entitydef/entitymodel.xml
> (revision 427048)
> > +++ applications/party/entitydef/entitymodel.xml
> (working copy)
> > @@ -242,6 +242,7 @@
> >        <field name="agreementId"
> type="id-ne"></field>
> >        <field name="agreementItemSeqId"
> type="id-ne"></field>
> >        <field name="productId"
> type="id-ne"></field>
> > +      <field name="price"
> type="currency-precise"></field>
> >        <prim-key field="agreementId"/>
> >        <prim-key field="agreementItemSeqId"/>
> >        <prim-key field="productId"/>
> > Index:
>
applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
> >
>
===================================================================
> > ---
>
applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
> (revision 427048)
> > +++
>
applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java

> (working copy)
> > @@ -876,6 +876,7 @@
> >                    
> priceContext.put("prodCatalogId",
> this.getProdCatalogId());
> >                      priceContext.put("webSiteId",
> cart.getWebSiteId());
> >                    
> priceContext.put("productStoreId",
> cart.getProductStoreId());
> > +                  
> priceContext.put("agreementId",
> cart.getAgreementId());
> >                      Map priceResult =
> dispatcher.runSync("calculateProductPrice",
> priceContext);
> >                      if
> (ServiceUtil.isError(priceResult)) {
> >                          throw new
> CartItemModifyException("There was an error while
> calculating the price: " +
> ServiceUtil.getErrorMessage(priceResult));
> > Index:
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh
> >
>
===================================================================
> > ---
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh
> (revision 427048)
> > +++
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh

> (working copy)
> > @@ -85,6 +85,7 @@
> >          priceContext.put("webSiteId", webSiteId);
> >          priceContext.put("prodCatalogId",
> catalogId);
> >          priceContext.put("productStoreId",
> productStoreId);
> > +        priceContext.put("agreementId",
> cart.getAgreementId());
> >          priceContext.put("checkIncludeVat", "Y");
> >          priceMap =
> dispatcher.runSync("calculateProductPrice",
> priceContext);
> >  
> > Index:
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh
> >
>
===================================================================
> > ---
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh
> (revision 427048)
> > +++
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh

> (working copy)
> > @@ -170,6 +170,7 @@
> >          priceContext.put("webSiteId", webSiteId);
> >          priceContext.put("productStoreId",
> productStoreId);
> >          priceContext.put("checkIncludeVat", "Y");
> > +        priceContext.put("agreementId",
> cart.getAgreementId());
> >          priceMap =
> dispatcher.runSync("calculateProductPrice",
> priceContext);
> >          context.put("priceMap", priceMap);
> >      } else {
> > Index:
>
applications/product/servicedef/services_pricepromo.xml
> >
>
===================================================================
> > ---
>
applications/product/servicedef/services_pricepromo.xml
> (revision 427048)
> > +++
>
applications/product/servicedef/services_pricepromo.xml

> (working copy)
> > @@ -32,6 +32,7 @@
> >          <attribute name="partyId" type="String"
> mode="IN" optional="true"/>
> >          <attribute name="productStoreId"
> type="String" mode="IN" optional="true"/>
> >          <attribute name="productStoreGroupId"
> type="String" mode="IN" optional="true"/>
> > +        <attribute name="agreementId"
> type="String" mode="IN" optional="true"/>
> >          <attribute name="quantity" type="Double"
> mode="IN" optional="true"/>
> >          <attribute name="currencyUomId"
> type="String" mode="IN" optional="true"/>
> >          <attribute name="productPricePurposeId"
> type="String" mode="IN" optional="true"><!--
> defaults to PURCHASE --></attribute>
> > Index:
>
applications/product/src/org/ofbiz/product/price/PriceServices.java
> >
>
===================================================================
> > ---
>
applications/product/src/org/ofbiz/product/price/PriceServices.java
> (revision 427192)
> > +++
>
applications/product/src/org/ofbiz/product/price/PriceServices.java

> (working copy)
> > @@ -70,6 +70,7 @@
> >       *   <li>webSiteId
> >       *   <li>productStoreId
> >       *   <li>productStoreGroupId
> > +     *   <li>agreementId
> >       *   <li>quantity
> >       *   <li>currencyUomId
> >       *   <li>checkIncludeVat
> > @@ -96,6 +97,8 @@
> >          String webSiteId = (String)
> context.get("webSiteId");
> >          String checkIncludeVat = (String)
> context.get("checkIncludeVat");
> >  
> > +        String agreementId = (String)
> context.get("agreementId");
> > +
> >          String productStoreId = (String)
> context.get("productStoreId");
> >          String productStoreGroupId = (String)
> context.get("productStoreGroupId");
>
=== message truncated ===

Reply | Threaded
Open this post in threaded view
|

Re: Price Agreements with customers

Jacopo Cappellato
Hi Chris,

price rules are not bypassed by this new feature.
The agreement price (if available) simply overrides the default price
but if there are price rules that apply they will be used.
I agree with you that you could get the same goal using price rules, but
in my opinion they are not well suited for this use case, i.e. the setup
of a custom price list between a customer and the company.
Using price rules this would involve the creation of a price rule
header, price rule condition and price rule action for each product in
the list.
Also, by using the Agreement data model (that in my opinion is a natural
fit here) it is easier to keep an history of price lists ("price list
2005", "price list 2006/2007" etc...) by using the agreement validity
dates (and the new feature of copying an agreement into a new one).

Jacopo

Chris Howe wrote:

> Can't this already be done using the price rules?
> Better screens need to be made, but this functionality
> is there with a lot more flexibility.
>
> --- Jacopo Cappellato <[hidden email]> wrote:
>
>> Can I go on and commit the patch?
>>
>> Jacopo
>>
>> Jacopo Cappellato wrote:
>>> Hi all,
>>>
>>> I've implemented a new price list feature that can
>> be used to set up
>>> price lists for specific customers. It is based on
>> the Agreement data
>>> model.
>>> There are only two relevant changes (please see
>> the attached patch)
>>> needed, and I'd really love to get your feedback
>> about them before
>>> committing:
>>>
>>> a) added a new price field to the
>> AgreementProductAppl entity
>>> b) added a new optional input parameter,
>> "agreementId", to the
>>> calculateProductPrice service; if the agreementId
>> is passed, and if a
>>> valid price for the product is found in the
>> AgreementProductAppl entity,
>>> this price overrides the default price in the
>> ProductPrice entity.
>>> Here are the steps needed to test this stuff:
>>>
>>> * create an agreement (of type sales) between the
>> Company and the customer
>>> * create an agreement item of type price list for
>> a given currency
>>> * associate products to the price list (agreement
>> item) and set the
>>> price there (this is a new field
>> AgreementProductAppl.price)
>>> * when you start a sales order, select the
>> agreement
>>> Jacopo
>>>
>>>
>>>
> ------------------------------------------------------------------------
>>> Index:
>> applications/party/entitydef/entitymodel.xml
> ===================================================================
>>> --- applications/party/entitydef/entitymodel.xml
>> (revision 427048)
>>> +++ applications/party/entitydef/entitymodel.xml
>> (working copy)
>>> @@ -242,6 +242,7 @@
>>>        <field name="agreementId"
>> type="id-ne"></field>
>>>        <field name="agreementItemSeqId"
>> type="id-ne"></field>
>>>        <field name="productId"
>> type="id-ne"></field>
>>> +      <field name="price"
>> type="currency-precise"></field>
>>>        <prim-key field="agreementId"/>
>>>        <prim-key field="agreementItemSeqId"/>
>>>        <prim-key field="productId"/>
>>> Index:
> applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
> ===================================================================
>>> ---
> applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
>> (revision 427048)
>>> +++
> applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
>> (working copy)
>>> @@ -876,6 +876,7 @@
>>>                    
>> priceContext.put("prodCatalogId",
>> this.getProdCatalogId());
>>>                      priceContext.put("webSiteId",
>> cart.getWebSiteId());
>>>                    
>> priceContext.put("productStoreId",
>> cart.getProductStoreId());
>>> +                  
>> priceContext.put("agreementId",
>> cart.getAgreementId());
>>>                      Map priceResult =
>> dispatcher.runSync("calculateProductPrice",
>> priceContext);
>>>                      if
>> (ServiceUtil.isError(priceResult)) {
>>>                          throw new
>> CartItemModifyException("There was an error while
>> calculating the price: " +
>> ServiceUtil.getErrorMessage(priceResult));
>>> Index:
> applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh
> ===================================================================
>>> ---
> applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh
>> (revision 427048)
>>> +++
> applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh
>> (working copy)
>>> @@ -85,6 +85,7 @@
>>>          priceContext.put("webSiteId", webSiteId);
>>>          priceContext.put("prodCatalogId",
>> catalogId);
>>>          priceContext.put("productStoreId",
>> productStoreId);
>>> +        priceContext.put("agreementId",
>> cart.getAgreementId());
>>>          priceContext.put("checkIncludeVat", "Y");
>>>          priceMap =
>> dispatcher.runSync("calculateProductPrice",
>> priceContext);
>>>  
>>> Index:
> applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh
> ===================================================================
>>> ---
> applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh
>> (revision 427048)
>>> +++
> applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh
>> (working copy)
>>> @@ -170,6 +170,7 @@
>>>          priceContext.put("webSiteId", webSiteId);
>>>          priceContext.put("productStoreId",
>> productStoreId);
>>>          priceContext.put("checkIncludeVat", "Y");
>>> +        priceContext.put("agreementId",
>> cart.getAgreementId());
>>>          priceMap =
>> dispatcher.runSync("calculateProductPrice",
>> priceContext);
>>>          context.put("priceMap", priceMap);
>>>      } else {
>>> Index:
> applications/product/servicedef/services_pricepromo.xml
> ===================================================================
>>> ---
> applications/product/servicedef/services_pricepromo.xml
>> (revision 427048)
>>> +++
> applications/product/servicedef/services_pricepromo.xml
>> (working copy)
>>> @@ -32,6 +32,7 @@
>>>          <attribute name="partyId" type="String"
>> mode="IN" optional="true"/>
>>>          <attribute name="productStoreId"
>> type="String" mode="IN" optional="true"/>
>>>          <attribute name="productStoreGroupId"
>> type="String" mode="IN" optional="true"/>
>>> +        <attribute name="agreementId"
>> type="String" mode="IN" optional="true"/>
>>>          <attribute name="quantity" type="Double"
>> mode="IN" optional="true"/>
>>>          <attribute name="currencyUomId"
>> type="String" mode="IN" optional="true"/>
>>>          <attribute name="productPricePurposeId"
>> type="String" mode="IN" optional="true"><!--
>> defaults to PURCHASE --></attribute>
>>> Index:
> applications/product/src/org/ofbiz/product/price/PriceServices.java
> ===================================================================
>>> ---
> applications/product/src/org/ofbiz/product/price/PriceServices.java
>> (revision 427192)
>>> +++
> applications/product/src/org/ofbiz/product/price/PriceServices.java
>> (working copy)
>>> @@ -70,6 +70,7 @@
>>>       *   <li>webSiteId
>>>       *   <li>productStoreId
>>>       *   <li>productStoreGroupId
>>> +     *   <li>agreementId
>>>       *   <li>quantity
>>>       *   <li>currencyUomId
>>>       *   <li>checkIncludeVat
>>> @@ -96,6 +97,8 @@
>>>          String webSiteId = (String)
>> context.get("webSiteId");
>>>          String checkIncludeVat = (String)
>> context.get("checkIncludeVat");
>>>  
>>> +        String agreementId = (String)
>> context.get("agreementId");
>>> +
>>>          String productStoreId = (String)
>> context.get("productStoreId");
>>>          String productStoreGroupId = (String)
>> context.get("productStoreGroupId");
>>
> === message truncated ===

Reply | Threaded
Open this post in threaded view
|

Re: Price Agreements with customers

cjhowe
To obtain the benefit of tracking, why not create a
"join" entity between agreement and pricerule.

I did some work a few months ago on making some
business sense specific price rule screens.  I can't
remember if the latest svn has errors in it or not.
I'll update it on Monday.  It's a work in progress but
it's on it's way.

https://sourceforge.net/projects/ezofbiz

I think you'll run into many problems with having
essentially 3 repositories for pricing.  Ideally, I
think it'd be better to consolidate the price rules
and the productPrice logic.  But of all the
hairbrained things I've proposed that's probably the
largest project as far as and individual's work goes
(ie not POC and have a monkey repeat it).

--- Jacopo Cappellato <[hidden email]> wrote:

> Hi Chris,
>
> price rules are not bypassed by this new feature.
> The agreement price (if available) simply overrides
> the default price
> but if there are price rules that apply they will be
> used.
> I agree with you that you could get the same goal
> using price rules, but
> in my opinion they are not well suited for this use
> case, i.e. the setup
> of a custom price list between a customer and the
> company.
> Using price rules this would involve the creation of
> a price rule
> header, price rule condition and price rule action
> for each product in
> the list.
> Also, by using the Agreement data model (that in my
> opinion is a natural
> fit here) it is easier to keep an history of price
> lists ("price list
> 2005", "price list 2006/2007" etc...) by using the
> agreement validity
> dates (and the new feature of copying an agreement
> into a new one).
>
> Jacopo
>
> Chris Howe wrote:
> > Can't this already be done using the price rules?
> > Better screens need to be made, but this
> functionality
> > is there with a lot more flexibility.
> >
> > --- Jacopo Cappellato <[hidden email]> wrote:
> >
> >> Can I go on and commit the patch?
> >>
> >> Jacopo
> >>
> >> Jacopo Cappellato wrote:
> >>> Hi all,
> >>>
> >>> I've implemented a new price list feature that
> can
> >> be used to set up
> >>> price lists for specific customers. It is based
> on
> >> the Agreement data
> >>> model.
> >>> There are only two relevant changes (please see
> >> the attached patch)
> >>> needed, and I'd really love to get your feedback
> >> about them before
> >>> committing:
> >>>
> >>> a) added a new price field to the
> >> AgreementProductAppl entity
> >>> b) added a new optional input parameter,
> >> "agreementId", to the
> >>> calculateProductPrice service; if the
> agreementId
> >> is passed, and if a
> >>> valid price for the product is found in the
> >> AgreementProductAppl entity,
> >>> this price overrides the default price in the
> >> ProductPrice entity.
> >>> Here are the steps needed to test this stuff:
> >>>
> >>> * create an agreement (of type sales) between
> the
> >> Company and the customer
> >>> * create an agreement item of type price list
> for
> >> a given currency
> >>> * associate products to the price list
> (agreement
> >> item) and set the
> >>> price there (this is a new field
> >> AgreementProductAppl.price)
> >>> * when you start a sales order, select the
> >> agreement
> >>> Jacopo
> >>>
> >>>
> >>>
> >
>
------------------------------------------------------------------------
> >>> Index:
> >> applications/party/entitydef/entitymodel.xml
> >
>
===================================================================

> >>> --- applications/party/entitydef/entitymodel.xml
> >> (revision 427048)
> >>> +++ applications/party/entitydef/entitymodel.xml
> >> (working copy)
> >>> @@ -242,6 +242,7 @@
> >>>        <field name="agreementId"
> >> type="id-ne"></field>
> >>>        <field name="agreementItemSeqId"
> >> type="id-ne"></field>
> >>>        <field name="productId"
> >> type="id-ne"></field>
> >>> +      <field name="price"
> >> type="currency-precise"></field>
> >>>        <prim-key field="agreementId"/>
> >>>        <prim-key field="agreementItemSeqId"/>
> >>>        <prim-key field="productId"/>
> >>> Index:
> >
>
applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
> >
>
===================================================================
> >>> ---
> >
>
applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
> >> (revision 427048)
> >>> +++
> >
>
applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java

> >> (working copy)
> >>> @@ -876,6 +876,7 @@
> >>>                    
> >> priceContext.put("prodCatalogId",
> >> this.getProdCatalogId());
> >>>                    
> priceContext.put("webSiteId",
> >> cart.getWebSiteId());
> >>>                    
> >> priceContext.put("productStoreId",
> >> cart.getProductStoreId());
> >>> +                  
> >> priceContext.put("agreementId",
> >> cart.getAgreementId());
> >>>                      Map priceResult =
> >> dispatcher.runSync("calculateProductPrice",
> >> priceContext);
> >>>                      if
> >> (ServiceUtil.isError(priceResult)) {
> >>>                          throw new
> >> CartItemModifyException("There was an error while
> >> calculating the price: " +
> >> ServiceUtil.getErrorMessage(priceResult));
> >>> Index:
> >
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh
> >
>
===================================================================
> >>> ---
> >
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh
> >> (revision 427048)
> >>> +++
> >
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productsummary.bsh

> >> (working copy)
> >>> @@ -85,6 +85,7 @@
> >>>          priceContext.put("webSiteId",
> webSiteId);
> >>>          priceContext.put("prodCatalogId",
> >> catalogId);
> >>>          priceContext.put("productStoreId",
> >> productStoreId);
> >>> +        priceContext.put("agreementId",
> >> cart.getAgreementId());
> >>>          priceContext.put("checkIncludeVat",
> "Y");
> >>>          priceMap =
> >> dispatcher.runSync("calculateProductPrice",
> >> priceContext);
> >>>  
> >>> Index:
> >
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh
> >
>
===================================================================
> >>> ---
> >
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh
> >> (revision 427048)
> >>> +++
> >
>
applications/order/webapp/ordermgr/WEB-INF/actions/entry/catalog/productdetail.bsh

> >> (working copy)
> >>> @@ -170,6 +170,7 @@
> >>>          priceContext.put("webSiteId",
> webSiteId);
> >>>          priceContext.put("productStoreId",
> >> productStoreId);
> >>>          priceContext.put("checkIncludeVat",
> "Y");
> >>> +        priceContext.put("agreementId",
> >> cart.getAgreementId());
> >>>          priceMap =
> >> dispatcher.runSync("calculateProductPrice",
> >> priceContext);
> >>>          context.put("priceMap", priceMap);
> >>>      } else {
> >>> Index:
> >
>
applications/product/servicedef/services_pricepromo.xml
>
=== message truncated ===

Reply | Threaded
Open this post in threaded view
|

Re: Price Agreements with customers

David E Jones-2
In reply to this post by Jacopo Cappellato

Yes, I think this addition sounds good and it would be great to have  
it in the project.

Another area that would be a nice supplement to the current product  
price rules is an easier way to do different prices for different  
quantity ranges.

-David


On Aug 5, 2006, at 11:58 PM, Jacopo Cappellato wrote:

> Can I go on and commit the patch?
>
> Jacopo
>
> Jacopo Cappellato wrote:
>> Hi all,
>> I've implemented a new price list feature that can be used to set  
>> up price lists for specific customers. It is based on the  
>> Agreement data model.
>> There are only two relevant changes (please see the attached  
>> patch) needed, and I'd really love to get your feedback about them  
>> before committing:
>> a) added a new price field to the AgreementProductAppl entity
>> b) added a new optional input parameter, "agreementId", to the  
>> calculateProductPrice service; if the agreementId is passed, and  
>> if a valid price for the product is found in the  
>> AgreementProductAppl entity, this price overrides the default  
>> price in the ProductPrice entity.
>> Here are the steps needed to test this stuff:
>> * create an agreement (of type sales) between the Company and the  
>> customer
>> * create an agreement item of type price list for a given currency
>> * associate products to the price list (agreement item) and set  
>> the price there (this is a new field AgreementProductAppl.price)
>> * when you start a sales order, select the agreement
>> Jacopo
>> ---------------------------------------------------------------------
>> ---
>> Index: applications/party/entitydef/entitymodel.xml
>> ===================================================================
>> --- applications/party/entitydef/entitymodel.xml (revision 427048)
>> +++ applications/party/entitydef/entitymodel.xml (working copy)
>> @@ -242,6 +242,7 @@
>>        <field name="agreementId" type="id-ne"></field>
>>        <field name="agreementItemSeqId" type="id-ne"></field>
>>        <field name="productId" type="id-ne"></field>
>> +      <field name="price" type="currency-precise"></field>
>>        <prim-key field="agreementId"/>
>>        <prim-key field="agreementItemSeqId"/>
>>        <prim-key field="productId"/>
>> Index: applications/order/src/org/ofbiz/order/shoppingcart/
>> ShoppingCartItem.java
>> ===================================================================
>> --- applications/order/src/org/ofbiz/order/shoppingcart/
>> ShoppingCartItem.java (revision 427048)
>> +++ applications/order/src/org/ofbiz/order/shoppingcart/
>> ShoppingCartItem.java (working copy)
>> @@ -876,6 +876,7 @@
>>                      priceContext.put("prodCatalogId",  
>> this.getProdCatalogId());
>>                      priceContext.put("webSiteId",  
>> cart.getWebSiteId());
>>                      priceContext.put("productStoreId",  
>> cart.getProductStoreId());
>> +                    priceContext.put("agreementId",  
>> cart.getAgreementId());
>>                      Map priceResult = dispatcher.runSync
>> ("calculateProductPrice", priceContext);
>>                      if (ServiceUtil.isError(priceResult)) {
>>                          throw new CartItemModifyException("There  
>> was an error while calculating the price: " +  
>> ServiceUtil.getErrorMessage(priceResult));
>> Index: applications/order/webapp/ordermgr/WEB-INF/actions/entry/
>> catalog/productsummary.bsh
>> ===================================================================
>> --- applications/order/webapp/ordermgr/WEB-INF/actions/entry/
>> catalog/productsummary.bsh (revision 427048)
>> +++ applications/order/webapp/ordermgr/WEB-INF/actions/entry/
>> catalog/productsummary.bsh (working copy)
>> @@ -85,6 +85,7 @@
>>          priceContext.put("webSiteId", webSiteId);
>>          priceContext.put("prodCatalogId", catalogId);
>>          priceContext.put("productStoreId", productStoreId);
>> +        priceContext.put("agreementId", cart.getAgreementId());
>>          priceContext.put("checkIncludeVat", "Y");
>>          priceMap = dispatcher.runSync("calculateProductPrice",  
>> priceContext);
>>  Index: applications/order/webapp/ordermgr/WEB-INF/actions/entry/
>> catalog/productdetail.bsh
>> ===================================================================
>> --- applications/order/webapp/ordermgr/WEB-INF/actions/entry/
>> catalog/productdetail.bsh (revision 427048)
>> +++ applications/order/webapp/ordermgr/WEB-INF/actions/entry/
>> catalog/productdetail.bsh (working copy)
>> @@ -170,6 +170,7 @@
>>          priceContext.put("webSiteId", webSiteId);
>>          priceContext.put("productStoreId", productStoreId);
>>          priceContext.put("checkIncludeVat", "Y");
>> +        priceContext.put("agreementId", cart.getAgreementId());
>>          priceMap = dispatcher.runSync("calculateProductPrice",  
>> priceContext);
>>          context.put("priceMap", priceMap);
>>      } else {
>> Index: applications/product/servicedef/services_pricepromo.xml
>> ===================================================================
>> --- applications/product/servicedef/services_pricepromo.xml
>> (revision 427048)
>> +++ applications/product/servicedef/services_pricepromo.xml
>> (working copy)
>> @@ -32,6 +32,7 @@
>>          <attribute name="partyId" type="String" mode="IN"  
>> optional="true"/>
>>          <attribute name="productStoreId" type="String" mode="IN"  
>> optional="true"/>
>>          <attribute name="productStoreGroupId" type="String"  
>> mode="IN" optional="true"/>
>> +        <attribute name="agreementId" type="String" mode="IN"  
>> optional="true"/>
>>          <attribute name="quantity" type="Double" mode="IN"  
>> optional="true"/>
>>          <attribute name="currencyUomId" type="String" mode="IN"  
>> optional="true"/>
>>          <attribute name="productPricePurposeId" type="String"  
>> mode="IN" optional="true"><!-- defaults to PURCHASE --></attribute>
>> Index: applications/product/src/org/ofbiz/product/price/
>> PriceServices.java
>> ===================================================================
>> --- applications/product/src/org/ofbiz/product/price/
>> PriceServices.java (revision 427192)
>> +++ applications/product/src/org/ofbiz/product/price/
>> PriceServices.java (working copy)
>> @@ -70,6 +70,7 @@
>>       *   <li>webSiteId
>>       *   <li>productStoreId
>>       *   <li>productStoreGroupId
>> +     *   <li>agreementId
>>       *   <li>quantity
>>       *   <li>currencyUomId
>>       *   <li>checkIncludeVat
>> @@ -96,6 +97,8 @@
>>          String webSiteId = (String) context.get("webSiteId");
>>          String checkIncludeVat = (String) context.get
>> ("checkIncludeVat");
>>  +        String agreementId = (String) context.get("agreementId");
>> +
>>          String productStoreId = (String) context.get
>> ("productStoreId");
>>          String productStoreGroupId = (String) context.get
>> ("productStoreGroupId");
>>          GenericValue productStore = null;
>> @@ -230,6 +233,23 @@
>>              if (Debug.infoOn()) Debug.logInfo("There is more than  
>> one DEFAULT_PRICE with the currencyUomId " + currencyUomId + " and  
>> productId " + productId + ", using the latest found with price: "  
>> + defaultPriceValue.getDouble("price"), module);
>>          }
>>  +        // If there is an agreement between the company and the  
>> client, and there is
>> +        // a price for the product in it, it will override the  
>> default price of the +        // ProductPrice entity.
>> +        if (UtilValidate.isNotEmpty(agreementId)) {
>> +            try {
>> +                List agreementPrices = delegator.findByAnd
>> ("AgreementItemAndProductAppl", UtilMisc.toMap("agreementId",  
>> agreementId, "productId", productId, "currencyUomId",  
>> currencyUomId));
>> +                GenericValue agreementPriceValue =  
>> EntityUtil.getFirst(agreementPrices);
>> +                if (agreementPriceValue != null &&  
>> agreementPriceValue.get("price") != null) {
>> +                    defaultPriceValue = agreementPriceValue;
>> +                }
>> +            } catch (GenericEntityException e) {
>> +                String errMsg = "Error getting agreement info  
>> from the database while calculating price" + e.toString();
>> +                Debug.logError(e, errMsg, module);
>> +                return ServiceUtil.returnError(errMsg);
>> +            }
>> +        }
>> +
>>          List competitivePrices = EntityUtil.filterByAnd
>> (productPrices, UtilMisc.toMap("productPriceTypeId",  
>> "COMPETITIVE_PRICE"));
>>          GenericValue competitivePriceValue = EntityUtil.getFirst
>> (competitivePrices);
>>          if (competitivePrices != null && competitivePrices.size()  
>> > 1) {
>