[rules-users] rules for promotional offers

Wolfgang Laun wolfgang.laun at gmail.com
Fri Sep 9 05:52:32 EDT 2011


If the declared type of productId and getProductId() is String, it should be
compared to a string literal. (A conversion might be made, but don't rely on
that.)

You cannot access components of a global in RHS code using the simplified
notation (not unless you use "mvel" - but don't do that.) Here, all accesses
should be written the usual Java way, with getter and setter calls.

The problem you have with modify(ci) is a bug (fixed for 5.3.0). As a
workaround,use

modify( (CartItem)ci ){ ... }

-W


2011/9/9 Sandeep Bandela <gibsosmat at gmail.com>

> some more info for the modify() problem, the CartItem is an interface and
> the implementation is CartItemImpl. if this info leads to some clues.
>

>
> On Fri, Sep 9, 2011 at 1:28 PM, Sandeep Bandela <gibsosmat at gmail.com>wrote:
>
>> Hi here is the same thing converted to mvl
>>
>> // this Bundler.java has integer member that keeps incrementing
>> global Bundler bundler
>>
>>
>> rule "Apply 10% discount if you purchase 2 items"
>>     when
>>         $s1 : CartItem( *productId == 219759*, processed == false)
>>         $s2 : CartItem( this != $s1, productId == $s1.productId, processed
>> == false)
>>
>>         $m : RuleMessage()
>>  then
>>         $m.addMessage("Found item1: " + $s1.getName() + " id:
>> "+$s1.getId());
>>         $m.addMessage("Found item2: " + $s2.getName() + " id:
>> "+$s2.getId());
>>         modify($s1){
>>         setProcessed(true),
>>         setPromoItemDiscount($s1.getPrice() * 0.1),
>>         setPromoId("1"),
>>         setBundleId(bundler.getId()),
>>         setAggrigatorId(1)
>>         };
>>         modify($s2){
>>         setProcessed(true),
>>         setPromoItemDiscount($s2.getPrice() * 0.1),
>>         setPromoId("1"),
>>         setBundleId(bundler.getId()),
>>         setAggrigatorId(1)
>>         };
>>         $m.addMessage("bundled ["+*bundler.getId()*+"]
>> "+$s1.getId()+","+$s2.getId());
>>         bundler.increment();
>> end
>>
>> the above rule dosent fire, but if I change the highlighter to
>> getProductId() == 219759, or use productId == "219759", may be this is some
>> edge case but it took long time for me to figure it out productId is String.
>> now consider the *bundler.getId()*, if I use *bundler.id* I get
>> compilation error.
>>
>> Rule Compilation error : [Rule name='Apply 10% discount if you purchase 2
>> items']
>>
>> com/example/promotions/promotionEngine/Rule_Apply_10__discount_if_you_purchase_2_items_0.java
>> (23:1592) : The field Bundler.id is not visible
>> 2011-09-09 13:18:39,863  INFO [STDOUT] - 2011-09-09 13:18:39,863  INFO
>> [PromotionsManager] - ksession initialized
>> 2011-09-09 13:18:39,863  INFO [STDOUT] - 2011-09-09 13:18:39,863  INFO
>> [PromotionsManager] - Exploding items and inserting cart
>> 2011-09-09 13:18:39,864  INFO [STDOUT] - 2011-09-09 13:18:39,863 ERROR
>> [CheckOutBasedUtilities] - Failed to apply promo offers
>> java.lang.RuntimeException: Unexpected global [bundler]
>>     at
>> org.drools.common.AbstractWorkingMemory.setGlobal(AbstractWorkingMemory.java:613)
>>     at
>> org.drools.impl.StatefulKnowledgeSessionImpl.setGlobal(StatefulKnowledgeSessionImpl.java:332)
>>     at
>> com.example.promotions.promotionEngine.PromotionsManager.applyOffers(PromotionsManager.java:154)
>>     at
>> com.example.promotions.promotionEngine.PromotionsManager.shuffleForOffers(PromotionsManager.java:61)`
>>
>> lastly my actual problem that I am looking for a solution lets say we have
>> "Buy X items of A and get Y Items of B". X=5 & Y=4 from the original problem
>> I want to template the rule and load the values of X,A,Y,B from database or
>> excel etc. if I use modify the error is as follows
>>
>> *my rule*
>>
>>
>>
>> rule "Buy X units of Product A and Get Y units of Product B Free"
>>     when
>>         $itemsX : ArrayList( size == 2 ) from collect( CartItem(
>> getProductId() == 24257, !isProcessed()))
>>         $itemsY : ArrayList( size == 1) from collect(CartItem(
>> getProductId() == 24260, !isProcessed()))
>>         $m : RuleMessage()
>>  then
>>          for(Object item : $itemsX){
>>              CartItem ci = (CartItem) item;
>>              $m.addMessage( ci.getId()+")Found item: "+ci.getItemId()+"
>> name: "+ci.getName());
>>              modify(ci){
>>                 setProcessed(true),
>>                 setPromoItemDiscount(0),
>>
>>                 setPromoId("2"),
>>                 setBundleId(bundler.getId()),
>>                 setAggrigatorId(1)
>>             };
>>          }
>>          for(Object item : $itemsY){
>>          CartItem ci = (CartItem) item;
>>              $m.addMessage( ci.getId()+")Found item: "+ci.getItemId()+"
>> name: "+ci.getName());
>>              modify(ci){
>>                 setProcessed(true),
>>                 setPromoItemDiscount(ci.getPrice()),
>>                 setPromoId("2"),
>>                 setBundleId(bundler.getId()),
>>                 setAggrigatorId(2)
>>             };
>>          }
>>         bundler.increment();
>> end
>>
>> Rule Compilation error : [Rule name='Buy X units of Product A and Get Y
>> units of Product B Free']
>>
>> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>> (11:1236) : The method setProcessed(boolean) is undefined for the type
>> Object
>>
>> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>> (12:1265) : The method setPromoItemDiscount(int) is undefined for the type
>> Object
>>
>> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>> (13:1299) : The method setPromoId(String) is undefined for the type Object
>>
>> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>> (14:1325) : The method setBundleId(Integer) is undefined for the type Object
>>
>> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>> (15:1364) : The method setAggrigatorId(int) is undefined for the type Object
>>
>> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>> (22:1702) : The method setProcessed(boolean) is undefined for the type
>> Object
>>
>> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>> (23:1731) : The method setPromoItemDiscount(Double) is undefined for the
>> type Object
>>
>> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>> (24:1777) : The method setPromoId(String) is undefined for the type Object
>>
>> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>> (25:1803) : The method setBundleId(Integer) is undefined for the type Object
>>
>> com/example/promotions/promotionEngine/Rule_Buy_X_units_of_Product_A_and_Get_Y_units_of_Product_B_Free_0.java
>> (26:1842) : The method setAggrigatorId(int) is undefined for the type Object
>>
>> Rule Compilation error : [Rule name='Apply 10% discount if you purchase 2
>> items']
>>
>> com/example/promotions/promotionEngine/Rule_Apply_10__discount_if_you_purchase_2_items_0.java
>> (23:1592) : The field Bundler.id is not visible
>>
>>
>>
>> On Fri, Sep 9, 2011 at 12:40 PM, Sandeep Bandela <gibsosmat at gmail.com>wrote:
>>
>>> Hi Wolfgang,
>>> This is what I did initially but for product > 2 I didnt find a generic
>>> way to do this. following is my first rule. I didnt use field names because
>>> it was giving error that member is not accessible. I will attach the errors
>>> of each case in a few mins.
>>>
>>> rule "Apply 10% discount if you purchase 2 items"
>>>     dialect "java"
>>>     when
>>>         $s1 : CartItem( getProductId() == 236061, !isProcessed())
>>>         $s2 : CartItem( getProductId() == 236061, getId() != $s1.getId(),
>>> !isProcessed())
>>>         $m : RuleMessage()
>>>  then
>>>         $m.addMessage("Found item1: " + $s1.getName() + " id:
>>> "+$s1.getId());
>>>         $m.addMessage("Found item2: " + $s2.getName() + " id:
>>> "+$s2.getId());
>>>         modify($s1){
>>>         setProcessed(true),
>>>         setPromoItemDiscount($s1.getPrice() * 0.1),
>>>         setPromoId("1"),
>>>         setBundleId(bundler.getId()),
>>>         setAggrigatorId(1)
>>>         };
>>>         modify($s2){
>>>         setProcessed(true),
>>>         setPromoItemDiscount($s2.getPrice() * 0.1),
>>>         setPromoId("1"),
>>>         setBundleId(bundler.getId()),
>>>         setAggrigatorId(1)
>>>         };
>>>         bundler.increment();
>>> end
>>>
>>>
>>> 2011/9/9 Wolfgang Laun <wolfgang.laun at gmail.com>
>>>
>>>> Your rule exhibits procedural thinking. (For an aspiring rule programmer
>>>> his is typical teething troubles.)
>>>>
>>>> There's no need to collect all A's and B's in order to determine their
>>>> number being greater than one or two - this is achieved automatically by a
>>>> simple triple match rule. Consider
>>>>
>>>> rule "2A - 1B"
>>>> when
>>>>    $a1: CartItem( productId == "A", processed == false )
>>>>    $a2: CartItem( this != $a1, productId == "A", processed == false )
>>>>    $b: CartItem( productId == "B", processed == false )
>>>> then
>>>>    modify( $a1 ){...}
>>>>    modify( $a2 ){...}
>>>>    modify( $b ){...}
>>>> end
>>>>
>>>> Note:
>>>>
>>>>    - The modify is essential. (When you say "doesn't work", always
>>>>    provide details.)
>>>>    - Use the field name rather than the getter call - it improves
>>>>    readability.
>>>>    - I'm not sure whether 5.2.0 final handles boolean fields correctly
>>>>    - IIRC, there were some issues. It's possible that CartItem(..., !processed)
>>>>    works.
>>>>
>>>> -W
>>>>
>>>> 2011/9/8 Sandeep Bandela <gibsosmat at gmail.com>
>>>>
>>>>> Hi,
>>>>> I am new to rules engine, after going through the examples shipped
>>>>> (shopping.drl, petstore.drl)
>>>>> I am trying to implement promotional discounting using drools 5.2.0
>>>>> final, stateful session. assume cart has all the items that customer wants
>>>>> to buy,
>>>>> I am trying to bundle them together with the existing offers
>>>>>
>>>>> rule "Buy X units of Product A and Get Y units of Product B Free"
>>>>>     dialect "java"
>>>>> when
>>>>>     $itemsA : ArrayList( size >= 2) from collect( CartItem(
>>>>> getProductId() == "A", !isProcessed()))
>>>>>     $itemsB : ArrayList( size >= 1) from collect( CartItem(
>>>>> getProductId() == "B", !isProcessed()))
>>>>> then
>>>>>     // current scenario buy 2*A and get 1*B
>>>>>     int x = 2;
>>>>>     int y = 1;
>>>>>     for(int i=0 ; i < x ; i++){
>>>>>         CartItem $ci = (CartItem) $itemsA.get(i);
>>>>>         // modify($ci){setProcessed(true) ... } dosent work
>>>>>         $ci.setProcessed(true);
>>>>>         $ci.setItemDiscount(0.0);
>>>>>         $ci.setBundleId(bundler.getId());
>>>>>     }
>>>>>
>>>>>     for(int i=0 ; i < y  ; i++){
>>>>>         CartItem $ci = (CartItem) $itemsB.get(i);
>>>>>         $ci.setProcessed(true);
>>>>>         $ci.setItemDiscount($ci.getPrice());
>>>>>         $ci.setBundleId(bundler.getId());
>>>>>     }
>>>>>     // global counter to identify bundled items
>>>>>     bundler.increment();
>>>>> end
>>>>>
>>>>> the above rule calculates only for 1 set of offer i.e first 2*A & 1*B
>>>>> are considered, rest in the cart are not bundled.
>>>>> if customer buys 4*A + 2*B it dosent consider it. am I missing
>>>>> anything? is this the right way to do it?
>>>>> any feedback is appreciated.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Regards,
>>>>> Sandeep Bandela.
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> rules-users mailing list
>>>>> rules-users at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/rules-users
>>>>>
>>>>>
>>>>
>>>> _______________________________________________
>>>> rules-users mailing list
>>>> rules-users at lists.jboss.org
>>>> https://lists.jboss.org/mailman/listinfo/rules-users
>>>>
>>>>
>>>
>>>
>>> --
>>> Regards,
>>> Sandeep Bandela.
>>>
>>>
>>
>>
>> --
>> Regards,
>> Sandeep Bandela.
>>
>>
>
>
> --
> Regards,
> Sandeep Bandela.
>
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20110909/831b30e5/attachment.html 


More information about the rules-users mailing list