Magento 2 - Having trouble collecting totals for a custom gift card module

by Danzapps   Last Updated February 19, 2017 11:09 AM

I've been banging my head against this wall for a couple of days now, hoping someone can help me gain some clarity on how best to approach the problem.

I'm in the process of adding support for a 3rd party gift card system. These cards will not exist in any way within the context of Magento, and an external web based API will validate/confirm balance/etc.

With that in mind, I simply need a way to alter the final cost of the order by adding one or more gift cards.

I feel like I'm close, but I'm getting very confused by how totals collection works in regards to \Magento\Quote\Model\Quote and \Magento\Quote\Model\Quote\Address\Total, specifically their ->getBaseGrandTotal()/->setBaseGrandTotal()/->getGrandTotal()/->setGrandTotal() methods.

$total->get[Base]GrandTotal() always seem to come back with a null or 0 value, even after calling $total->set[Base]GrandTotal(1234);

Here is my current collect() method, which seems to be not affecting the order total cost at all.

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);

    $baseGrandTotal = $total->getGrandTotal(); //this is always zero!
    $totalGiftCardBalance = $this->_CardSessionHelper->GetTotalAvailableBalanceOfCurrentGiftCards();

    $giftCardContribution = min($baseGrandTotal, $totalGiftCardBalance);
    //this takes the total viable gift card amount and spreads it over multiple gift cards
    //depending on how much balance each one has 
    $this->_CardSessionHelper->AllocateToGiftCards($giftCardContribution);

    //$contribution is a negative value determined by the previous allocation
    $contribution = $this->_CardSessionHelper->GetSumOfCurrentGiftCardsContribution();
    $total->setGrandTotal($contribution);
    $total->setBaseGrandTotal($this->_PriceCurrency->convert($contribution));

    return $this;
}

I've had other variations of this method which $quote->set[Base]GrandTotal, and seemed to work for the most part, but trying to work out additional gift card contributions after the fact would result in negative quote total values, or other values that made little sense.

In addition to this, the collection seems to happen multiple times - I presume this is because of both billing and shipping addresses.

Is there a way to get it to work for a billing address only?

Thanks!



Answers 1


Collect Totals:

We should base on shipping address.

\Magento\Quote\Model\Quote::collectTotals (can be called at the first) loops through each quote address (quote address total):

 $total = $this->totalsCollector->collect($this);

The \Magento\Quote\Model\Quote\TotalsCollector::collect() and collectAddressTotals() will be called for the next step

\Magento\Quote\Model\Quote\TotalsCollector::collectAddressTotals()

 foreach ($this->collectorList->getCollectors($quote->getStoreId()) as $collector) {
            /** @var CollectorInterface $collector */
            $collector->collect($quote, $shippingAssignment, $total);
 }

In the foreach loop, we will get the collect total of each total Model, for example: \Magento\Quote\Model\Quote\Address\Total\Subtotal::collect(), Magento\Weee\Model\Total\Quote\Weee::collect(), Magento\SalesRule\Model\Quote\Discount::collect(). Our custom total will be called in this loop also.

Each total Model based on the shipping address.

So, we need to check: if having shipping address items, we will process the custom totals

For example, in the collect method, we need to check: vendor/magento/module-sales-rule/Model/Quote/Discount.php

    parent::collect($quote, $shippingAssignment, $total);

    $items = $shippingAssignment->getItems();
    if (!count($items)) {
        return $this;
    }

Or (your case can be used)

if ($shippingAssignment->getShipping()->getAddress()->getAddressType() != Address::TYPE_SHIPPING) {
            return $this;
}

Grand Totals:

As far as I know, the grand total is the "final" total after tax, discount,....

  • setBaseGrandTotal: the grand total bases on base currency.

  • setGrandTotal : bases on the current currency.

Khoa TruongDinh
Khoa TruongDinh
February 16, 2017 11:35 AM

Related Questions


Updated October 17, 2016 09:03 AM

Updated January 18, 2019 13:09 PM

Updated September 16, 2019 09:09 AM

Updated July 09, 2019 13:09 PM

Updated April 28, 2017 06:09 AM