文章彙整

分享Magento1.9.3.1 Coupon 的Bug與修正方式

By Astral Web 10 months agoNo Comments
首頁  /  Magento  /  解決Magento問題  /  分享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的流程

  1. 將產品加入購物車
  2. 執行Coupon code
  3. 取消Coupon code
  4. 顯示成功取消Coupon code
  5. 進行結帳
  6. 確認完帳單和運送地址步驟
  7. 回到購物車或完成結帳流程
  8. 再次回到購物車頁面,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

以上內容由Astralweb 歐斯瑞編寫製作

 000

推薦文章

Category:
  解決Magento問題

留下回應

你的電子郵件地址不會被公開.

取得獨家電子商務祕技

建立更好的策略靈感

跟上全球的網路趨勢

絕佳的電商解決方案

電子商務戰略全指南

每月發送電商戰略指南,只要填寫E-mail即可訂閱!

請到您的信箱確認,即可完成訂閱。