decimalroundingmagento2calculationsubtotal

Magento 2 / Prices and subtotals with 4 decimals But VAT and Totals on 2 decimals


I had to change prices to 4 decimals and it's OK. However, i have sometimes rounded cent in totals which is wrong. The explanation is that all calculations (subtotal, VAT and total) are on 4 decimals then rounded to 2 decimals. With rounding, subtotal + VAT is sometimes different for 1 cent from total.

To fix this, i need to :

But i can't figure how to do this. I tried multiple solutions and nothing is working : even with forcing subtotal/VAT and saving, it seems to be calculated again elsewhere and 4 decimals appear again.

Can you give me some piece of advice on how to achieve this ? Thanks !


Solution

  • I succeed in rewriting event sales_quote_collect_totals_after

    Update : here is the code

    in Myvendor/Mymodule/etc/events.xml :

    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
        <event name="sales_quote_address_collect_totals_after">
            <observer name="changeTotals" instance="Myvendor\Mymodule\Observer\ChangeTotals"/>
        </event>
    </config>
    

    In Myvendor/Mymodule/Observer/ChangeTotals.php :

    <?php
    namespace Myvendor\Mymodule\Observer;
    
    use Psr\Log\LoggerInterface as Logger;
    use \Magento\Framework\Event\ObserverInterface;
    use \Magento\Framework\Event\Observer;
    
    class ChangeTotals implements ObserverInterface
    {
         /**
         * @var Logger
         */
        protected $_logger;
        
        /**
         * [__construct ]
         * 
         * @param Logger $logger
         */
        public function __construct(
            Logger $logger
        ) {
            $this->_logger = $logger;
        }
    
        public function execute(Observer $observer)
        {
            /** @var Magento\Quote\Model\Quote\Address\Total */
            $total = $observer->getData('total');
            
                $subtotal = $total->getTotalAmount('subtotal');
                $tax = $total->getTotalAmount('tax');
                $grandTotal = $total->getGrandTotal();
                
                /* $this->_logger->info('**** total_before **** ' , array($total->getData()));*/
                
                /* the $total->getData() contains : 
                [subtotal] => 0
                [weee] => 0
                [discount] => 0
                [shipping] => 0
                [shipping_discount] => 0
                [tax] => 0
                [discount_tax_compensation] => 0
                [shipping_discount_tax_compensation] => 0
                [extra_tax] => 0
                [weee_tax] => 0*/
                
                // i round tax to 2 decimals
                $tax = round($tax,2);
                $total->setTotalAmount('tax', $tax);
                $total->setBaseTaxAmount($tax);
                
                /* recalculate grandTotal */
                $grandTotal = round($subtotal,2) + $tax + $total->getTotalAmount('discount') + $total->getShippingAmount()
                +$total->getShippingDiscountAmount() + $total->getDiscountTaxCompensation() + $total->getShippingDiscountTaxCompensation() + $total->getExtraTax(), 2);
    
                /* recalculate baseGrandTotal */
                $baseGrandTotal = round($total->getBaseSubtotal(),2) + $tax + $total->getBaseDiscount() + $total->getBaseShippingAmount()
                + $total->getBaseShippingDiscountAmount() + $total->getBaseDiscountTaxCompensation() + $total->getBaseShippingDiscountTaxCompensation() + $total->getBaseExtraTax(), 2);
                /* update totals */
                $total->setGrandTotal($grandTotal);
                /*$total->setBaseGrandTotal($baseGrandTotal);
    
                /* $this->_logger->info('**** total_after **** ' , array($total->getData())); */
    
            return $this;
        }
    }