分享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
我要留言