PageRenderTime 28ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/app/code/local/Amasty/Promo/Model/Observer.php

https://bitbucket.org/hexzawanekz/magento
PHP | 413 lines | 330 code | 61 blank | 22 comment | 67 complexity | 1b87eb653258047f81099f45ca61b31d MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2009-11 Amasty
  4. */
  5. class Amasty_Promo_Model_Observer
  6. {
  7. protected $_isHandled = array();
  8. /**
  9. * Process sales rule form creation
  10. * @param Varien_Event_Observer $observer
  11. */
  12. public function handleFormCreation($observer)
  13. {
  14. $actionsSelect = $observer->getForm()->getElement('simple_action');
  15. if ($actionsSelect){
  16. $vals = $actionsSelect->getValues();
  17. $vals[] = array(
  18. 'value' => 'ampromo_items',
  19. 'label' => Mage::helper('ampromo')->__('Auto add promo items with products'),
  20. );
  21. $vals[] = array(
  22. 'value' => 'ampromo_cart',
  23. 'label' => Mage::helper('ampromo')->__('Auto add promo items for the whole cart'),
  24. );
  25. $vals[] = array(
  26. 'value' => 'ampromo_product',
  27. 'label' => Mage::helper('ampromo')->__('Auto add the same product'),
  28. );
  29. $vals = $vals;
  30. $actionsSelect->setValues($vals);
  31. $actionsSelect->setOnchange('ampromo_hide()');
  32. $fldSet = $observer->getForm()->getElement('action_fieldset');
  33. $fldSet->addField('promo_sku', 'text', array(
  34. 'name' => 'promo_sku',
  35. 'label' => Mage::helper('ampromo')->__('Promo Items'),
  36. 'note' => Mage::helper('ampromo')->__('Comma separated list of the SKUs'),
  37. ),
  38. 'discount_amount'
  39. );
  40. }
  41. return $this;
  42. }
  43. /**
  44. * Process quote item validation and discount calculation
  45. * @param Varien_Event_Observer $observer
  46. */
  47. public function handleValidation($observer)
  48. {
  49. $rule = $observer->getEvent()->getRule();
  50. if ($rule->getSimpleAction() == 'ampromo_product') {
  51. try {
  52. $item = $observer->getEvent()->getItem();
  53. $discountStep = max(1, $rule->getDiscountStep());
  54. $maxDiscountQty = max(1, $rule->getDiscountQty());
  55. $discountAmount = max(1, $rule->getDiscountAmount());
  56. $qty = min(floor($item->getQty() * $discountAmount / $discountStep), $maxDiscountQty);
  57. // if simple option has a sku we need take parent SKU
  58. $product = $item->getProduct()->toArray();
  59. $sku = $product['sku'];
  60. if ($product['type_id'] == 'configurable') {
  61. $sku = $item->getProduct()->getSku();
  62. }
  63. // we support only simple, configurable, virtual
  64. if ($product['type_id']=='bundle' || $product['type_id'] =='downloadable') {
  65. return false;
  66. }
  67. $product = $this->_loadProduct($sku, $qty);
  68. if (!$product){
  69. return false;
  70. }
  71. $customOptions = array();
  72. foreach ($item->getOptions() as $optionItem) {
  73. if ((substr($optionItem->getCode(), 0, 6) == 'option') && ($optionItem->getCode() != 'option_ids')) {
  74. $customOptions[substr($optionItem->getCode(), 7)] = $optionItem->getValue();
  75. }
  76. }
  77. $request = new Varien_Object(array(
  78. 'qty' => $qty,
  79. 'options' => $customOptions
  80. ));
  81. $quote = $observer->getEvent()->getQuote();
  82. if ($this->_addProductToQuote($quote, $product, $request, $rule)){
  83. $msg = $rule->getStoreLabel(Mage::app()->getStore());
  84. if ($msg){
  85. $this->_showMessage($msg, false);
  86. }
  87. }
  88. }
  89. catch (Exception $e){
  90. $this->_showMessage(Mage::helper('ampromo')->__(
  91. 'We apologise, but there is an error while adding free items to the cart: %s', $e->getMessage()
  92. ));
  93. return false;
  94. }
  95. }
  96. if (!in_array($rule->getSimpleAction(), array('ampromo_items','ampromo_cart'))){
  97. return $this;
  98. }
  99. if (isset($this->_isHandled[$rule->getId()])){
  100. return $this;
  101. }
  102. $this->_isHandled[$rule->getId()] = true;
  103. $promoSku = $rule->getPromoSku();
  104. if (!$promoSku){
  105. return $this;
  106. }
  107. $quote = $observer->getEvent()->getQuote();
  108. $qty = $this->_getFreeItemsQty($rule, $quote);
  109. if (!$qty){
  110. //@todo - add new field for label table
  111. // and show message like "Add 2 more products to get free items"
  112. return $this;
  113. }
  114. $session = Mage::getSingleton('checkout/session');
  115. if ($session->getAmpromoId() != $quote->getId()){
  116. $session->setAmpromoDeletedItems(null);
  117. $session->setAmpromoMessages(null);
  118. $session->setAmpromoId($quote->getId());
  119. }
  120. $promoSku = explode(',', $promoSku);
  121. foreach ($promoSku as $sku){
  122. $sku = trim($sku);
  123. if (!$sku){
  124. continue;
  125. }
  126. $product = $this->_loadProduct($sku, $qty);
  127. if (!$product){
  128. continue;
  129. }
  130. if ($this->_addProductToQuote($quote, $product, $qty, $rule)){
  131. $message = $rule->getStoreLabel(Mage::app()->getStore());
  132. if ($message){
  133. $this->_showMessage($message, false);
  134. }
  135. }
  136. }
  137. return $this;
  138. }
  139. public function initFreeItems($observer)
  140. {
  141. $this->_isHandled = array();
  142. $quote = $observer->getQuote();
  143. if (!$quote)
  144. return $this;
  145. foreach ($quote->getItemsCollection() as $item) {
  146. if (!$item){
  147. continue;
  148. }
  149. if (!$item->getOptionByCode('ampromo_rule')){
  150. continue;
  151. }
  152. Mage::unregister('ampromo_del');
  153. Mage::register('ampromo_del', $item->getId());
  154. $item->isDeleted(true);
  155. $item->setData('qty_to_add', '0.0000');
  156. $quote->removeItem($item->getId());
  157. }
  158. return $this;
  159. }
  160. public function removeFreeItems($observer)
  161. {
  162. $item = $observer->getEvent()->getQuoteItem();
  163. if ($item->getId() != Mage::registry('ampromo_del')){
  164. $allowDelete = Mage::getStoreConfig('ampromo/general/allow_delete');
  165. if ($allowDelete){
  166. $arr = Mage::getSingleton('checkout/session')->getAmpromoDeletedItems();
  167. if (!is_array($arr)){
  168. $arr = array();
  169. }
  170. $arr[$item->getSku()] = true;
  171. Mage::getSingleton('checkout/session')->setAmpromoDeletedItems($arr);
  172. Mage::getSingleton('checkout/session')->setAmpromoId($item->getQuote()->getId());
  173. }
  174. }
  175. }
  176. public function updateFreeItems($observer)
  177. {
  178. $info = $observer->getInfo();
  179. $quote = $observer->getCart()->getQuote();
  180. foreach (array_keys($info) as $itemId) {
  181. $item = $quote->getItemById($itemId);
  182. if (!$item)
  183. continue;
  184. if (!$item->getOptionByCode('ampromo_rule'))
  185. continue;
  186. if (empty($info[$itemId]))
  187. continue;
  188. $info[$itemId]['remove'] = true;
  189. }
  190. return $this;
  191. }
  192. public function updateFreeItems1($observer)
  193. {
  194. $cart = $observer->getEvent()->getCart();
  195. $quote = $cart->getQuote();
  196. $allItems = $quote->getItemsCollection();
  197. $rule = array();
  198. foreach($this->_getMatchedPromoItem($allItems) as $item) {
  199. $ruleId = $item->getOptionByCode('ampromo_rule')->getValue();
  200. if(!isset($rule[$ruleId])) {
  201. $rule[$ruleId] = Mage::getModel('salesrule/rule')->load($ruleId);
  202. }
  203. $qty = $this->_getFreeItemsQty($rule[$ruleId],$quote);
  204. if($qty>0) {
  205. $item->setQty($qty);
  206. }
  207. else {
  208. $quote->removeItem($item->getId());
  209. }
  210. }
  211. return $this;
  212. }
  213. protected function _getMatchedPromoItem($items) {
  214. $found = array();
  215. foreach($items as $item) {
  216. if($item->getOptionByCode('ampromo_rule')) {
  217. $found[] = $item;
  218. }
  219. }
  220. return $found;
  221. }
  222. // find qty
  223. // (for the whole cart it is $rule->getDiscountQty()
  224. // for items it is (qty * (number of matched non-free items) / step)
  225. protected function _getFreeItemsQty($rule, $quote)
  226. {
  227. $amount = max(1, $rule->getDiscountAmount());
  228. $qty = 0;
  229. if ('ampromo_cart' == $rule->getSimpleAction()){
  230. $qty = $amount;
  231. }
  232. else {
  233. $step = max(1, $rule->getDiscountStep());
  234. foreach ($quote->getAllItems() as $item) {
  235. if (!$item)
  236. continue;
  237. if ($item->getOptionByCode('ampromo_rule'))
  238. continue;
  239. if (!$rule->getActions()->validate($item)) {
  240. continue;
  241. }
  242. $qty = $qty + $item->getQty();
  243. }
  244. $qty = floor($qty / $step) * $amount;
  245. $max = $rule->getDiscountQty();
  246. if ($max){
  247. $qty = min($max, $qty);
  248. }
  249. }
  250. return $qty;
  251. }
  252. protected function _loadProduct($sku, $qty)
  253. {
  254. // don't add already removed items
  255. $arr = Mage::getSingleton('checkout/session')->getAmpromoDeletedItems();
  256. if (!is_array($arr)){
  257. $arr = array();
  258. }
  259. if (isset($arr[$sku])){
  260. if (Mage::app()->getRequest()->getControllerName() == 'cart'){
  261. $message = Mage::helper('ampromo')->__(
  262. 'Your cart has deleted free items. <a href="%s">Restore them</a>?', Mage::getUrl('ampromo/cart/restore')
  263. );
  264. $this->_showMessage($message, false, true);
  265. }
  266. return false;
  267. }
  268. $product = Mage::getModel('catalog/product')->reset();
  269. $product->load($product->getIdBySku($sku)); // we have to load each product individually
  270. if (!$product->getId()){
  271. $this->_showMessage(Mage::helper('ampromo')->__(
  272. 'We apologise, but there is no promo item with the SKU `%s` in the catalog', $sku
  273. ));
  274. return false;
  275. }
  276. if (Mage_Catalog_Model_Product_Status::STATUS_ENABLED != $product->getStatus()){
  277. $this->_showMessage(Mage::helper('ampromo')->__(
  278. 'We apologise, but promo item with the SKU `%s` is not available', $sku
  279. ));
  280. return false;
  281. }
  282. $hasQty = $product->getStockItem()->checkQty($qty);
  283. $inStock = $product->getStockItem()->getIsInStock();
  284. if (!$inStock || !$hasQty){
  285. $this->_showMessage(Mage::helper('ampromo')->__(
  286. 'We apologise, but there are no %d item(s) with the SKU `%s` in the stock', $qty, $sku
  287. ));
  288. return false;
  289. }
  290. return $product;
  291. }
  292. protected function _addProductToQuote($quote, $product, $qty, $rule)
  293. {
  294. try {
  295. if ('multishipping' === Mage::app()->getRequest()->getControllerName()){
  296. return false;
  297. }
  298. $product->addCustomOption('ampromo_rule', $rule->getId());
  299. $item = $quote->getItemByProduct($product);
  300. if ($item) {
  301. return false;
  302. }
  303. // we need this line in case the initial quote was virtual
  304. if (!$product->isVirtual()){
  305. $quote->getBillingAddress()->setTotalAmount('subtotal', 0);
  306. }
  307. $item = $quote->addProduct($product, $qty);
  308. // required custom options or configurable product
  309. if (!is_object($item)){
  310. throw new Exception($item);
  311. }
  312. $item->setCustomPrice(0);
  313. $item->setOriginalCustomPrice(0);
  314. $prefix = Mage::getStoreConfig('ampromo/general/prefix');
  315. if ($prefix){
  316. $item->setName($prefix . ' ' . $item->getName());
  317. }
  318. $customMessage = Mage::getStoreConfig('ampromo/general/message');
  319. if ($customMessage){
  320. $item->setMessage($customMessage);
  321. }
  322. }
  323. catch (Exception $e){
  324. $this->_showMessage(Mage::helper('ampromo')->__(
  325. 'We apologise, but there is an error while adding free items to the cart: %s', $e->getMessage()
  326. ));
  327. return false;
  328. }
  329. return true;
  330. }
  331. protected function _showMessage($message, $isError = true, $showEachTime=false)
  332. {
  333. // show on cart page only
  334. $all = Mage::getSingleton('checkout/session')->getMessages(false)->toString();
  335. if (false !== strpos($all, $message))
  336. return;
  337. if ($isError && isset($_GET['debug'])){
  338. Mage::getSingleton('checkout/session')->addError($message);
  339. }
  340. else {
  341. $arr = Mage::getSingleton('checkout/session')->getAmpromoMessages();
  342. if (!is_array($arr)){
  343. $arr = array();
  344. }
  345. if (!in_array($message, $arr) || $showEachTime){
  346. Mage::getSingleton('checkout/session')->addNotice($message);
  347. $arr[] = $message;
  348. Mage::getSingleton('checkout/session')->setAmpromoMessages($arr);
  349. }
  350. }
  351. }
  352. }