5

I want to apply custom discount amount to cart programmatically. I have tried doing it in following 2 ways, none of which work:

METHOD 1:

I tried following the default way in which Magento2 applies sales-rule discounts. I did it by creating following files in my module:

etc\sales.xml

<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="discount" instance="Vendorname\Modulenmae\Model\CustomFolderName\Quote\Discount" sort_order="400"/>
        </group>
    </section>
</config>

frontend\layout\checkout_cart_index.xml

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
        <referenceBlock name="checkout.cart.totals">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="block-totals" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="before_grandtotal" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="discount" xsi:type="array">
                                            <item name="config" xsi:type="array">
                                                <item name="title" xsi:type="string" translate="true">My Custom Discount</item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Model File

class Discount extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
{
    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);

            $label          = 'My Custom Discount';
            $discountAmount = -10;              
            $total->setDiscountDescription($label);
            $total->setDiscountAmount($discountAmount);
            $total->setBaseDiscountAmount($discountAmount);
            $total->setSubtotalWithDiscount($total->getSubtotal() + $discountAmount);
            $total->setBaseSubtotalWithDiscount($total->getBaseSubtotal() + $discountAmount);
            return $this;
        }
        //fetch function is also defined in this class. Since it is only used for display purposes I have not added its code in this question.
}

However, with this method, my custom discount gets applied but Magento's default sales rules like coupon code, etc. stop working. They throw errors like Invalid Coupon Code even when the coupon code is completely valid. If I revert my changes, the default coupon codes start working again.

METHOD 2:

Another method i tried is applying discount by observing the sales_quote_collect_totals_after event. It is working fine, but i think method 1 might be the best way to achieve it.

Any ideas as to how can I do it correctly ?

  • 1
    Take a look at github.com/magepal/stackexchange/tree/develop/104112 . The discount work with other coupons and display the correct total but the break down of the discount fetch() not display correctly – Renon Stewart Mar 1 '16 at 21:29
  • @R.S - Thank you so much. With your code there was 1 issue, discount coupon got applied but it removed my custom discount and added its coupon discount. I have made minor change to add both discounts, so when custom discount is in cart and coupon is applied it will add both. github.com/parekhreena/stackexchange/blob/develop/104112/… . Please add it as answer and i will accept it – Reena Parekh Mar 2 '16 at 11:03
  • There is an issue in Admin where it will automatically apply the discount before any item is added. So you will need to check to make sure the total is greater than zero and check to make sure that the total is always greater than total discount (so you don't have a negative total). – Renon Stewart Mar 3 '16 at 12:41
7

Thanks @R.S. . I found the solution by referring repo created by @R.S. here: https://github.com/magepal/stackexchange/tree/develop/104112 after some minor modifications.

sales.xml

<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="testdiscount" instance="MagePal\TestDiscount\Model\Quote\Discount" sort_order="500"/>
        </group>
    </section>
</config>

Model file

public function collect(
        \Magento\Quote\Model\Quote $quote,
        \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment,
        \Magento\Quote\Model\Quote\Address\Total $total
    ) {
        //Fix for discount applied twice
        $items = $shippingAssignment->getItems();
        if (!count($items)) {
            return $this;
        }

        parent::collect($quote, $shippingAssignment, $total);
        //$address             = $shippingAssignment->getShipping()->getAddress();
        $label               = 'My Custom Discount';
        $discountAmount      = -10;   
        $appliedCartDiscount = 0;
        if($total->getDiscountDescription()) {
            // If a discount exists in cart and another discount is applied, the add both discounts.
            $appliedCartDiscount = $total->getDiscountAmount();
            $discountAmount      = $total->getDiscountAmount()+$discountAmount;
        $label               = $total->getDiscountDescription().', '.$label;
        }    

        $total->setDiscountDescription($label);
    $total->setDiscountAmount($discountAmount);
    $total->setBaseDiscountAmount($discountAmount);
        $total->setSubtotalWithDiscount($total->getSubtotal() + $discountAmount);
        $total->setBaseSubtotalWithDiscount($total->getBaseSubtotal() + $discountAmount);

       if(isset($appliedCartDiscount)) {
        $total->addTotalAmount($this->getCode(), $discountAmount - $appliedCartDiscount);
        $total->addBaseTotalAmount($this->getCode(), $discountAmount - $appliedCartDiscount);
    } else {
        $total->addTotalAmount($this->getCode(), $discountAmount);
        $total->addBaseTotalAmount($this->getCode(), $discountAmount);
    }

        return $this;
    }

checkout_cart_index.xml

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.cart.totals">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="block-totals" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="before_grandtotal" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="testdiscount" xsi:type="array">
                                            <item name="config" xsi:type="array">
                                                <item name="title" xsi:type="string" translate="true">My Discount</item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

checkout_index_index.xml

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.root">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="checkout" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="sidebar" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="summary" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="totals" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="testdiscount" xsi:type="array">
                                                            <item name="config" xsi:type="array">
                                                                <item name="title" xsi:type="string" translate="true">My Discount</item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Fetch is not showing the custom discount description. I have opened its ticket here: https://github.com/magento/magento2/issues/3594

| improve this answer | |
  • Hello Reena, your answer is fine and working perfect, but one issue create.. Coupon code is not working when use above answer.. – Payal Patel Oct 21 '16 at 5:43
  • 1
    Ohh Sorry for my comment.. My small mistake here. Now Perfect.. Thanks Reena. – Payal Patel Oct 21 '16 at 5:53
  • Discount is working fine but discount detail not displaying on cart page, Can you please let me know the fix. I have checked the ticket and found same discount file – mjdevloper Nov 17 '16 at 5:47
  • 2
    some time discount applied twice , can you please let me know quick fix for this – mjdevloper Nov 22 '16 at 8:43
  • @mjdevloper- this code works just fine and doesn't apply discount twice. kindly post your question separately on this site and either I or someone else from the community will get back to you. – Reena Parekh Dec 28 '16 at 5:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.