{"id":1537,"date":"2017-09-26T19:57:39","date_gmt":"2017-09-26T13:57:39","guid":{"rendered":"http:\/\/promincproductions.com\/blog\/?p=1537"},"modified":"2022-01-06T14:44:55","modified_gmt":"2022-01-06T20:44:55","slug":"magento1-enterprise-rewards-refund-bug","status":"publish","type":"post","link":"https:\/\/promincproductions.com\/blog\/magento1-enterprise-rewards-refund-bug\/","title":{"rendered":"Magento 1 Enterprise Rewards Refund Bug"},"content":{"rendered":"<p>In the Magento 1 Enterprise Rewards module, there is a bug that affects page load time and server performance during the creation of a credit memo. &nbsp;In the case of a large store with large Reward Points history, it can actually prevent you from creating a credit memo. &nbsp;This problem affects orders placed from guests &#8211; customers that do not have a <strong>customer_id<\/strong>.<\/p>\n<figure id=\"attachment_1539\" aria-describedby=\"caption-attachment-1539\" style=\"width: 500px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/promincproductions.com\/blog\/wp-content\/uploads\/2017\/09\/Magento-1x-Enterprise-Guest-RP-Bug.jpg\" rel=\"attachment wp-att-539\" data-lasso-id=\"642\" data-rel=\"lightbox-gallery-Xne4WMVp\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" class=\"size-medium wp-image-1539\" src=\"https:\/\/promincproductions.com\/blog\/wp-content\/uploads\/2017\/09\/Magento-1x-Enterprise-Guest-RP-Bug-500x500.jpg\" alt=\"\" width=\"500\" height=\"500\" srcset=\"https:\/\/promincproductions.com\/blog\/wp-content\/uploads\/2017\/09\/Magento-1x-Enterprise-Guest-RP-Bug-500x500.jpg 500w, https:\/\/promincproductions.com\/blog\/wp-content\/uploads\/2017\/09\/Magento-1x-Enterprise-Guest-RP-Bug-150x150.jpg 150w, https:\/\/promincproductions.com\/blog\/wp-content\/uploads\/2017\/09\/Magento-1x-Enterprise-Guest-RP-Bug-768x768.jpg 768w, https:\/\/promincproductions.com\/blog\/wp-content\/uploads\/2017\/09\/Magento-1x-Enterprise-Guest-RP-Bug-600x600.jpg 600w, https:\/\/promincproductions.com\/blog\/wp-content\/uploads\/2017\/09\/Magento-1x-Enterprise-Guest-RP-Bug.jpg 944w\" sizes=\"(max-width: 500px) 100vw, 500px\" \/><\/a><figcaption id=\"caption-attachment-1539\" class=\"wp-caption-text\">Fixing the Magento 1 Enterprise Guest Reward Points History Bug<\/figcaption><\/figure>\n<h2>Nature of the Issue<\/h2>\n<p>When creating a credit memo while the Magento 1 Enterprise Reward Points module is installed and enabled, Magento will load all of the reward points history for the customer. &nbsp;It then iterates through this history, looking for this order in the Reward Points history so that it knows how to correctly calculate points during the refund.<\/p>\n<p>This all happens in this file\/method:<\/p>\n<pre class=\"lang:default decode:true\">app\/code\/core\/Enterprise\/Reward\/Model\/Observer.php\npublic function creditmemoSaveAfter(Varien_Event_Observer $observer)\nLine 755\n<\/pre>\n<p>Reward Points history is saved based on a&nbsp;<strong>reward_id<\/strong>, which is correlated to a&nbsp;<strong>customer_id<\/strong> in the&nbsp;<strong>enterprise_reward<\/strong> table.<\/p>\n<pre class=\"lang:mysql decode:true\">mysql&gt; DESCRIBE enterprise_reward;\n+-----------------------+----------------------+------+-----+---------+----------------+\n| Field                 | Type                 | Null | Key | Default | Extra          |\n+-----------------------+----------------------+------+-----+---------+----------------+\n| reward_id             | int(10) unsigned     | NO   | PRI | NULL    | auto_increment |\n| customer_id           | int(10) unsigned     | NO   | MUL | 0       |                |\n| website_id            | smallint(5) unsigned | YES  | MUL | NULL    |                |\n| points_balance        | int(10) unsigned     | NO   |     | 0       |                |\n| website_currency_code | varchar(3)           | YES  |     | NULL    |                |\n+-----------------------+----------------------+------+-----+---------+----------------+\n5 rows in set (0.00 sec)\n<\/pre>\n<p>Here is where Magento looks up the Reward Points history:<\/p>\n<pre class=\"lang:php decode:true\"># app\/code\/core\/Enterprise\/Reward\/Model\/Observer.php\n# Lines 798 - 809\n\n\/\/ Void reward points granted for refunded amount if there was any\n$customerId = $order-&gt;getCustomerId();\n$websiteId = Mage::app()-&gt;getStore($order-&gt;getStoreId())-&gt;getWebsiteId();\n\n\/\/ @var $rewardHistoryCollection Enterprise_Reward_Model_Resource_Reward_History_Collection\n$rewardHistoryCollection = Mage::getModel('enterprise_reward\/reward_history')-&gt;getCollection();\n$rewardHistoryCollection-&gt;addCustomerFilter($customerId)\n    -&gt;addWebsiteFilter($websiteId)\n    \/\/ nothing to void if reward points are expired already\n    -&gt;addFilter('main_table.is_expired', 0)\n    \/\/ void points acquired for purchase only\n    -&gt;addFilter('main_table.action', Enterprise_Reward_Model_Reward::REWARD_ACTION_ORDER_EXTRA);\n<\/pre>\n<p>The issue comes in then when the customer is a guest and thus does not have a&nbsp;<strong>customer_id<\/strong>. &nbsp;This line:<\/p>\n<pre class=\"lang:php decode:true\">$rewardHistoryCollection-&gt;addCustomerFilter($customerId)\n    -&gt;addWebsiteFilter($websiteId)<\/pre>\n<p>calls:<\/p>\n<pre class=\"lang:php decode:true\"># app\/code\/core\/Enterprise\/Reward\/Model\/Resource\/Reward\/History\/Collection.php\n# public function addCustomerFilter($customerId)\n# Line 107\n\n\/**\n * Join reward table to filter history by customer id\n *\n * @param string $customerId\n * @return Enterprise_Reward_Model_Resource_Reward_History_Collection\n *\/\npublic function addCustomerFilter($customerId)\n{\n    if ($customerId) {\n        $this-&gt;_joinReward();\n        $this-&gt;getSelect()-&gt;where('reward_table.customer_id = ?', $customerId);\n    }\n    return $this;\n}\n<\/pre>\n<p>If the&nbsp;<strong>$customerId<\/strong> is null, the join is never added to the query, thus resulting in ALL of the Reward Points history for ALL customers being returned.<\/p>\n<pre class=\"lang:mysql decode:true\">SELECT `main_table`.* FROM `enterprise_reward_history` AS `main_table` WHERE (main_table.website_id = '1')<\/pre>\n<p>Depending on the size of your Reward Points history this can be a large issue. &nbsp;I&#8217;ve noticed that Magento will not return a page when it is too large because the server is asked to process far too much data. &nbsp;It can throw an error in the traffic logs similar to this:<\/p>\n<pre class=\"lang:default decode:true\">PHP Fatal error: Allowed memory size of 2147483648 bytes exhausted (tried to allocate 8208 bytes) in \/var\/www\/vhosts\/examplesite.com\/html\/app\/code\/core\/Enterprise\/Reward\/Model\/Reward\/History.php on line 196, referer: https:\/\/examplesite.com\/sales_order\/view\/order_id\/123456\/<\/pre>\n<h2>Bug Fix<\/h2>\n<p>The solution to this issue is to ensure that even if&nbsp;<strong>$customerId<\/strong> is&nbsp;<strong>null<\/strong> (guest customer) that this join still is called. &nbsp;We can&nbsp;<strong>$customerId<\/strong> = 0 as that customer would never exist in a Magento store.<\/p>\n<pre class=\"lang:php decode:true\">\/**\n * Join reward table to filter history by customer id\n *\n * @param string $customerId\n * @return Enterprise_Reward_Model_Resource_Reward_History_Collection\n *\/\npublic function addCustomerFilter($customerId)\n{\n    \/* Added to core *\/\n    if( !$customerId ) {\n        $customerId = 0;\n    }\n\n    if ($customerId OR $customerId === 0) {  \/* Changed from core *\/\n        $this-&gt;_joinReward();\n        $this-&gt;getSelect()-&gt;where('reward_table.customer_id = ?', $customerId);\n    }\n    return $this;\n}\n<\/pre>\n<p>This bug fix sets&nbsp;<strong>$customerId<\/strong> = 0, thus the join will have something to look for.<\/p>\n<p>Also the <strong>if<\/strong> statement has to be modified as a value of 0 would fail.<\/p>\n<p>The end result is that the query resulting from this change will look like:<\/p>\n<pre class=\"lang:mysql decode:true\">SELECT `main_table`.*, `reward_table`.`customer_id`, `reward_table`.`points_balance` AS `points_balance_total` FROM `enterprise_reward_history` AS `main_table`\n INNER JOIN `enterprise_reward` AS `reward_table` ON reward_table.reward_id = main_table.reward_id WHERE (reward_table.customer_id = 0) AND (main_table.website_id = '1')<\/pre>\n<p>This should return zero results (as opposed to ALL results) and your server will hum right along just fine from there.<\/p>\n<h3>Bug Fix Via an Extend<\/h3>\n<p>As always, DO NOT modify core code &#8211; instead extend this module and properly fix this bug through the app\/code\/local directory. &nbsp;NEVER modify core code in a production environment!<\/p>\n<h2>Other Areas Using This Function<\/h2>\n<p>For clarity, there are a few other areas of the website that use this same function. &nbsp;These areas have been taken into account with this bug fix and are not affected by this change.<\/p>\n<pre class=\"lang:default decode:true\">grep -rn addCustomerFilter app\/code\/core\/Enterprise\/Reward\/\napp\/code\/core\/Enterprise\/Reward\/Model\/Resource\/Reward\/History\/Collection.php:107:    public function addCustomerFilter($customerId)\napp\/code\/core\/Enterprise\/Reward\/Model\/Observer.php:804:        $rewardHistoryCollection-&gt;addCustomerFilter($customerId)\napp\/code\/core\/Enterprise\/Reward\/Block\/Adminhtml\/Customer\/Edit\/Tab\/Reward\/History\/Grid.php:57:            -&gt;addCustomerFilter($this-&gt;getCustomerId())\napp\/code\/core\/Enterprise\/Reward\/Block\/Customer\/Reward\/History.php:147:                -&gt;addCustomerFilter(Mage::getSingleton('customer\/session')-&gt;getCustomerId())<\/pre>\n<h3>app\/code\/core\/Enterprise\/Reward\/Model\/Resource\/Reward\/History\/Collection.php<\/h3>\n<p><strong>Usage<\/strong>: The function with the bug that is modified with the proposed fix above<\/p>\n<h3>app\/code\/core\/Enterprise\/Reward\/Model\/Observer.php<\/h3>\n<p><strong>Usage<\/strong>: Called after saving a credit memo.<\/p>\n<h3>app\/code\/core\/Enterprise\/Reward\/Block\/Adminhtml\/Customer\/Edit\/Tab\/Reward\/History\/Grid.php<\/h3>\n<p><strong>Usage<\/strong>: In the Magento admin, displays the customers Reward Points history.<\/p>\n<h3>app\/code\/core\/Enterprise\/Reward\/Block\/Customer\/Reward\/History.php<\/h3>\n<p><strong>Usage<\/strong>: On the frontend, displays the customers Reward Points history.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>","protected":false},"excerpt":{"rendered":"<p>In the Magento 1 Enterprise Rewards module, there is a bug that affects page load time and server [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1539,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"wprm-recipe-roundup-name":"","wprm-recipe-roundup-description":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[46,5],"tags":[328],"class_list":["post-1537","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-magento","category-website-development","tag-magento-1"],"jetpack_featured_media_url":"https:\/\/promincproductions.com\/blog\/wp-content\/uploads\/2017\/09\/Magento-1x-Enterprise-Guest-RP-Bug.jpg","jetpack_shortlink":"https:\/\/wp.me\/p4BbcR-oN","jetpack_sharing_enabled":true,"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/posts\/1537","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/comments?post=1537"}],"version-history":[{"count":3,"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/posts\/1537\/revisions"}],"predecessor-version":[{"id":2290,"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/posts\/1537\/revisions\/2290"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/media\/1539"}],"wp:attachment":[{"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/media?parent=1537"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/categories?post=1537"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/promincproductions.com\/blog\/wp-json\/wp\/v2\/tags?post=1537"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}