Display collection of Shopping cart rules and products categories associated to each rule
Asked Answered
B

4

6

I want to check if there is a sales promotion on the product then stick the promotion label on that product on category list page. But I don't know how to loop through all the shopping cart rules and retrieve the products/categories associated to each rule.

EDITED

Thanks seanbreeden, but I can't pull the skus from $conditions. var_dump($conditions); shows this:

{s:4:"type";s:32:"salesrule/rule_condition_combine";s:9:"attribute";N;s:8:"operator";N;s:5:"value";s:1:"1";s:18:"is_value_processed";N;s:10:"aggregator";s:3:"all";}a:7:{s:4:"type";s:32:"salesrule/rule_condition_combine";s:9:"attribute";N;s:8:"operator";N;s:5:"value";s:1:"1";s:18:"is_value_processed";N;s:10:"aggregator";s:3:"all";s:10:"conditions";a:1:{i:0;a:7:{s:4:"type";s:42:"salesrule/rule_condition_product_subselect";s:9:"attribute";s:3:"qty";s:8:"operator";s:2:">=";s:5:"value";s:1:"1";s:18:"is_value_processed";N;s:10:"aggregator";s:3:"all";s:10:"conditions";a:1:{i:0;a:5:{s:4:"type";s:32:"salesrule/rule_condition_product";s:9:"attribute";s:12:"category_ids";s:8:"operator";s:2:"==";s:5:"value";s:2:"23";s:18:"is_value_processed";b:0;}}}}}a:7:{s:4:"type";s:32:"salesrule/rule_condition_combine";s:9:"attribute";N;s:8:"operator";N;s:5:"value";s:1:"1";s:18:"is_value_processed";N;s:10:"aggregator";s:3:"all";s:10:"conditions";a:2:{i:0;a:5:{s:4:"type";s:32:"salesrule/rule_condition_address";s:9:"attribute";s:13:"base_subtotal";s:8:"operator";s:2:">=";s:5:"value";s:2:"45";s:18:"is_value_processed";b:0;}i:1;a:7:{s:4:"type";s:42:"salesrule/rule_condition_product_subselect";s:9:"attribute";s:3:"qty";s:8:"operator";s:2:">=";s:5:"value";s:1:"1";s:18:"is_value_processed";N;s:10:"aggregator";s:3:"all";s:10:"conditions";a:1:{i:0;a:5:{s:4:"type";s:32:"salesrule/rule_condition_product";s:9:"attribute";s:3:"sku";s:8:"operator";s:2:"==";s:5:"value";s:46:"test-config, BLFA0968C-BK001, BLFA0968C-CR033X";s:18:"is_value_processed";b:0;}}}}}a:6:{s:4:"type";s:32:"salesrule/rule_condition_combine";s:9:"attribute";N;s:8:"operator";N;s:5:"value";s:1:"1";s:18:"is_value_processed";N;s:10:"aggregator";s:3:"all";}a:6:{s:4:"type";s:32:"salesrule/rule_condition_combine";s:9:"attribute";N;s:8:"operator";N;s:5:"value";s:1:"1";s:18:"is_value_processed";N;s:10:"aggregator";s:3:"all";}a:7:{s:4:"type";s:32:"salesrule/rule_condition_combine";s:9:"attribute";N;s:8:"operator";N;s:5:"value";s:1:"1";s:18:"is_value_processed";N;s:10:"aggregator";s:3:"all";s:10:"conditions";a:1:{i:0;a:7:{s:4:"type";s:42:"salesrule/rule_condition_product_subselect";s:9:"attribute";s:3:"qty";s:8:"operator";s:2:">=";s:5:"value";s:1:"1";s:18:"is_value_processed";N;s:10:"aggregator";s:3:"all";s:10:"conditions";a:1:{i:0;a:5:{s:4:"type";s:32:"salesrule/rule_condition_product";s:9:"attribute";s:3:"sku";s:8:"operator";s:2:"==";s:5:"value";s:16:"BLFA0968C-CR033X";s:18:"is_value_processed";b:0;}}}}}

but when I loop through $conditions i.e.

$rules = Mage::getResourceModel('salesrule/rule_collection')->load();

foreach ($rules as $rule) {
    $conditions = $rule->getConditionsSerialized();
    foreach ($conditions as $condition) {
        var_dump($condition);
    }
}

it doesn't show anything so don't really know how to pull skus here.

EDIT2 As Alaxandre suggested, I'm not using unserialized approach. I'm doing it like this now:

$rules = Mage::getResourceModel('salesrule/rule_collection')->load();

foreach ($rules as $rule) {
    if ($rule->getIsActive()) {
        //print_r($rule->getData());
        $rule = Mage::getModel('salesrule/rule')->load($rule->getId()); 

        $conditions = $rule->getConditions();
        $conditions = $rule->getConditions()->asArray();

        foreach( $conditions['conditions'] as $_conditions ):
            foreach( $_conditions['conditions'] as $_condition ):
                $string = explode(',', $_condition['value']);
                for ($i=0; $i<count($string); $i++) {
                    $skus[] = trim($string[$i]);
                }
            endforeach;
        endforeach;
    }
}
return $skus;

And then checking in list page if sku matches within $skus array then show the label. But again there are limitation with this approach as well. I'm think of another approach (I'm not sure if thats is possible). Thinking of creating a new table (to save the sales rules products).Everytime save the sales rule, catch the save rule event and update the table with Rule name and all the associated products. Then on the list page check that table, if products exist in the table, show the appropriate label. Now I think the event is adminhtml_controller_salesrule_prepare_save (not 100% sure) but I don't know how to get the sku from the rule condition in the observer to save in the new table.

Bedfast answered 28/2, 2012 at 13:47 Comment(5)
You have to be very careful with unserialzing yourself the rule data. You have to validate the rule for each of them and it can be very complex. For example the rule can be if sku is 'sku001' but can be also sku is not 'sku001'. And there is also rules combination and so on. I don't think you get the good direction...Ashram
Thanks Alexandre. I thought about that so not using unserialized now. I have updated the question. Please see Edit2Bedfast
You can't do like this also. You have to validate the rule for each product. But to be honest, I think it's too crazy! Because then you will may be have lot of label for a single product. Catching the event save would not be enough because there is a possible end date for your rule.Ashram
What root should be taken then? You suggested to cache the rules but I have no clue how to do that so is there anything else I can do to show the labels on list page?Bedfast
check to my comment, I made an update. I think this would be the easiest way to do. Good luck.Ashram
A
4

I would suggest you to do it like this. When you had a product to cart, each rules are checked to calculate the final price and reduction. You can know which rules are applied to each item of your cart. In the table sales_flat_quote_item you have the column applied_rule_ids. I think you can access to this in php, by a function getAllItemsInCart or something like this (you have to find out). After you do $item->getAppliedRuleIds() and finally you can get the name of the rule apply to an item (product).

Good luck :)

Edit:

I read again your request and I think my answer doesn't fit with your request. Your case is even more complicated. For each product on your catalog page you have to apply all the rules of your website. But Mage_SalesRule_Model_Validator process expect item and not product... If you have lot of rules this task will slow down your catalog and this is really not good! The best would be to cache this result of the rules label in the database, may be in the table catalog_category_product or... (and even better to generate this cache automatically).

Edit2:

Other possibility would be to have a new field in rule creation where you set manually the related products (sku). You save this data in the table salesrule or in a new table salesrule_related_sku. Then when you display the catalog you check for the sku and if the rule still active. This solution would be the easiest one :-)

Ashram answered 29/2, 2012 at 11:24 Comment(5)
Make sense. But I'm thinking of another approach (don't know how to execute though). Thinking of creating a new table (to save the sales rules products).Everytime save the sales rule, catch the save rule event and update the table with Rule name and all the associated products. Then on the list page check that table, if products exist in the table, show the appropriate label. Now I think the event is adminhtml_controller_salesrule_prepare_save (not 100% sure) but I don't know how to get the sku from the rule condition in the observer to save in the new table.Bedfast
I'm using adminhtml_controller_salesrule_prepare_save event. How do I get the id of the rule I am trying to save? If I can get the id here, I can save all the related skus in the new table and then can match with this table on list page.Bedfast
I created a new field in promo rules as $fldSet->addField('promo_skus', 'text', array( 'name' => 'promo_skus', 'label' => Mage::helper('rules')->__('Promo SKUs'), 'note' => Mage::helper('rules')->__('Comma separated list of the sku ids'), ), 'discount_amount' ); by capturing the adminhtml_block_salesrule_actions_prepareform event . Qhen I add skus in coditions, I want to auto populate this field with them skus. Don't know how to do that.Bedfast
I knew there had to be an easier way! Thanks I learned from this too!Performance
Found any solution ?Casebound
P
3

You could pull the getMatchingProductsIds from /app/code/core/Mage/CatalogRule/Model/Rule.php and compare them with the skus displayed on the category list page.

 $catalog_rule = Mage::getModel('catalogrule/rule')->load(1);  // ID of your catalog rule here, or you could leave off ->load(1) and iterate through  ->getCollection() instead
 $catalog_rule_skus = $catalog_rule->getMatchingProductIds();

hth

EDIT

Here's a way to get the serialized conditions:

$rules = Mage::getResourceModel('salesrule/rule_collection')->load();

foreach ($rules as $rule) {
    $conditions = $rule->getConditionsSerialized();
    var_dump($conditions);
}

EDIT 2

There would have to be a better way to do this. The only way I could pull that data was to unserialize then iterate with foreach through each layer. Anyone have any better ideas for this? This works but is very sloppy.

$rules = Mage::getResourceModel('salesrule/rule_collection')->load();

foreach ($rules as $rule) {

  if ($rule->getIsActive()) { 
$conditions = $rule->getConditionsSerialized();
$unserialized_conditions = unserialize($conditions);

$unserialized_conditions_compact = array();

foreach($unserialized_conditions as $key => $value) {
   $unserialized_conditions_compact[] = compact('key', 'value');
}

for ($i=0;$i<count($unserialized_conditions_compact);$i++) {
        if (in_array("conditions",$unserialized_conditions_compact[$i])) {
                foreach($unserialized_conditions_compact[$i] as $key => $value) {
                        foreach($value as $key1 => $value1) {
                                foreach($value1 as $key2 => $value2) {
                                        foreach($value2 as $key3 => $value3) {
                                                $skus[] = explode(",",$value3['value']);
                                        }
                                }
                        }
                }
        }
}
 }

}

var_dump($skus);
Performance answered 28/2, 2012 at 15:11 Comment(7)
I'm using Shopping cart price rules not Catalog rules. Just checked /app/code/core/Mage/SalesRule/Model/Rule.php, it doesn't have any GetMatchingProductsIds function.Bedfast
I edited the code above. See if that gets you going in the right direction. You should be able to iterate through to pull the Skus so they can be compared in your list.phtmlPerformance
Thanks seanbreeden, but I'm struggling to get the skus. I have updated the question. Please adviceBedfast
Thanks seanbreeden. Yeah it works but as you said it is a bit long winded.Bedfast
how to get the collection of only active salesrules?Bedfast
I couldn't see how to add it to the collection itself so I added a check for getIsActive() in the edited Answer abovePerformance
Yeah I'm doing the same way, but thought may be could add the filter to the collection.Bedfast
A
0

The rules are associated to all product for a website. There is no rules set for a specific products/categories from the database point of view. For each product in the cart, Magento will validate all the rules you have for a website. This operation is done in the class Mage_SalesRule_Model_Validator. The only way to solve your request is to extend the function process from this class (at least I think so :p).

Ashram answered 28/2, 2012 at 14:4 Comment(1)
Let me explain a bit more. Say I create a rule of BOGOF and in condition I add only 3 products (prod1, prod2, prod3). Which means BOGOF only applies on these three products. On category list page, say I have 10 products but I want to show BOGOF label only on prod1, prod2 and prod3. Hope its bit more clearer nowBedfast
S
0

I wanted the same thing as you want. I wanted to get associated SKUS, Category Ids and any other conditions value to generate Google feeds to be used in Google merchant promotions.

I have used the recursive function to reach to last children of the condition and fetch its value.

I am checking based on the attribute value of the condition. If an attribute value is blank then go one step down and check if attribute value present and if so then fetch the value of it otherwise continue to go down.

Here is the code that I used to fetch values. Which will also work for the case, when two conditions are on the same level.

public function get_value_recursively($value){

        foreach($value as $key => $new_value) {
            if(strlen($new_value[attribute]) == 0){
                $value = $new_value[conditions];
                return $this->get_value_recursively($value);
            }else{
                $resultSet = array();
                if (count($value) > 1){
                    for ($i=0;$i<count($value);$i++) {
                        $resultSet[] = array('attribute' =>  $value[$i][attribute], 'value' => $value[$i][value]);
                    }
                    $result = $resultSet;
                }else{
                    $result = array('attribute' =>  $new_value[attribute], 'value' => $new_value[value]);
                }
                return json_encode($result, JSON_FORCE_OBJECT);
            }
        }
    }

according to @seanbreeden answer you can call this function from first foreach

It will return the result like this :

{"0":{"attribute":"category_ids","value":"5, 15"},"1":{"attribute":"sku","value":"msj000, msj001, msj002"}}

P.S. I am not PHP dev. So, Ignore layman style code. :)

Swag answered 23/3, 2018 at 20:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.