In magento 2 cart page how add a more than one discount

I want be like this:

enter image description here

But i get like this

enter image description here

app/code/Bg/SpecialPromotion/view/frontend/web/js/view/checkout/cart/total/fee.js

 define([
    'ko',
    'uiComponent',
    'Magento_Checkout/js/model/quote',
    'Magento_Catalog/js/price-utils',
    'Magento_Checkout/js/model/totals'

], function (ko, Component, quote, priceUtils, totals) {
    'use strict';
    var show_hide_Extrafee_blockConfig = window.checkoutConfig.show_hide_Extrafee_block;
    var fee_label = window.checkoutConfig.fee_label;
    var custom_fee_amount = window.checkoutConfig.custom_fee_amount;

    return Component.extend({

        totals: quote.getTotals(),
        canVisibleExtrafeeBlock: show_hide_Extrafee_blockConfig,
        getFormattedPrice: ko.observable(priceUtils.formatPrice(custom_fee_amount, quote.getPriceFormat())),
        getFeeLabel:ko.observable(fee_label),

        isDisplayed: function () {
            return this.getValue() != 0;
        },
        getValue: function() {
            var price = 0;
            if (this.totals() && totals.getSegment('fee')) {
                price = totals.getSegment('fee').value;
            }
            return price;
        }
    });
});

app/code/Bg/SpecialPromotion/view/frontend/template/checkout/cart/total/fee.html

<!-- ko if: isDisplayed() -->
<tr class="totals fee excl" >
    <th class="mark" colspan="1" scope="row" data-bind="text: getFeeLabel()"></th>
    <td class="amount">
        <span class="price" data-bind="text: getFormattedPrice()"></span>
    </td>
</tr>
<!-- /ko -->

etc/sales.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Sales:etc/sales.xsd">
    <section name="quote">
        <group name="totals">
            <item name="fee" instance="Bg\SpecialPromotion\Model\Quote\Total\Fee" sort_order="150"/>
        </group>
    </section>
 <section name="order_invoice">
        <group name="totals">
            <item name="fee" instance="Bg\SpecialPromotion\Model\Invoice\Total\Fee" sort_order="160"/>
        </group>
    </section>
 <section name="order_creditmemo">
        <group name="totals">
            <item name="fee" instance="Bg\SpecialPromotion\Model\Creditmemo\Total\Fee" sort_order="160"/>
        </group>
    </section>
</config>

app/code/Bg/SpecialPromotion/Model/Quote/Total/Fee.php

<?php
namespace Bg\SpecialPromotion\Model\Quote\Total;

use Magento\Store\Model\ScopeInterface;

class Fee extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
{

    protected $helperData;
    protected $_priceCurrency;


    protected $quoteValidator = null;

    public function __construct(\Magento\Quote\Model\QuoteValidator $quoteValidator,
                                \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
                                \Bg\SpecialPromotion\Helper\Data $helperData)
    {
        $this->quoteValidator = $quoteValidator;
        $this->_priceCurrency = $priceCurrency;
        $this->helperData = $helperData;
    }

    public function collect(
        \Magento\Quote\Model\Quote $quote,
        \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment,
        \Magento\Quote\Model\Quote\Address\Total $total
    )
    {
        parent::collect($quote, $shippingAssignment, $total);
        if (!count($shippingAssignment->getItems())) {
            return $this;
        }
        // $test = $this->helperData->getExtrafee();
        // print_r($test);exit;

        $enabled = $this->helperData->isModuleEnabled();
        $minimumOrderAmount = $this->helperData->getMinimumOrderAmount();
        $subtotal = $total->getTotalAmount('subtotal');
        if ($enabled && $minimumOrderAmount <= $subtotal) {
              $fee = $this->helperData->getExtrafee();
            //Try to test with sample value
             // $fee=-50;
            $total->setTotalAmount('fee', $fee);
            $total->setBaseTotalAmount('fee', $fee);
            $total->setFee($fee);
            $quote->setFee($fee);


            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
            $productMetadata = $objectManager->get('Magento\Framework\App\ProductMetadataInterface');
            $version = (float)$productMetadata->getVersion(); 

            if($version > 2.1)
            {
                //$total->setGrandTotal($total->getGrandTotal() + $fee);
            }
            else
            {
                $total->setGrandTotal($total->getGrandTotal()+$fee);
            }

        }
        return $this;
    }

    /**
     * @param \Magento\Quote\Model\Quote $quote
     * @param \Magento\Quote\Model\Quote\Address\Total $total
     * @return array
     */
    public function fetch(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Model\Quote\Address\Total $total)
    {

        $enabled = $this->helperData->isModuleEnabled();
        $minimumOrderAmount = $this->helperData->getMinimumOrderAmount();
        $subtotal = $quote->getSubtotal();
        $fee = $quote->getFee();

        $result = [];
        if ($enabled && ($minimumOrderAmount <= $subtotal) && $fee) {
            $result = [
                'code' => 'fee',
                'title' => $this->helperData->getFeeLabel(),
                'value' => $fee
            ];
        }
        return $result;
    }

    /**
     * Get Subtotal label
     *
     * @return \Magento\Framework\Phrase
     */
    public function getLabel()
    {
        return __('Extra Fee');
    }

    /**
     * @param \Magento\Quote\Model\Quote\Address\Total $total
     */
    protected function clearValues(\Magento\Quote\Model\Quote\Address\Total $total)
    {
        $total->setTotalAmount('subtotal', 0);
        $total->setBaseTotalAmount('subtotal', 0);
        $total->setTotalAmount('tax', 0);
        $total->setBaseTotalAmount('tax', 0);
        $total->setTotalAmount('discount_tax_compensation', 0);
        $total->setBaseTotalAmount('discount_tax_compensation', 0);
        $total->setTotalAmount('shipping_discount_tax_compensation', 0);
        $total->setBaseTotalAmount('shipping_discount_tax_compensation', 0);
        $total->setSubtotalInclTax(0);
        $total->setBaseSubtotalInclTax(0);

    }
}

app/code/Bg/SpecialPromotion/Helper/Data.php

 <?php

    namespace Bg\SpecialPromotion\Helper;
    use Magento\Framework\App\Helper\AbstractHelper;
    use Magento\Framework\App\Helper\Context;
    use Magento\Framework\App\Config\ScopeConfigInterface;
    use Magento\Store\Model\ScopeInterface;
    use Magento\SalesRule\Model\RuleFactory;
    use \Magento\Framework\Serialize\Serializer\Json;
    use \Magento\SalesRule\Model\Rule;
    class Data extends AbstractHelper
    {


        protected $scopeConfig;
        protected $_ruleFactory;

        public function __construct(
            Context $context,
            ScopeConfigInterface $scopeInterface,
             RuleFactory $ruleFactory ,
            Rule  $ruleModel   ) {
            parent::__construct($context);
            $this->scopeConfig = $scopeInterface;
            $this->_ruleFactory = $ruleFactory;
            $this->ruleModel=$ruleModel;
        }
        public function isModuleEnabled()
        {
            return  1;
        }
        public function getMinimumOrderAmount()
        {

            return 1;
        }

        public function getExtrafee()
        {
            $amount = $this->getFinalRule();
            $amt = array();
           foreach ($amount as $key => $value) {
            $amt[] = $value['amount'];
           }
           $sum_of_amount = array_sum($amt);
            return $sum_of_amount;
        }
         public function getFeeLabel()
        {
           $name = $this->getFinalRule();
            $label = array();
           foreach ($name as $key => $value) {
            $label[] = $value['name'];
           }
            // $label = 'Special Discount';
            return $label;
        }
 public function getFinalRule()
    {
      $activeRule = $this->getActiveRule();
      $result =array();
      $rule_info = array();

      foreach ($activeRule as $key => $rule) {

             $id = $rule['rule_id'];
             $action = $rule['simple_action'];
             $name   = $rule['description'];
             $discount_amount = $rule['discount_amount'];
             $max_discount  =  $rule['max_discount'];
             $discount_qty =  $rule['discount_qty'];
             $discount_step = $rule['discount_step'];
             $priceselector = $rule['priceselector'];
             $apply_discount_to =$rule['apply_discount_to'];
             // $apply_to_shipping = $rule['apply_to_shipping'];
             // $stop_rules_processing = $rule[' stop_rules_processing'];


        switch($action){

        case "thecheapest":
                $cartItem = $this->getCartItem();
                $amt = array();
                foreach ($cartItem as $key => $item) {
                  $qty = $item->getQty();
                  if($qty >= 2)
                  {
                    if($priceselector == 0)
                    {
                      $price = $item->getProduct()->getFinalPrice();
                    }
                    else if($priceselector == 2)
                    {
                      $price = $item->getProduct()->getPrice();
                    }
                    else
                    {
                      $price = $item->getProduct()->getFinalPrice();
                    }
                    if(($qty%2==0))
                    {
                       $x_product = ($qty/2);
                       $final_amt = ($price * $x_product);
                       $amt[] = $final_amt;
                    }
                    else
                    {
                      $x_odd = $qty - 1;
                      $x_product = ($x_odd/2);
                      $final_amt = (($price * $x_product));
                      $amt[] = $final_amt;
                    }
                   }
                  } 

                $amount = array_sum($amt);
                $finalDiscount = -$amount;
                $rule_info[]= [
                  'name' => $name,
                  'amount'=> $finalDiscount,

                ];
                break;

        case "moneyamount":
              $cartTotal = $this->getCartTotal();
              if($cartTotal >= $discount_step)
              {
                 $get_x = $cartTotal/$discount_step;
                 $lower_round_off = floor($get_x);
                 $final_amt = $lower_round_off * $discount_amount;
              }
              else
              {
                $final_amt =0;
              }
               $finalDiscount = -$final_amt;
               $rule_info[] = [
                        'name' => $name,
                        'amount'=> $finalDiscount,
                      ];
       break;

        } // end  of swich case

      } // end of for loop
      return $rule_info;
    }
    }
有帮助吗?

解决方案

Try to get additional fee from config provider

app/code/Bg/SpecialPromotion/Helper/Data.php

<?php
    namespace Bg\SpecialPromotion\Helper;

    use Magento\Framework\App\Helper\AbstractHelper;
    use Magento\Framework\App\Helper\Context;
    use Magento\Framework\App\Config\ScopeConfigInterface;
    use Magento\Store\Model\ScopeInterface;
    use Magento\SalesRule\Model\RuleFactory;
    use \Magento\Framework\Serialize\Serializer\Json;
    use \Magento\SalesRule\Model\Rule;

    class Data extends AbstractHelper
    {
        protected $scopeConfig;
        protected $_ruleFactory;
        protected $ruleModel;

        public function __construct(
            Context $context,
            ScopeConfigInterface $scopeInterface,
            RuleFactory $ruleFactory ,
            Rule  $ruleModel
        ) {
            parent::__construct($context);
            $this->scopeConfig = $scopeInterface;
            $this->_ruleFactory = $ruleFactory;
            $this->ruleModel=$ruleModel;
        }

        public function isModuleEnabled()
        {
            return  true;
        }

        public function getMinimumOrderAmount()
        {
            return true;
        }

        public function getExtrafee()
        {
            $amount = $this->getFinalRule();
            $amt = array();
            foreach ($amount as $key => $value) {
                $amt[] = $value['amount'];
            }
            $sum_of_amount = array_sum($amt);
            return $sum_of_amount;
        }

        public function getFeeLabel()
        {
            $name = $this->getFinalRule();
            $label = array();
            foreach ($name as $key => $value) {
                $label[] = $value['name'];
            }
            // $label = 'Special Discount';
            return $label;
        }

        public function getShippingPrices()
        {
            $data = $this->getFinalRule();
            $shippingData = array();
            foreach ($data as $key => $value) {
               $shippingData[$key] = [
                           'title' => $value['name'],
                           'value'=> $value['amount']
            ];
            }
            return $shippingData;
        }

        public function getFinalRule()
        {
            $activeRule = $this->getActiveRule();
            $result =array();
            $rule_info = array();
            foreach ($activeRule as $key => $rule) {

                $id                = $rule['rule_id'];
                $action            = $rule['simple_action'];
                $name              = $rule['description'];
                $discount_amount   = $rule['discount_amount'];
                $max_discount      =  $rule['max_discount'];
                $discount_qty      =  $rule['discount_qty'];
                $discount_step     = $rule['discount_step'];
                $priceselector     = $rule['priceselector'];
                $apply_discount_to = $rule['apply_discount_to'];
                //$apply_to_shipping = $rule['apply_to_shipping'];
                //$stop_rules_processing = $rule[' stop_rules_processing'];


                switch($action){
                    case "thecheapest":
                        $cartItem = $this->getCartItem();
                        $amt = array();
                        foreach ($cartItem as $key => $item) {
                            $qty = $item->getQty();
                            if($qty >= 2) {
                                if($priceselector == 0) {
                                    $price = $item->getProduct()->getFinalPrice();
                                } else if($priceselector == 2) {
                                    $price = $item->getProduct()->getPrice();
                                } else {
                                $price = $item->getProduct()->getFinalPrice();
                                }
                                if(($qty%2==0)) {
                                    $x_product = ($qty/2);
                                    $final_amt = ($price * $x_product);
                                    $amt[] = $final_amt;
                                } else {
                                    $x_odd = $qty - 1;
                                    $x_product = ($x_odd/2);
                                    $final_amt = (($price * $x_product));
                                    $amt[] = $final_amt;
                                }
                            }
                        } 

                        $amount = array_sum($amt);
                        $finalDiscount = -$amount;
                        $rule_info[]= [
                            'name' => $name,
                            'amount'=> $finalDiscount
                        ];
                    break;

                    case "moneyamount":
                        $cartTotal = $this->getCartTotal();
                        if($cartTotal >= $discount_step) {
                            $get_x = $cartTotal/$discount_step;
                            $lower_round_off = floor($get_x);
                            $final_amt = $lower_round_off * $discount_amount;
                        } else {
                            $final_amt =0;
                        }
                        $finalDiscount = -$final_amt;
                        $rule_info[] = [
                            'name' => $name,
                            'amount'=> $finalDiscount,
                        ];
                    break;
                } // end  of swich case
            } // end of for loop
            return $rule_info;
        }
    }

app/code/Bg/SpecialPromotion/Model/ExtrafeeConfigProvider.php

<?php
namespace Bg\SpecialPromotion\Model;

use Magento\Checkout\Model\ConfigProviderInterface;

class ExtrafeeConfigProvider implements ConfigProviderInterface
{
    /**
     * @var \Magecomp\Extrafee\Helper\Data
     */
    protected $dataHelper;

    /**
     * @var \Magento\Checkout\Model\Session
     */
    protected $checkoutSession;

    /**
     * @var \Psr\Log\LoggerInterface
     */
    protected $logger;

    /**
     * @param \Bg/SpecialPromotion\Helper\Data $dataHelper
     * @param \Magento\Checkout\Model\Session $checkoutSession
     * @param \Psr\Log\LoggerInterface $logger
     */
    public function __construct(
        \Bg\SpecialPromotion\Helper\Data $dataHelper,
        \Magento\Checkout\Model\Session $checkoutSession,
        \Psr\Log\LoggerInterface $logger
    ) {
        $this->dataHelper = $dataHelper;
        $this->checkoutSession = $checkoutSession;
        $this->logger = $logger;
    }

    /**
     * @return array
     */
    public function getConfig()
    {
        $ExtrafeeConfig = [];
        $enabled = $this->dataHelper->isModuleEnabled();
        $minimumOrderAmount = $this->dataHelper->getMinimumOrderAmount();
        $ExtrafeeConfig['fee_label'] = $this->dataHelper->getFeeLabel();
        $quote = $this->checkoutSession->getQuote();
        $subtotal = $quote->getSubtotal();
        $ExtrafeeConfig['custom_fee_amount'] = $this->dataHelper->getExtrafee();
        $ExtrafeeConfig['custom_shipping'] = $this->dataHelper->getShippingPrices();
        $ExtrafeeConfig['show_hide_Extrafee_block'] = ($enabled && ($minimumOrderAmount <= $subtotal) && $quote->getFee()) ? true : false;
        $ExtrafeeConfig['show_hide_Extrafee_shipblock'] = ($enabled && ($minimumOrderAmount <= $subtotal)) ? true : false;
        return $ExtrafeeConfig;
    }
}

app/code/Bg/SpecialPromotion/view/frontend/web/js/view/checkout/cart/total/fee.js

define([
    'ko',
    'uiComponent',
    'Magento_Checkout/js/model/quote',
    'Magento_Catalog/js/price-utils',
    'Magento_Checkout/js/model/totals'

], function (ko, Component, quote, priceUtils, totals) {
    'use strict';
        var show_hide_Extrafee_blockConfig = window.checkoutConfig.show_hide_Extrafee_block;
        var fee_label = window.checkoutConfig.fee_label;
        var custom_fee_amount = window.checkoutConfig.custom_fee_amount;
        var custom_shipping = window.checkoutConfig.custom_shipping;

        return Component.extend({

            totals: quote.getTotals(),
            canVisibleExtrafeeBlock: show_hide_Extrafee_blockConfig,
            getFormattedPrice: ko.observable(priceUtils.formatPrice(custom_fee_amount, quote.getPriceFormat())),
            getFeeLabel:ko.observable(fee_label),

            isDisplayed: function () {
                return this.getValue() != 0;
            },
            getValue: function() {
                var price = 0;
                if (this.totals() && totals.getSegment('fee')) {
                    price = totals.getSegment('fee').value;
                }
                return price;
            },
            rawHtml: function() {
               var $html = '';
                _.each(custom_shipping, function (item) {
                $html += '<tr class="totals fee excl" >';
                $html += '<th class="mark" colspan="1" scope="row">'+item.title+'</th>';
                $html += '<td class="amount">';
                $html += '<span class="price">'+priceUtils.formatPrice(item.value)+'</span>';
                $html += '</td>';
                $html += '</tr>';
            });
            return $html;
        }
    });
});

app/code/Bg/SpecialPromotion/view/frontend/template/checkout/cart/total/fee.html

<!-- ko if: isDisplayed() -->
    <tr data-bind="html: rawHtml()"></tr>
<!-- /ko -->

Have tested in my local env, try to code like Magento zendframework format. Your code is not aligned properly. And add comments before every function like ExtrafeeConfigProvider.php file. Happy coding :-)

许可以下: CC-BY-SA归因
scroll top