4

I am trying to understand the working of discount coupon codes on the checkout page.

When we apply any coupon code, then the discount is added to cart without reloading the page.

I have checked and found some below points:

  • "discount" totals segment is added by Magento_SalesRule module.

When we apply any coupon code then, using vendor\magento\module-sales-rule\view\frontend\web\js\action\set-coupon-code.js, an ajax request is send to rest/default/V1/carts/mine/coupons/:coupon.

Code from vendor\magento\module-sales-rule\view\frontend\web\js\action\set-coupon-code.js :

 return storage.put(
            url,
            {},
            false
        ).done(function (response) {
            var deferred;

            if (response) {
                deferred = $.Deferred();

                isApplied(true);
                totals.isLoading(true);
                getPaymentInformationAction(deferred);
                $.when(deferred).done(function () 
                {
                    fullScreenLoader.stopLoader();
                    totals.isLoading(false);
                });
                messageContainer.addSuccessMessage({
                    'message': message
                });
            }
        }).fail(function (response) {
            fullScreenLoader.stopLoader();
            totals.isLoading(false);
            errorProcessor.process(response, messageContainer);
        });
  • After the above ajax call, Summary total section gets refresh and Discount appears in it below image.

apply coupon

  • When we click on the cancel coupon button then code from vendor\magento\module-sales-rule\view\frontend\web\js\action\cancel-coupon.js runs and "Discount" disappears from the summary total section.

enter image description here

How does the total_segments add or remove "discount"?

  • What is your requirement? – Suresh Chikani Apr 19 '18 at 12:57
  • Hi @SureshChikani, I wanted to add custom fee to total_segments like a discount. – vedu Apr 20 '18 at 4:20
4
+50

1) For customer account: /V1/carts/mine/coupons/:couponCode

I just explain how sale rules work for customer logged

a) Set coupon:

vendor/magento/module-quote/etc/webapi.xml

<route url="/V1/carts/mine/coupons/:couponCode" method="PUT">
    <service class="Magento\Quote\Api\CouponManagementInterface" method="set"/>
    <resources>
        <resource ref="Magento_Cart::manage" />
    </resources>
</route>

So, the service class interface class Magento\Quote\Api\CouponManagementInterface::set() will be used and Magento\Quote\Model\CouponManagement::set will be called.

$quote->setCouponCode($couponCode);
$this->quoteRepository->save($quote->collectTotals());

When quote collects totals: $quote->collectTotals()

\Magento\SalesRule\Model\Quote\Discount::collect() will be called. It will calculate the coupon logic here.

b) Remove coupon:

vendor/magento/module-quote/etc/webapi.xml

<route url="/V1/carts/mine/coupons" method="DELETE">
    <service class="Magento\Quote\Api\CouponManagementInterface" method="remove"/>
    <resources>
        <resource ref="self" />
    </resources>
    <data>
        <parameter name="cartId" force="true">%cart_id%</parameter>
    </data>
</route>

Magento\Quote\Model\CouponManagement::remove() will be called.

c) Total Segment: V1/carts/mine/payment-information

vendor/magento/module-checkout/etc/webapi.xml

<route url="/V1/carts/mine/payment-information" method="GET">
    <service class="Magento\Checkout\Api\PaymentInformationManagementInterface" method="getPaymentInformation"/>
    <resources>
        <resource ref="self" />
    </resources>
    <data>
        <parameter name="cartId" force="true">%cart_id%</parameter>
    </data>
</route>

vendor/magento/module-checkout/Model/PaymentInformationManagement.php

/**
 * {@inheritDoc}
 */
public function getPaymentInformation($cartId)
{
    ...
    $paymentDetails->setTotals($this->cartTotalsRepository->get($cartId));
    ...
}

\Magento\Quote\Model\Cart\CartTotalRepository::get()

 if ($quote->isVirtual()) {
        $addressTotalsData = $quote->getBillingAddress()->getData();
        $addressTotals = $quote->getBillingAddress()->getTotals();
    } else {
        $addressTotalsData = $quote->getShippingAddress()->getData();
        $addressTotals = $quote->getShippingAddress()->getTotals();
    }
......

$calculatedTotals = $this->totalsConverter->process($addressTotals);
$quoteTotals->setTotalSegments($calculatedTotals);

This will get the totals data and set the total segments.

\Magento\Quote\Model\Quote\TotalsReader::fetch()

foreach ($this->collectorList->getCollectors($quote->getStoreId()) as $reader) {
        $data = $reader->fetch($quote, $total);

2) For guest account, we can see the apis:

vendor/magento/module-quote/etc/webapi.xml

<!-- Managing Guest Cart Coupons -->
<route url="/V1/guest-carts/:cartId/coupons" method="GET">
    <service class="Magento\Quote\Api\GuestCouponManagementInterface" method="get"/>
    <resources>
        <resource ref="anonymous" />
    </resources>
</route>
<route url="/V1/guest-carts/:cartId/coupons/:couponCode" method="PUT">
    <service class="Magento\Quote\Api\GuestCouponManagementInterface" method="set"/>
    <resources>
        <resource ref="anonymous" />
    </resources>
</route>
<route url="/V1/guest-carts/:cartId/coupons" method="DELETE">
    <service class="Magento\Quote\Api\GuestCouponManagementInterface" method="remove"/>
    <resources>
        <resource ref="anonymous" />
    </resources>
</route>
  • 1
    Thank you for the answer. I wanted to add a custom fee to total_segments like discount, \Magento\Quote\Model\Quote\TotalsReader::fetch() this line helped me. – vedu Apr 20 '18 at 5:19

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.