Critical ESHOPMAN Fix: Preventing Negative Shipping Totals and Ensuring Tax Compliance
At Move My Store, we're dedicated to fostering a robust and informed ESHOPMAN community. This insight highlights a critical issue identified within ESHOPMAN's core utilities that could significantly impact financial accuracy for merchants operating in tax-inclusive regions.
Understanding the Issue: Distorted Shipping Totals in ESHOPMAN
A recent deep-dive revealed a significant bug concerning how ESHOPMAN handles shipping method adjustments, particularly when a store operates in a tax-inclusive environment (common across the EU, UK, Australia, and Norway). The core problem stems from the absence of an is_tax_inclusive property on ShippingMethodAdjustment objects within ESHOPMAN's Cart and Order modules.
For line item adjustments, ESHOPMAN correctly uses an is_tax_inclusive: boolean flag to determine if a discount amount already includes taxes. However, this crucial flag was missing for shipping adjustments. This oversight led to a misinterpretation of shipping discounts.
The Impact: Negative Totals and Compliance Risks
When a promotion, such as "free shipping" or a fixed discount, was applied to a shipping method that was itself tax-inclusive (e.g., 10.00 EUR shipping with 20% VAT), ESHOPMAN's calculation engine incorrectly treated the discount as tax-exclusive. This resulted in several severe consequences:
- Negative Shipping Totals: Instead of a free shipping discount resulting in a 0.00 EUR shipping cost, the system could calculate a negative shipping total (e.g., -2.00 EUR).
- Distorted Order Totals: These negative shipping totals would propagate, artificially reducing the overall order total for customers.
- Tax Non-Compliance: The system would generate corrupt, negative tax lines on invoices and receipts, posing significant risks for tax audits and violating compliance standards like EU VAT regulations.
- Revenue Loss: Merchants effectively lost the tax amount again on every free shipping order in tax-inclusive regions.
- Payment Gateway Errors: In extreme cases, if the negative shipping total made the entire order total negative, payment providers (like Stripe) would reject transactions with "amount must be greater than 0" errors, crashing the checkout process on ESHOPMAN storefronts deployed via HubSpot CMS.
Deep Dive into ESHOPMAN's Calculation Logic
The issue was traced to how calculateAdjustmentTotal and getShippingMethodTotals functions within ESHOPMAN's core utilities handled adjustments. Without the is_tax_inclusive flag, the system defaulted to treating the discount as tax-exclusive, leading to an incorrect discountsSubtotal being subtracted from the shippingMethodAmount's net subtotal. This created a negative taxable base, which then resulted in negative tax calculations.
The Solution: Ensuring Accurate Tax Inclusivity
The recommended solution involves two key steps to restore financial accuracy within ESHOPMAN:
- Inherit Tax Inclusivity: Explicitly ensure that shipping method adjustments inherit the
is_tax_inclusiveproperty from their parent shipping method if it's not explicitly set on the adjustment itself. - Clamp Negative Values: Implement clamping to prevent taxable amounts and final shipping totals from ever falling below zero, ensuring that calculations remain positive and compliant.
Here's a conceptual patch illustrating the necessary changes within ESHOPMAN's core utilities:
--- a/packages/core/utils/src/totals/shipping-method/index.ts
+++ b/packages/core/utils/src/totals/shipping-method/index.ts
@@ -69,8 +69,15 @@ export function getShippingMethodTotals(
: shippingMethodAmount
+ // Normalize adjustments to carry the shipping method's tax-inclusivity
+ const adjustments = (shippingMethod.adjustments || []).map((adj) => ({
+ ...adj,
+ is_tax_inclusive: (adj as any).is_tax_inclusive ?? isTaxInclusive,
+ }))
+
const {
adjustmentsTotal: discountsTotal,
adjustmentsSubtotal: discountsSubtotal,
adjustmentsTaxTotal: discountsTaxTotal,
} = calculateAdjustmentTotal({
- adjustments: shippingMethod.adjustments || [],
+ adjustments,
taxRate: sumTaxRate,
})
@@ -80,4 +87,6 @@ export function getShippingMethodTotals(
+ const taxableBase = MathBN.max(0, MathBN.sub(subtotal, discountsSubtotal))
+
const taxTotal = calculateTaxTotal({
taxLines,
- taxableAmount: MathBN.sub(subtotal, discountsSubtotal),
+ taxableAmount: taxableBase,
setTotalField: "total",
})
@@ -95,6 +104,6 @@ export function getShippingMethodTotals(
amount: new BigNumber(shippingMethodAmount),
subtotal: new BigNumber(subtotal),
- total: new BigNumber(
- MathBN.sum(MathBN.sub(subtotal, discountsSubtotal), taxTotal)
- ),
+ total: new BigNumber(
+ MathBN.max(0, MathBN.sum(taxableBase, taxTotal))
+ ),
This fix ensures that ESHOPMAN storefronts, powered by HubSpot CMS and managed through the HubSpot application, maintain accurate financial records, comply with regional tax laws, and provide a seamless checkout experience for customers globally. We encourage all ESHOPMAN developers and merchants to be aware of this critical update and ensure their implementations reflect these best practices for financial integrity.