I have a custom totals collector, which removes the VAT for exempt items. Here is the code:
app/code/Innox/VatExemption/etc/sales.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Sales:etc/sales.xsd">
<section name="quote">
<group name="totals">
<item name="tax_subtotal" instance="VendorModuleModelSalesTotalQuoteSubtotal" sort_order="600"/>
</group>
</section>
</config>
app/code/Vendor/Module/Model/Sales/Total/Quote/Subtotal.php
<?php
namespace VendorModuleModelSalesTotalQuote;
use VendorModuleHelperData as ExemptionHelper;
use MagentoCustomerApiDataAddressInterfaceFactory as CustomerAddressFactory;
use MagentoCustomerApiDataRegionInterfaceFactory as CustomerAddressRegionFactory;
use MagentoTaxHelperData as TaxHelper;
use MagentoTaxApiDataQuoteDetailsInterfaceFactory;
use MagentoTaxApiDataQuoteDetailsItemInterfaceFactory;
use MagentoTaxModelSalesTotalQuoteTax;
use MagentoTaxModelConfig;
use MagentoTaxApiTaxCalculationInterface;
use MagentoTaxApiDataTaxClassKeyInterfaceFactory;
use MagentoFrameworkSerializeSerializerJson;
class Subtotal extends Tax
{
protected $exemptionHelper;
/**
* Constructor
*
* @param ExemptionHelper $exemptionHelper
*/
public function __construct(
Config $taxConfig,
TaxCalculationInterface $taxCalculationService,
QuoteDetailsInterfaceFactory $quoteDetailsDataObjectFactory,
QuoteDetailsItemInterfaceFactory $quoteDetailsItemDataObjectFactory,
TaxClassKeyInterfaceFactory $taxClassKeyDataObjectFactory,
CustomerAddressFactory $customerAddressFactory,
CustomerAddressRegionFactory $customerAddressRegionFactory,
TaxHelper $taxData,
Json $serializer,
ExemptionHelper $exemptionHelper
) {
$this->exemptionHelper = $exemptionHelper;
parent::__construct(
$taxConfig,
$taxCalculationService,
$quoteDetailsDataObjectFactory,
$quoteDetailsItemDataObjectFactory,
$taxClassKeyDataObjectFactory,
$customerAddressFactory,
$customerAddressRegionFactory,
$taxData,
$serializer
);
}
/**
* Calculate tax on product items. The result will be used to determine shipping
* and discount later.
*
* @param MagentoQuoteModelQuote $quote
* @param ShippingAssignmentInterface $shippingAssignment
* @param AddressTotal $total
* @return $this
*/
public function collect(
MagentoQuoteModelQuote $quote,
MagentoQuoteApiDataShippingAssignmentInterface $shippingAssignment,
MagentoQuoteModelQuoteAddressTotal $total
) {
// return if no items in quote
if (!$quote->getItems()) {
return $this;
}
// set some default values
$subtotal = 0;
$tax = 0;
$quoteId = $quote->getId();
foreach ($quote->getItems() as $quoteItem) {
// check for exempt item
if ($this->exemptionHelper->isVatExemptProduct($quoteItem)) {
// check for this item in current quote
if ($this->exemptionHelper->isExemptProductInQuote($quoteId, $quoteItem)) {
// remove VAT from item row price and subtotals
$this->setRowExclTax($quoteItem);
}
}
// add to cart subtotal
$subtotal += $quoteItem->getBaseRowTotalInclTax();
// add to cart tax
$tax += $quoteItem->getBaseTaxAmount();
$this->updateCartTotals($total, $subtotal, $tax);
}
return $this;
}
private function setRowExclTax($quoteItem)
{
$rowTotal = ($quoteItem->getPrice() * $quoteItem->getQty());
// calculate row total ex tax
$quoteItem->setPrice($quoteItem->getPrice());
$quoteItem->setBasePrice($quoteItem->getBasePrice());
$quoteItem->setPriceInclTax($quoteItem->getPrice());
$quoteItem->setBasePriceInclTax($quoteItem->getBasePrice());
$quoteItem->setRowTotal($rowTotal);
$quoteItem->setBaseRowTotal($rowTotal);
$quoteItem->setRowTotalInclTax($rowTotal);
$quoteItem->setBaseRowTotalInclTax($rowTotal);
$quoteItem->setTaxAmount(0);
$quoteItem->setBaseTaxAmount(0);
$quoteItem->setTaxPercent(0);
}
private function updateCartTotals($total, $subtotal, $tax)
{
$total->setTotalAmount('subtotal', $subtotal);
$total->setBaseTotalAmount('subtotal', $subtotal);
$total->setSubtotalInclTax($subtotal);
$total->setBaseSubtotalInclTax($subtotal);
$total->setTotalAmount('tax', $tax);
$total->setBaseTotalAmount('tax', $tax);
$total->setGrandTotal($subtotal);
}
}
but even with normal items (VAT inclusive) the shipping is not being calculated in the totals for the checkout page, e.g:
in this case the grand total should be £11.44
I’ve tried changing the sort order in the sales.xml file to 101 and 600 and a few other values in between but none of them seem to work for some reason. Any help would be greatly appreciated 🙂
Cheers
