分享Magento1.9.3.1 Coupon 的Bug與修正方式
此次的BUG是在結帳時候,如果你使用Coupon功能獲得折扣,之後就算取消或者此筆結帳完成,卻仍然一直保有Coupon獲得的優惠折扣,這是在開發其中的一個商業網站QA測試驗收時候發現的,先前的magento專案都沒測出這個問題,所以進而去比對其他專案的magento版本和source code,發現在magento的1.9.0.1和1.9.2.0版本,結帳流程的程式碼沒有一些參數設置和驗證,而1.9.3.1版本多了那些參數的設置與驗證導致BUG的產生。
復原BUG的流程
- 將產品加入購物車
- 執行Coupon code
- 取消Coupon code
- 顯示成功取消Coupon code
- 進行結帳
- 確認完帳單和運送地址步驟
- 回到購物車或完成結帳流程
- 再次回到購物車頁面,Coupon code優惠卻還存在
產生這個BUG的原因在於第2步驟的時候,執行couponPostAction裡多了儲存setCartCouponCode的程式碼(Magento1.9.3.1才發現有的),而在第3步驟執行移除CouponCode的時候,只有移除除CouponCode的參數卻沒有移除CartCouponCode,到了第6步驟會去驗證是否有CartCouponCode的值,如果成立CouponCode將會恢復CouponCode折扣優惠,所以先前第3步驟的取消形同虛設,甚至到了第7步驟完成結帳了,也沒有取消CartCouponCode的機制,導致優惠會一直存在著。
列出問題code與檔案位置
第2步驟、第3步驟
檔案位置:app\code\core\Mage\Checkout\controllers\CartController.php
public function couponPostAction() { /** * No reason continue with empty shopping cart */ if (!$this->_getCart()->getQuote()->getItemsCount()) { $this->_goBack(); return; } $couponCode = (string) $this->getRequest()->getParam('coupon_code'); if ($this->getRequest()->getParam('remove') == 1) { $couponCode = ''; } $oldCouponCode = $this->_getQuote()->getCouponCode(); if (!strlen($couponCode) && !strlen($oldCouponCode)) { $this->_goBack(); return; } try { $codeLength = strlen($couponCode); $isCodeLengthValid = $codeLength && $codeLength <= Mage_Checkout_Helper_Cart::COUPON_CODE_MAX_LENGTH; $this->_getQuote()->getShippingAddress()->setCollectShippingRates(true); $this->_getQuote()->setCouponCode($isCodeLengthValid ? $couponCode : '') ->collectTotals() ->save(); if ($codeLength) { if ($isCodeLengthValid && $couponCode == $this->_getQuote()->getCouponCode()) { $this->_getSession()->addSuccess( $this->__('Coupon code "%s" was applied.', Mage::helper('core')->escapeHtml($couponCode)) ); $this->_getSession()->setCartCouponCode($couponCode); //1.9.3.1新增儲存CartCouponCode參數,卻沒有任何移除此參數的機制 } else { $this->_getSession()->addError( $this->__('Coupon code "%s" is not valid.', Mage::helper('core')->escapeHtml($couponCode)) ); } } else { $this->_getSession()->addSuccess($this->__('Coupon code was canceled.')); } } catch (Mage_Core_Exception $e) { $this->_getSession()->addError($e->getMessage()); } catch (Exception $e) { $this->_getSession()->addError($this->__('Cannot apply the coupon code.')); Mage::logException($e); } $this->_goBack(); }
第6步驟
檔案位置:app\code\core\Mage\Checkout\Model\Type\Onepage.php
public function saveBilling($data, $customerAddressId) { ********************以上省略***************** if (!$this->getQuote()->isVirtual()) { /** * Billing address using otions */ $usingCase = isset($data['use_for_shipping']) ? (int)$data['use_for_shipping'] : 0; switch ($usingCase) { case 0: $shipping = $this->getQuote()->getShippingAddress(); $shipping->setSameAsBilling(0); break; case 1: $billing = clone $address; $billing->unsAddressId()->unsAddressType(); $shipping = $this->getQuote()->getShippingAddress(); $shippingMethod = $shipping->getShippingMethod(); // Billing address properties that must be always copied to shipping address $requiredBillingAttributes = array('customer_address_id'); // don't reset original shipping data, if it was not changed by customer foreach ($shipping->getData() as $shippingKey => $shippingValue) { if (!is_null($shippingValue) && !is_null($billing->getData($shippingKey)) && !isset($data[$shippingKey]) && !in_array($shippingKey, $requiredBillingAttributes) ) { $billing->unsetData($shippingKey); } } $shipping->addData($billing->getData()) ->setSameAsBilling(1) ->setSaveInAddressBook(0) ->setShippingMethod($shippingMethod) ->setCollectShippingRates(true); $this->getCheckout()->setStepData('shipping', 'complete', true); $this->_setCartCouponCode();//檢查CartCouponCode參數值 break; } } ********************以下省略***************** } protected function _setCartCouponCode() { //如果有CartCouponCode的值將重新設置couponCode if ($couponCode = $this->getCheckout()->getCartCouponCode()) { $this->getQuote()->setCouponCode($couponCode); } return $this; }
修正方式分享
為了在不動到Magento原生程式碼和可以快速的移植到其他專案上,決定開發一個Fixcoupon extension,採用event/observer觸發方式去執行。
主要程式碼
config.xml
public function saveBilling($data, $customerAddressId) { ********************以上省略***************** if (!$this->getQuote()->isVirtual()) { /** * Billing address using otions */ $usingCase = isset($data['use_for_shipping']) ? (int)$data['use_for_shipping'] : 0; switch ($usingCase) { case 0: $shipping = $this->getQuote()->getShippingAddress(); $shipping->setSameAsBilling(0); break; case 1: $billing = clone $address; $billing->unsAddressId()->unsAddressType(); $shipping = $this->getQuote()->getShippingAddress(); $shippingMethod = $shipping->getShippingMethod(); // Billing address properties that must be always copied to shipping address $requiredBillingAttributes = array('customer_address_id'); // don't reset original shipping data, if it was not changed by customer foreach ($shipping->getData() as $shippingKey => $shippingValue) { if (!is_null($shippingValue) && !is_null($billing->getData($shippingKey)) && !isset($data[$shippingKey]) && !in_array($shippingKey, $requiredBillingAttributes) ) { $billing->unsetData($shippingKey); } } $shipping->addData($billing->getData()) ->setSameAsBilling(1) ->setSaveInAddressBook(0) ->setShippingMethod($shippingMethod) ->setCollectShippingRates(true); $this->getCheckout()->setStepData('shipping', 'complete', true); $this->_setCartCouponCode();//檢查CartCouponCode參數值 break; } } ********************以下省略***************** } protected function _setCartCouponCode() { //如果有CartCouponCode的值將重新設置couponCode if ($couponCode = $this->getCheckout()->getCartCouponCode()) { $this->getQuote()->setCouponCode($couponCode); } return $this; }
Observer.php
public function cancelCoupon(Varien_Event_Observer $observer) { $controller = $observer->getControllerAction(); if ($controller->getRequest()->getParam('remove') == 1) { Mage::getSingleton("checkout/session")->unsetData('cart_coupon_code'); } return $this; } public function afterCheckoutRemoveCoupon() { Mage::getSingleton("checkout/session")->unsetData('cart_coupon_code'); return $this; }
更多Magento相關文章請見: Magento教學導覽
參考資料
https://tutel.me/c/programming/questions/42839090/coupon+is+always+readded+during+checkout
我要留言