Magento 2 how to apply tax in credit memo adjustable refund field

By | March 5, 2024
Spread the love

In Magento 2, the Adjustable Refund field in the credit memo allows you to adjust the refund amount for each line item. However, handling taxes in credit memos can sometimes be a bit complex, and it may depend on your specific tax configuration and business rules. Here are the general steps to apply tax in the Adjustable Refund field for a credit memo in Magento 2:

  1. Create a Credit Memo:
    • Navigate to the Magento Admin Panel.
    • Go to Sales > Orders.
    • Open the order for which you want to create a credit memo.
    • Click on “Credit Memo” and create a credit memo for the order.
  2. Adjustable Refund Field:
    • In the credit memo creation page, you will find the “Adjustment Refund” field. Here, you can enter the adjusted refund amount for each line item.
  3. Handle Taxes:
    • Adjusting taxes might depend on your specific tax configuration. Magento 2 usually calculates and applies taxes automatically based on your tax rules and settings.
    • If you need to adjust taxes manually, you can do so by modifying the “Adjustment Refund” field for each line item.
  4. Review Tax Configuration:
    • Ensure that your tax settings and configurations are accurate. Check tax rules, tax zones, and product tax classes in Stores > Configuration > Sales > Tax.
  5. Check Tax Calculation Settings:
    • Verify that your tax calculation settings are correct. Go to Stores > Configuration > Sales > Tax > Calculation Settings.
  6. Custom Code or Extensions:
    • If your business requirements are complex, and the default Magento functionality doesn’t meet your needs, you might need to customize the tax calculation process.
    • You can create custom modules or use existing extensions that provide additional tax features.
  7. Testing:
    • After making adjustments, it’s crucial to test the credit memo and refund process thoroughly to ensure that taxes are calculated correctly and the Adjustable Refund field behaves as expected.

Always remember to test any changes in a staging environment before applying them to a live store to avoid disruptions to your business. If you encounter difficulties or have specific requirements, you might want to consult with a Magento developer or seek assistance from the Magento community.

In Default magento 2, adjustable refund field do not apply tax refund. You can do apply with following changes.

  1. Create app/code/Techgroup/Addon/etc/di.xml
<preference for="Magento\Sales\Model\Order\Creditmemo\Total\Tax" type="Techgroup\Addon\Model\Order\Creditmemo\Total\Tax"/>

2. Override a model  class and create in following path: app/code/Techgroup/Addon/Model/Order/Creditmemo/Total/Tax.php

<?php
namespace Techgroup\Addon\Model\Order\Creditmemo\Total;

use Magento\Sales\Model\ResourceModel\Order\Invoice as ResourceInvoice;

/**
 * Class Tax
 * @package Vendor\Module\Model\Order\Creditmemo\Total
 */
class Tax extends \Magento\Sales\Model\Order\Creditmemo\Total\Tax
{
    /**
     * @param ResourceInvoice $resourceInvoice
     * @param array $data
     */
    public function __construct(ResourceInvoice $resourceInvoice, array $data = [])
    {
        parent::__construct($resourceInvoice, $data);
    }

    /**
     * @param \Magento\Sales\Model\Order\Creditmemo $creditmemo
     * @return $this|\Magento\Sales\Model\Order\Creditmemo\Total\Tax
     */
    public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo)
    {
        $shippingTaxAmount = 0;
        $baseShippingTaxAmount = 0;
        $totalTax     = 0;
        $baseTotalTax = 0;
        $totalDiscountTaxCompensation = 0;
        $baseTotalDiscountTaxCompensation = 0;
        $adjustmentPositive = $adjustmentNegative = $newTax = 0;

        $order = $creditmemo->getOrder();
        $tax_percent = null;
        
        /** @var $item \Magento\Sales\Model\Order\Creditmemo\Item */
        foreach ($creditmemo->getAllItems() as $item) {
            $orderItem = $item->getOrderItem();
            if(is_null($tax_percent)) {
                $tax_percent =  $orderItem->getTaxPercent();
            }

            if ($orderItem->isDummy() || $item->getQty() <= 0) {
                continue;
            }

            $orderItemTax = (double)$orderItem->getTaxInvoiced();
            $baseOrderItemTax = (double)$orderItem->getBaseTaxInvoiced();
            $orderItemQty = (double)$orderItem->getQtyInvoiced();

            if ($orderItemQty) {
                /** Check item tax amount */
                $tax = $orderItemTax - $orderItem->getTaxRefunded();
                $baseTax = $baseOrderItemTax - $orderItem->getBaseTaxRefunded();
                $discountTaxCompensation = $orderItem->getDiscountTaxCompensationInvoiced()
                    - $orderItem->getDiscountTaxCompensationRefunded();
                $baseDiscountTaxCompensation = $orderItem->getBaseDiscountTaxCompensationInvoiced()
                    - $orderItem->getBaseDiscountTaxCompensationRefunded();
                
                if (!$item->isLast()) {
                    $availableQty = $orderItemQty - $orderItem->getQtyRefunded();
                    $tax = $creditmemo->roundPrice($tax / $availableQty * $item->getQty());
                    $baseTax = $creditmemo->roundPrice(($baseTax / $availableQty * $item->getQty()), 'base');
                    $discountTaxCompensation = $creditmemo->roundPrice(
                        $discountTaxCompensation / $availableQty * $item->getQty()
                    );
                    $baseDiscountTaxCompensation = $creditmemo->roundPrice(
                        $baseDiscountTaxCompensation / $availableQty * $item->getQty(),
                        'base'
                    );
                }

                $item->setTaxAmount($tax);
                $item->setBaseTaxAmount($baseTax);
                $item->setDiscountTaxCompensationAmount($discountTaxCompensation);
                $item->setBaseDiscountTaxCompensationAmount($baseDiscountTaxCompensation);

                $totalTax += $tax;
                $baseTotalTax += $baseTax;
                $totalDiscountTaxCompensation += $discountTaxCompensation;
                $baseTotalDiscountTaxCompensation += $baseDiscountTaxCompensation;
            }
        }
        
        $adjustmentNegative = $creditmemo->getAdjustmentNegative();
        $adjustmentPositive = $creditmemo->getAdjustmentPositive();
        if ($adjustmentNegative != 0) {
            $newSubtotal = $creditmemo->getSubtotal() - $adjustmentNegative;
            $newTax = $newSubtotal * $tax_percent / 100;
        }
        
        if($adjustmentPositive != 0)
        {
            $newTax += $adjustmentPositive * $tax_percent / 100;
        }

        $totalTax += $newTax;
        $baseTotalTax += $newTax;

        $isPartialShippingRefunded = false;
        $baseOrderShippingAmount = (float)$order->getBaseShippingAmount();
        if ($invoice = $creditmemo->getInvoice()) {
            //recalculate tax amounts in case if refund shipping value was changed
            if ($baseOrderShippingAmount && $creditmemo->getBaseShippingAmount() !== null) {
                $taxFactor = $creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount;
                $shippingTaxAmount = $invoice->getShippingTaxAmount() * $taxFactor;
                $baseShippingTaxAmount = $invoice->getBaseShippingTaxAmount() * $taxFactor;
                $totalDiscountTaxCompensation += $invoice->getShippingDiscountTaxCompensationAmount() * $taxFactor;
                $baseTotalDiscountTaxCompensation +=
                    $invoice->getBaseShippingDiscountTaxCompensationAmnt() * $taxFactor;
                $shippingTaxAmount = $creditmemo->roundPrice($shippingTaxAmount);
                $baseShippingTaxAmount = $creditmemo->roundPrice($baseShippingTaxAmount, 'base');
                $totalDiscountTaxCompensation = $creditmemo->roundPrice($totalDiscountTaxCompensation);
                $baseTotalDiscountTaxCompensation = $creditmemo->roundPrice($baseTotalDiscountTaxCompensation, 'base');
                if ($taxFactor < 1 && $invoice->getShippingTaxAmount() > 0) {
                    $isPartialShippingRefunded = true;
                }
                $totalTax += $shippingTaxAmount;
                $baseTotalTax += $baseShippingTaxAmount;
            }
        } 
        else {
            $orderShippingAmount = $order->getShippingAmount();
            $baseOrderShippingRefundedAmount = $order->getBaseShippingRefunded();

            $shippingTaxAmount = 0;
            $baseShippingTaxAmount = 0;
            $shippingDiscountTaxCompensationAmount = 0;
            $baseShippingDiscountTaxCompensationAmount = 0;

            $shippingDelta = $baseOrderShippingAmount - $baseOrderShippingRefundedAmount;

            if ($shippingDelta > $creditmemo->getBaseShippingAmount()) {
                $part = $creditmemo->getShippingAmount() / $orderShippingAmount;
                $basePart = $creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount;
                $shippingTaxAmount = $order->getShippingTaxAmount() * $part;
                $baseShippingTaxAmount = $order->getBaseShippingTaxAmount() * $basePart;
                $shippingDiscountTaxCompensationAmount = $order->getShippingDiscountTaxCompensationAmount() * $part;
                $baseShippingDiscountTaxCompensationAmount =
                    $order->getBaseShippingDiscountTaxCompensationAmnt() * $basePart;
                $shippingTaxAmount = $creditmemo->roundPrice($shippingTaxAmount);
                $baseShippingTaxAmount = $creditmemo->roundPrice($baseShippingTaxAmount, 'base');
                $shippingDiscountTaxCompensationAmount =
                    $creditmemo->roundPrice($shippingDiscountTaxCompensationAmount);
                $baseShippingDiscountTaxCompensationAmount =
                    $creditmemo->roundPrice($baseShippingDiscountTaxCompensationAmount, 'base');
                if ($part < 1 && $order->getShippingTaxAmount() > 0) {
                    $isPartialShippingRefunded = true;
                }
            } 
            elseif ($shippingDelta == $creditmemo->getBaseShippingAmount()) {
                $shippingTaxAmount = $order->getShippingTaxAmount() - $order->getShippingTaxRefunded();
                $baseShippingTaxAmount = $order->getBaseShippingTaxAmount() - $order->getBaseShippingTaxRefunded();
                $shippingDiscountTaxCompensationAmount = $order->getShippingDiscountTaxCompensationAmount() -
                    $order->getShippingDiscountTaxCompensationRefunded();
                $baseShippingDiscountTaxCompensationAmount = $order->getBaseShippingDiscountTaxCompensationAmnt() -
                    $order->getBaseShippingDiscountTaxCompensationRefunded();
            }
            
            $totalTax += $shippingTaxAmount;
            $baseTotalTax += $baseShippingTaxAmount;
            $totalDiscountTaxCompensation += $shippingDiscountTaxCompensationAmount;
            $baseTotalDiscountTaxCompensation += $baseShippingDiscountTaxCompensationAmount;
        }
        
        if ($adjustmentNegative != 0) {
            $allowedTax = $newTax;
            $allowedBaseTax = $newTax;
        } 
        elseif( $adjustmentPositive != 0){
            $allowedTax = $totalTax;
            $allowedBaseTax = $baseTotalTax;
        }
        else {
            $allowedTax = $order->getTaxInvoiced() - $order->getTaxRefunded() - $creditmemo->getTaxAmount();
            $allowedBaseTax = $order->getBaseTaxInvoiced() - $order->getBaseTaxRefunded() - $creditmemo->getBaseTaxAmount();
        }
        
        $allowedDiscountTaxCompensation = $order->getDiscountTaxCompensationInvoiced() +
            $order->getShippingDiscountTaxCompensationAmount() -
            $order->getDiscountTaxCompensationRefunded() -
            $order->getShippingDiscountTaxCompensationRefunded() -
            $creditmemo->getDiscountTaxCompensationAmount() -
            $creditmemo->getShippingDiscountTaxCompensationAmount();
        $allowedBaseDiscountTaxCompensation = $order->getBaseDiscountTaxCompensationInvoiced() +
            $order->getBaseShippingDiscountTaxCompensationAmnt() -
            $order->getBaseDiscountTaxCompensationRefunded() -
            $order->getBaseShippingDiscountTaxCompensationRefunded() -
            $creditmemo->getBaseShippingDiscountTaxCompensationAmnt() -
            $creditmemo->getBaseDiscountTaxCompensationAmount();

        if ($creditmemo->isLast() && !$isPartialShippingRefunded) {
            $totalTax = $allowedTax;
            $baseTotalTax = $allowedBaseTax;
            $totalDiscountTaxCompensation = $allowedDiscountTaxCompensation;
            $baseTotalDiscountTaxCompensation = $allowedBaseDiscountTaxCompensation;
        } 
        else {
            $totalTax = min($allowedTax, $totalTax);
            $baseTotalTax = min($allowedBaseTax, $baseTotalTax);
            $totalDiscountTaxCompensation =
                min($allowedDiscountTaxCompensation, $totalDiscountTaxCompensation);
            $baseTotalDiscountTaxCompensation =
                min($allowedBaseDiscountTaxCompensation, $baseTotalDiscountTaxCompensation);
        }

        $creditmemo->setTaxAmount($creditmemo->getTaxAmount() + $totalTax);
        $creditmemo->setBaseTaxAmount($creditmemo->getBaseTaxAmount() + $baseTotalTax);
        $creditmemo->setDiscountTaxCompensationAmount($totalDiscountTaxCompensation);
        $creditmemo->setBaseDiscountTaxCompensationAmount($baseTotalDiscountTaxCompensation);

        $creditmemo->setShippingTaxAmount($shippingTaxAmount);
        $creditmemo->setBaseShippingTaxAmount($baseShippingTaxAmount);

        $creditmemo->setGrandTotal($creditmemo->getGrandTotal() + $totalTax + $totalDiscountTaxCompensation);
        $creditmemo->setBaseGrandTotal(
            $creditmemo->getBaseGrandTotal() +
            $baseTotalTax + $baseTotalDiscountTaxCompensation
        );
        return $this;
    }
}