1

I was facing an issue in tax calculation after discount for that i need to do code change from

//TODO: handle originalDiscountAmount
$taxableAmount = max($rowTotalInclTax - $discountAmount, 0);
$rowTaxAfterDiscount = $this->calculationTool->calcTaxAmount(
    $taxableAmount,
    $rate,
    true,
    false
);
$rowTaxAfterDiscount = $this->roundAmount(
    $rowTaxAfterDiscount,
    $rate,
    true,
    self::KEY_REGULAR_DELTA_ROUNDING,
    $round,
    $item
);
// Set discount tax compensation
$discountTaxCompensationAmount = $rowTax - $rowTaxAfterDiscount;
$rowTax = $rowTaxAfterDiscount;

to

$taxableAmount = max($rowTotal - $discountAmount, 0);
$discountTaxCompensationAmount = 0;
$rowTax = $taxableAmount * ($rate / 100);

in vendor/magento/module-tax/Model/Calculation/AbstractAggregateCalculator.php:49

For that change i use preference in my custom module

  <preference for="Magento\Tax\Model\Calculation\AbstractAggregateCalculator" type="Custom\Tax\Model\Calculation\AbstractAggregateCalculator" />

and overwritten the file

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Custom\Tax\Model\Calculation;

use Magento\Tax\Api\Data\QuoteDetailsItemInterface;

/**
 * Abstract aggregate calculator.
 */
abstract class AbstractAggregateCalculator extends \Magento\Tax\Model\Calculation\AbstractAggregateCalculator
{
    /**
     * @inheritdoc
     */
    protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
    {
        $taxRateRequest = $this->getAddressRateRequest()->setProductClassId(
            $this->taxClassManagement->getTaxClassId($item->getTaxClassKey())
        );
        $rate = $this->calculationTool->getRate($taxRateRequest);
        $storeRate = $this->calculationTool->getStoreRate($taxRateRequest, $this->storeId);

        $discountTaxCompensationAmount = 0;
        $applyTaxAfterDiscount = $this->config->applyTaxAfterDiscount($this->storeId);
        $discountAmount = $item->getDiscountAmount();

        // Calculate $rowTotalInclTax
        $priceInclTax = $this->calculationTool->round($item->getUnitPrice());
        $rowTotalInclTax = $priceInclTax * $quantity;
        if (!$this->isSameRateAsStore($rate, $storeRate)) {
            $priceInclTax = $this->calculatePriceInclTax($priceInclTax, $storeRate, $rate, $round);
            $rowTotalInclTax = $priceInclTax * $quantity;
        }
        $rowTaxExact = $this->calculationTool->calcTaxAmount($rowTotalInclTax, $rate, true, false);
        $deltaRoundingType = self::KEY_REGULAR_DELTA_ROUNDING;
        if ($applyTaxAfterDiscount) {
            $deltaRoundingType = self::KEY_TAX_BEFORE_DISCOUNT_DELTA_ROUNDING;
        }
        $rowTax = $this->roundAmount($rowTaxExact, $rate, true, $deltaRoundingType, $round, $item);
        $rowTotal = $rowTotalInclTax - $rowTax;
        $price = $rowTotal / $quantity;
        if ($round) {
            $price = $this->calculationTool->round($price);
        }

        //Handle discount
        if ($applyTaxAfterDiscount) {
            //TODO: handle originalDiscountAmount
            $taxableAmount = \max($rowTotal - $discountAmount, 0);
            $discountTaxCompensationAmount = 0;
            $rowTax = $taxableAmount * ($rate / 100);
        }

        // Calculate applied taxes
        /** @var  \Magento\Tax\Api\Data\AppliedTaxInterface[] $appliedTaxes */
        $appliedRates = $this->calculationTool->getAppliedRates($taxRateRequest);
        $appliedTaxes = $this->getAppliedTaxes($rowTax, $rate, $appliedRates);

        return $this->taxDetailsItemDataObjectFactory->create()
            ->setCode($item->getCode())
            ->setType($item->getType())
            ->setRowTax($rowTax)
            ->setPrice($price)
            ->setPriceInclTax($priceInclTax)
            ->setRowTotal($rowTotal)
            ->setRowTotalInclTax($rowTotalInclTax)
            ->setDiscountTaxCompensationAmount($discountTaxCompensationAmount)
            ->setAssociatedItemCode($item->getAssociatedItemCode())
            ->setTaxPercent($rate)
            ->setAppliedTaxes($appliedTaxes);
    }
    /**
     * Round amount
     *
     * @param float $amount
     * @param null|float $rate
     * @param null|bool $direction
     * @param string $type
     * @param bool $round
     * @param QuoteDetailsItemInterface $item
     * @return float
     */
    abstract protected function roundAmount(
        $amount,
        $rate = null,
        $direction = null,
        $type = self::KEY_REGULAR_DELTA_ROUNDING,
        $round = true,
        $item = null
    );
}

But the changes are not reflecting, i think abstract class cannot be overwritten, can some one suggest a solution or fix?

2 Answers 2

3

Right, you can't overwrite an Abstract class, overwrite its child classes instead.

There are 2 child classes of Magento\Tax\Model\Calculation\AbstractAggregateCalculator:

  • Magento\Tax\Model\Calculation\RowBaseCalculator
  • Magento\Tax\Model\Calculation\TotalBaseCalculator

To achieve your requirements, take the following steps:
Assume your vendor name is Custom and your module name is Tax.

Step 1: Create registration.php:
File path: app/code/Custom/Tax/registration.php

<?php

use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Custom_Tax', __DIR__);

Step 2: Create module.xml:
File path: app/code/Custom/Tax/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Custom_Tax">
        <sequence>
            <module name="Magento_Tax"/>
        </sequence>
    </module>
</config>

Step 3: Create di.xml:
File path: app/code/Custom/Tax/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Tax\Model\Calculation\TotalBaseCalculator" type="Custom\Tax\Model\Calculation\TotalBaseCalculator" />
    <preference for="Magento\Tax\Model\Calculation\RowBaseCalculator" type="Custom\Tax\Model\Calculation\RowBaseCalculator" />
</config>

Step 4: Create TotalBaseCalculator file.
File path: app/code/Custom/Tax/Model/Calculation/TotalBaseCalculator.php

<?php

namespace Custom\Tax\Model\Calculation;

use Magento\Tax\Api\Data\QuoteDetailsItemInterface;

class TotalBaseCalculator extends \Magento\Tax\Model\Calculation\TotalBaseCalculator
{
    /**
     * @inheritdoc
     */
    protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
    {
        // Your overwrite code goes here
    }
}

Step 5: Create RowBaseCalculator file.
File path: app/code/Custom/Tax/Model/Calculation/RowBaseCalculator.php

<?php

namespace Custom\Tax\Model\Calculation;

use Magento\Tax\Api\Data\QuoteDetailsItemInterface;

class RowBaseCalculator extends \Magento\Tax\Model\Calculation\RowBaseCalculator
{
    /**
     * @inheritdoc
     */
    protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
    {
        // Your overwrite code goes here
    }
}

Step 6: Run setup upgrade command to install and enable the module: bin/magento setup:upgrade

Step 7: Run compilation code command: bin/magento setup:di:compile

Step 8: Run deploy static content command: bin/magento setup:static-content:deploy -f

You are done.

5
  • You can also try magento plugin for enhancing existing functionality of any Abstract class that means you can write your code : $taxableAmount = max($rowTotal - $discountAmount, 0); $discountTaxCompensationAmount = 0; $rowTax = $taxableAmount * ($rate / 100); By using afterYourMethodName() your code will go in this method. Nov 23, 2022 at 9:52
  • For example : afterCalculateWithTaxInPrice{ // Your code goes here } Nov 23, 2022 at 9:57
  • @Oscprofessionals calculateWithTaxInPrice method is a protected method, so you can't use a plugin for that method.
    – Tu Van
    Nov 23, 2022 at 10:17
  • Plugins and overwriting Magento\Tax\Model\Calculation\RowBaseCalculator didn't worked for me. For quick fix i created patch and applied
    – Anju
    Nov 23, 2022 at 13:51
  • @Anju I've updated my answer to include step-by-step to achieve your need, please check. In case you already installed your custom module, you must remove generated directory before running compile code command.
    – Tu Van
    Nov 26, 2022 at 18:45
0

I applied patch like this for quick fix as it is an urgency in my project, but still waiting for some other approach

diff --git a/vendor/magento/module-tax/Model/Calculation/AbstractAggregateCalculator.php b/vendor/magento/module-tax/Model/Calculation/AbstractAggregateCalculator.php
--- a/vendor/magento/module-tax/Model/Calculation/AbstractAggregateCalculator.php
+++ b/vendor/magento/module-tax/Model/Calculation/AbstractAggregateCalculator.php
@@ -49,24 +49,9 @@
         //Handle discount
         if ($applyTaxAfterDiscount) {
             //TODO: handle originalDiscountAmount
-            $taxableAmount = max($rowTotalInclTax - $discountAmount, 0);
-            $rowTaxAfterDiscount = $this->calculationTool->calcTaxAmount(
-                $taxableAmount,
-                $rate,
-                true,
-                false
-            );
-            $rowTaxAfterDiscount = $this->roundAmount(
-                $rowTaxAfterDiscount,
-                $rate,
-                true,
-                self::KEY_REGULAR_DELTA_ROUNDING,
-                $round,
-                $item
-            );
-            // Set discount tax compensation
-            $discountTaxCompensationAmount = $rowTax - $rowTaxAfterDiscount;
-            $rowTax = $rowTaxAfterDiscount;
+            $taxableAmount = max($rowTotal - $discountAmount, 0);
+            $discountTaxCompensationAmount = 0;
+            $rowTax = $taxableAmount * ($rate / 100);
         }
 
         // Calculate applied taxes
1
  • This ways is better than other answers.
    – HoangHieu
    Nov 28, 2022 at 15:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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