如何在Magento2中设置多个sku买二送一规则

前言,最近黑五活动来临,运营决定搞个买二送一,买四送二,送的商品以购物车最便宜的来。

遇到的问题

在Magento2中,虽然有买X送Y的购物车优惠规则,但是,仅仅是针对单个SKU来设置规则的,而我们是针对购物车所有产品来计算规则的。

然后也有考虑通过插件来处理,但是市面上的插件都是买一送一,送最便宜这种的,就是买X送Y,X和Y都是要选择固定的商品。所以,最终只能考虑代码处理。

开始后台设置规则

1.通过谷歌搜索到的方法设置。先在后台设置一个购物车优惠规则,命名为”Buy 2 get 1 free

2.设置优惠规则条件,如果是针对所有产品,则为空

3.设置优惠规则,Percent of product price discount,优惠比率为100%。如图所示

开始编写代码

1.在/vendor/magento/module-sales-rule/etc/events.xml,中添加事件。如果有重写此模块,则在重写模块的events.xml中增加标签,没有events.xml则新增此文件后再增加

    <event name="salesrule_validator_process">
        <observer name="custom_cart_rules" instance="\Magento\SalesRule\Observer\CustomCartPriceRules" />
    </event>

2.创建绑定事件的文件,在vendor/magento/module-sales-rule/Observer/CustomCartPriceRules.php

<?php
namespace Magento\SalesRule\Observer;

use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\App\ObjectManager;

class CustomCartPriceRules implements ObserverInterface {
    public function __construct() {

    }

    /**
     *
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(\Magento\Framework\Event\Observer $observer) {
        $result = $observer->getEvent()->getResult();
        $item = $observer->getEvent()->getItem();
        $rule = $observer->getEvent()->getRule();
        $address = $observer->getEvent()->getAddress();
        $qty = $item->getQty();

        if ($rule->getData('name') == 'Buy 2 get 1 free'):

            // overriding magento rules here and updating Almusbah Offer
            $result->setAmount(0)
                ->setBaseAmount(0)
                ->setOriginalAmount(0)
                ->setBaseOriginalAmount(0);

            $item->setDiscountPercent(0);


            $products = [];
            $z = 0;
            $totalQty = 0;
            $dA = 0;
            //first the total free quantity needs to be calculated based on all items in the quote
            $quote = $observer->getEvent()->getQuote();
            $totalFreeQty = (int) ($quote->getItemsSummaryQty() / 2);

            //second you need all quote items sorted by calculation_price ascending;
            //that won't work with collection sorting, therefore you need to use the items array
            //to make sorting easy we use the price as key
            $allItems = $quote->getAllVisibleItems();
            $sortedItems = [];
            foreach ($allItems as $quoteItem) {
                //convert the float price into integer preserving all decimal positions
                $priceKey = (int) ($quoteItem->getData('calculation_price') * 1000);
                //if item qith the same price already exists, we increment until we find a free key
                //in this way we make sure that no key is overwritten and we keep the price sort order
                //in case that two items have the same price the first item of the collection will be sorted first
                while (isset($sortedItems[$priceKey])){
                    $priceKey++;
                }
                $sortedItems[$priceKey] = $quoteItem;
            }
            ksort($sortedItems,SORT_NUMERIC);

            //now you can use your foreach loop as follows (I have changed only the freeQty calculation)
            foreach ($sortedItems as $q):
                $validate = $rule->getActions()->validate($q);

                if ($validate):
                    $products[$z]['sku'] = $q->getData('sku');
                    $products[$z]['qty'] = $q->getData('qty');
                    $products[$z]['freeQty'] = 0;
                    if ($totalFreeQty > 0):
                        if ($totalFreeQty > $products[$z]['qty']){
                            $products[$z]['freeQty'] = $products[$z]['qty'];
                            $totalFreeQty = $totalFreeQty - $products[$z]['qty'];
                        } else {
                            $products[$z]['freeQty'] = $totalFreeQty;
                            $totalFreeQty = 0;
            }
                        $products[$z]['applyDiscount'] = 1;
                        $dicountPercent = 100;
                        $dA = ($products[$z]['freeQty'] * $q->getData('calculation_price'));
                        $products[$z]['discountAmount'] = $dA;
                    endif;
                    $z++;
                endif;
            endforeach;
            $chkCurrentSku = $item->getSku();

            foreach ($products as $p):
                if(isset($p['applyDiscount']) && !empty($p['applyDiscount']) && $chkCurrentSku == $p['sku']):
                    $discountAmount = $p['discountAmount'];
                    $fullDiscount = 100;
                    $item->setDiscountPercent($fullDiscount);
                    $this->almusbahBuy2Get1Offer($discountAmount,$result);
                endif;
            endforeach;

        endif;
    }

    public function almusbahBuy2Get1Offer($discountAmount, $result) {

        $result->setAmount($discountAmount)
            ->setBaseAmount($discountAmount)
            ->setOriginalAmount($discountAmount)
            ->setBaseOriginalAmount($discountAmount);
    }

}

查看效果

相关文章

0 0 投票数
文章评分
订阅评论
提醒
0 评论
最旧
最新 最多投票
内联反馈
查看所有评论