Dừng lại các quy tắc khác Xử lý không áp dụng cho tất cả các mục


8

Dường như có một lỗi với "Dừng xử lý quy tắc tiếp theo" trong Magento CE1.9 / EE1.13 trong đó chỉ có mục đầu tiên trong giỏ hàng của bạn nhận được giảm giá.

Tôi mong đợi: Nếu tôi có nhiều quy tắc giỏ hàng, mỗi quy tắc có "Dừng xử lý quy tắc tiếp theo: Có", chỉ quy tắc đầu tiên trong số này sẽ được áp dụng, tuy nhiên, nó sẽ được áp dụng đầy đủ cho tất cả các mặt hàng phù hợp cho quy tắc đó.

Điều gì đang xảy ra: Giảm giá chỉ được áp dụng cho mặt hàng đầu tiên trong giỏ hàng, sau đó quá trình xử lý quy tắc được dừng lại.

Xem ảnh chụp màn hình: Mức giảm giá mà tôi mong đợi cho toàn bộ giỏ hàng là 50 đô la, nhưng do "Dừng xử lý quy tắc tiếp theo" tôi chỉ thấy 25 đô la.

Bảng quản trị Magento

Magento Frontend Checkout

Câu trả lời:


7

Tôi nghĩ điều này có thể là do _calculator được lưu trữ hiệu quả dưới dạng một singleton trong lớp Mage_SalesRule_Model_Quote_Discount, nghĩa là mục thứ hai được xử lý sẽ đạt $ this -> _ stopFurtherRules == true và bail.

Quá trình suy nghĩ của tôi là lưu trữ ID của quy tắc $ vẫn được xử lý, cho phép các mục tiếp theo chỉ xử lý quy tắc này.

Theo CE1.9.0.1 và EE1.14.0.1

Mage_SalesRule_Model_Validator dòng 316

- if ($this->_stopFurtherRules) {
+ if ($this->_stopFurtherRules !== false && $rule->getId() != $this->_stopFurtherRules) {

Mage_SalesRule_Model_Validator dòng 514

- $this->_stopFurtherRules = true;
+ $this->_stopFurtherRules = $rule->getId();

Đây là giải pháp đề xuất của tôi, tôi sẽ quan tâm để nghe lý do tại sao đây là một ý tưởng khủng khiếp!


2

Điều làm việc cho tôi là đặt lại cờ quy tắc dừng sau khi mỗi mục được xử lý để cho phép mục tiếp theo kiểm tra các quy tắc chống lại nó.

thêm dòng này:

$this->_stopFurtherRules = false;

trực tiếp sau vòng lặp này trong process()phương thức:

foreach ($this->_getRules() as $rule) {
    ...
}

Đó là trên đường dây 518, đối với tôi.

Theo ý kiến ​​của tôi, Magento có mặt trước. Nó lặp lại các mục, sau đó các quy tắc cho từng mục. Nó nên được lặp lại các quy tắc, sau đó là các mặt hàng, vì vậy một quy tắc có thể áp dụng cho toàn bộ giỏ hàng và chỉ sau đó ngăn chặn giảm giá thêm.


Vấn đề với cách tiếp cận đó là (và đây là một giả định chỉ từ việc liếc vào mã, chưa được kiểm tra), bạn mất chức năng 'dừng các quy tắc tiếp theo', tức là. tất cả các quy tắc của bạn sẽ được xử lý, ngay cả khi bạn có một quy tắc chỉ nên được áp dụng riêng. Cập nhật: Tôi đồng ý với nhận xét từ phía trước, tôi tin rằng nó nên xử lý các quy tắc sau đó các mục.
Joseph McDermott

@JosephMcDermott Điều đó không đúng. Nó vẫn dừng xử lý thêm các quy tắc cho mặt hàng đó. Đối với nhiều giảm giá, nó sẽ dừng lại ở cùng một quy tắc cho từng mặt hàng. Đối với bất kỳ mục nào mà quy tắc phù hợp trước đó không áp dụng, chúng chỉ có thể được giảm giá nhiều như các quy tắc áp dụng khác cho phép. Và không Magento chỉ cho phép một mã phiếu giảm giá được sử dụng cùng một lúc?
Walf

Tôi nghĩ rằng bạn đã hiểu sai ý định của cờ dừng quy tắc tiếp theo, đó là cấp quy tắc không phải cấp độ mục. Nếu bạn có hai quy tắc quảng cáo, không có quy tắc nào yêu cầu mã khuyến mãi, lần đầu tiên là 30% nếu bạn chi 300 bảng, lần thứ hai là 20% nếu bạn chi 200 bảng, bạn sẽ đánh dấu quy tắc đầu tiên là ưu tiên thấp hơn với quy tắc tiếp theo xử lý: có để khách hàng chỉ được giảm giá 30%, thay vì 30% theo sau là% 20. Hoặc bạn có thể giảm giá 10% toàn cầu mọi thứ (không có quảng cáo) nhưng nếu khách hàng nhập mã khuyến mãi, bạn không muốn khách hàng nhận được điều này, vì vậy hãy sử dụng các quy tắc tiếp theo.
Joseph McDermott

@JosephMcDermott Không, tôi chưa. Tôi nhận thức rõ mục đích của lá cờ đó, nhưng Magento rõ ràng không sử dụng nó như mong đợi. Giải pháp của tôi cho phép mỗi mục đi qua các quy tắc, ít nhất là cho đến khi chúng đánh cờ đó. Tôi chắc chắn có một cách tốt hơn để ngăn chặn hoàn toàn việc xử lý quy tắc giảm giá toàn bộ giỏ hàng, nhưng tôi đảm bảo nó phức tạp hơn nhiều so với việc đặt lại một biến.
Walf

Tốt thôi, ít nhất chúng tôi đồng ý rằng Magento đã làm điều này rất tệ :) Công chúng hiện có hai giải pháp để lựa chọn, một trong số đó ít nhất nên hướng các nhà phát triển đi đúng hướng.
Joseph McDermott

2

Điều này đã được sửa trong phiên bản sau của Magento CE. Trong 1.9.2.1, bạn có thể tìm thấy giải pháp, nhưng nó có thể đã được sửa sớm hơn.

Mã ban đầu trông như thế này:

$appliedRuleIds = array();
foreach ($this->_getRules() as $rule) {
    if ($this->_stopFurtherRules) {
        break;
    }

Và mã cố định phải là:

$appliedRuleIds = array();
$this->_stopFurtherRules = false;
foreach ($this->_getRules() as $rule) {
    // The if-clause is removed
    ...    

Sự khác biệt là $this->_stopFurtherRules = false;if ($this->_stopFurtherRules) {...}

Không có gì khác.

Hoặc, nếu bạn ở trên 1.9, bạn chỉ cần thay thế toàn bộ tệp mà không gặp nguy hiểm.

Hy vọng điều này sẽ giúp được ai đó.


1

Đối với tất cả những gì cần khắc phục sự cố đó, nên ghi đè phương thức quy trình cho lớp Mage_SalesRule_Model_Validator như dưới đây

public function process(Mage_Sales_Model_Quote_Item_Abstract $item)
{
    $item->setDiscountAmount(0);
    $item->setBaseDiscountAmount(0);
    $item->setDiscountPercent(0);
    $quote      = $item->getQuote();
    $address    = $this->_getAddress($item);

    $itemPrice              = $this->_getItemPrice($item);
    $baseItemPrice          = $this->_getItemBasePrice($item);
    $itemOriginalPrice      = $this->_getItemOriginalPrice($item);
    $baseItemOriginalPrice  = $this->_getItemBaseOriginalPrice($item);

    if ($itemPrice < 0) {
        return $this;
    }

    $appliedRuleIds = array();
    $this->_stopFurtherRules = false;
    foreach ($this->_getRules() as $rule) {

        /* @var $rule Mage_SalesRule_Model_Rule */
        if (!$this->_canProcessRule($rule, $address)) {
            continue;
        }

        if (!$rule->getActions()->validate($item)) {
            continue;
        }

        $qty = $this->_getItemQty($item, $rule);
        $rulePercent = min(100, $rule->getDiscountAmount());

        $discountAmount = 0;
        $baseDiscountAmount = 0;
        //discount for original price
        $originalDiscountAmount = 0;
        $baseOriginalDiscountAmount = 0;

        switch ($rule->getSimpleAction()) {
            case Mage_SalesRule_Model_Rule::TO_PERCENT_ACTION:
                $rulePercent = max(0, 100-$rule->getDiscountAmount());
            //no break;
            case Mage_SalesRule_Model_Rule::BY_PERCENT_ACTION:
                $step = $rule->getDiscountStep();
                if ($step) {
                    $qty = floor($qty/$step)*$step;
                }
                $_rulePct = $rulePercent/100;
                $discountAmount    = ($qty * $itemPrice - $item->getDiscountAmount()) * $_rulePct;
                $baseDiscountAmount = ($qty * $baseItemPrice - $item->getBaseDiscountAmount()) * $_rulePct;
                //get discount for original price
                $originalDiscountAmount    = ($qty * $itemOriginalPrice - $item->getDiscountAmount()) * $_rulePct;
                $baseOriginalDiscountAmount =
                    ($qty * $baseItemOriginalPrice - $item->getDiscountAmount()) * $_rulePct;

                if (!$rule->getDiscountQty() || $rule->getDiscountQty()>$qty) {
                    $discountPercent = min(100, $item->getDiscountPercent()+$rulePercent);
                    $item->setDiscountPercent($discountPercent);
                }
                break;
            case Mage_SalesRule_Model_Rule::TO_FIXED_ACTION:
                $quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount());
                $discountAmount    = $qty * ($itemPrice-$quoteAmount);
                $baseDiscountAmount = $qty * ($baseItemPrice-$rule->getDiscountAmount());
                //get discount for original price
                $originalDiscountAmount    = $qty * ($itemOriginalPrice-$quoteAmount);
                $baseOriginalDiscountAmount = $qty * ($baseItemOriginalPrice-$rule->getDiscountAmount());
                break;

            case Mage_SalesRule_Model_Rule::BY_FIXED_ACTION:
                $step = $rule->getDiscountStep();
                if ($step) {
                    $qty = floor($qty/$step)*$step;
                }
                $quoteAmount        = $quote->getStore()->convertPrice($rule->getDiscountAmount());
                $discountAmount     = $qty * $quoteAmount;
                $baseDiscountAmount = $qty * $rule->getDiscountAmount();
                break;

            case Mage_SalesRule_Model_Rule::CART_FIXED_ACTION:
                if (empty($this->_rulesItemTotals[$rule->getId()])) {
                    Mage::throwException(Mage::helper('salesrule')->__('Item totals are not set for rule.'));
                }

                /**
                 * prevent applying whole cart discount for every shipping order, but only for first order
                 */
                if ($quote->getIsMultiShipping()) {
                    $usedForAddressId = $this->getCartFixedRuleUsedForAddress($rule->getId());
                    if ($usedForAddressId && $usedForAddressId != $address->getId()) {
                        break;
                    } else {
                        $this->setCartFixedRuleUsedForAddress($rule->getId(), $address->getId());
                    }
                }
                $cartRules = $address->getCartFixedRules();
                if (!isset($cartRules[$rule->getId()])) {
                    $cartRules[$rule->getId()] = $rule->getDiscountAmount();
                }

                if ($cartRules[$rule->getId()] > 0) {
                    if ($this->_rulesItemTotals[$rule->getId()]['items_count'] <= 1) {
                        $quoteAmount = $quote->getStore()->convertPrice($cartRules[$rule->getId()]);
                        $baseDiscountAmount = min($baseItemPrice * $qty, $cartRules[$rule->getId()]);
                    } else {
                        $discountRate = $baseItemPrice * $qty /
                            $this->_rulesItemTotals[$rule->getId()]['base_items_price'];
                        $maximumItemDiscount = $rule->getDiscountAmount() * $discountRate;
                        $quoteAmount = $quote->getStore()->convertPrice($maximumItemDiscount);

                        $baseDiscountAmount = min($baseItemPrice * $qty, $maximumItemDiscount);
                        $this->_rulesItemTotals[$rule->getId()]['items_count']--;
                    }

                    $discountAmount = min($itemPrice * $qty, $quoteAmount);
                    $discountAmount = $quote->getStore()->roundPrice($discountAmount);
                    $baseDiscountAmount = $quote->getStore()->roundPrice($baseDiscountAmount);

                    //get discount for original price
                    $originalDiscountAmount = min($itemOriginalPrice * $qty, $quoteAmount);
                    $baseOriginalDiscountAmount = $quote->getStore()->roundPrice($baseItemOriginalPrice);

                    $cartRules[$rule->getId()] -= $baseDiscountAmount;
                }
                $address->setCartFixedRules($cartRules);

                break;

            case Mage_SalesRule_Model_Rule::BUY_X_GET_Y_ACTION:
                $x = $rule->getDiscountStep();
                $y = $rule->getDiscountAmount();
                if (!$x || $y > $x) {
                    break;
                }
                $buyAndDiscountQty = $x + $y;

                $fullRuleQtyPeriod = floor($qty / $buyAndDiscountQty);
                $freeQty  = $qty - $fullRuleQtyPeriod * $buyAndDiscountQty;

                $discountQty = $fullRuleQtyPeriod * $y;
                if ($freeQty > $x) {
                    $discountQty += $freeQty - $x;
                }

                $discountAmount    = $discountQty * $itemPrice;
                $baseDiscountAmount = $discountQty * $baseItemPrice;
                //get discount for original price
                $originalDiscountAmount    = $discountQty * $itemOriginalPrice;
                $baseOriginalDiscountAmount = $discountQty * $baseItemOriginalPrice;
                break;
        }

        $result = new Varien_Object(array(
            'discount_amount'      => $discountAmount,
            'base_discount_amount' => $baseDiscountAmount,
        ));
        Mage::dispatchEvent('salesrule_validator_process', array(
            'rule'    => $rule,
            'item'    => $item,
            'address' => $address,
            'quote'   => $quote,
            'qty'     => $qty,
            'result'  => $result,
        ));

        $discountAmount = $result->getDiscountAmount();
        $baseDiscountAmount = $result->getBaseDiscountAmount();

        $percentKey = $item->getDiscountPercent();
        /**
         * Process "delta" rounding
         */
        if ($percentKey) {
            $delta      = isset($this->_roundingDeltas[$percentKey]) ? $this->_roundingDeltas[$percentKey] : 0;
            $baseDelta  = isset($this->_baseRoundingDeltas[$percentKey])
                ? $this->_baseRoundingDeltas[$percentKey]
                : 0;
            $discountAmount += $delta;
            $baseDiscountAmount += $baseDelta;

            $this->_roundingDeltas[$percentKey]     = $discountAmount -
                $quote->getStore()->roundPrice($discountAmount);
            $this->_baseRoundingDeltas[$percentKey] = $baseDiscountAmount -
                $quote->getStore()->roundPrice($baseDiscountAmount);
            $discountAmount = $quote->getStore()->roundPrice($discountAmount);
            $baseDiscountAmount = $quote->getStore()->roundPrice($baseDiscountAmount);
        } else {
            $discountAmount     = $quote->getStore()->roundPrice($discountAmount);
            $baseDiscountAmount = $quote->getStore()->roundPrice($baseDiscountAmount);
        }

        /**
         * We can't use row total here because row total not include tax
         * Discount can be applied on price included tax
         */

        $itemDiscountAmount = $item->getDiscountAmount();
        $itemBaseDiscountAmount = $item->getBaseDiscountAmount();

        $discountAmount     = min($itemDiscountAmount + $discountAmount, $itemPrice * $qty);
        $baseDiscountAmount = min($itemBaseDiscountAmount + $baseDiscountAmount, $baseItemPrice * $qty);

        $item->setDiscountAmount($discountAmount);
        $item->setBaseDiscountAmount($baseDiscountAmount);

        $item->setOriginalDiscountAmount($originalDiscountAmount);
        $item->setBaseOriginalDiscountAmount($baseOriginalDiscountAmount);

        $appliedRuleIds[$rule->getRuleId()] = $rule->getRuleId();

        $this->_maintainAddressCouponCode($address, $rule);
        $this->_addDiscountDescription($address, $rule);

        if ($rule->getStopRulesProcessing()) {
            $this->_stopFurtherRules = true;
            break;
        }
    }

    $item->setAppliedRuleIds(join(',',$appliedRuleIds));
    $address->setAppliedRuleIds($this->mergeIds($address->getAppliedRuleIds(), $appliedRuleIds));
    $quote->setAppliedRuleIds($this->mergeIds($quote->getAppliedRuleIds(), $appliedRuleIds));

    return $this;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.