Skip to content

Add VAT Included line item for inclusive taxes - #1445

Open
pbennett1-godaddy wants to merge 4 commits into
mainfrom
inclusive-taxes-line-item
Open

Add VAT Included line item for inclusive taxes#1445
pbennett1-godaddy wants to merge 4 commits into
mainfrom
inclusive-taxes-line-item

Conversation

@pbennett1-godaddy

@pbennett1-godaddy pbennett1-godaddy commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a separate VAT Included line item to checkout and storefront order totals.

Inclusive taxes are already part of the displayed product price and are not included in order.totals.taxTotal. As a result, they were not visible in the existing Estimated taxes row. This
change derives the VAT amount from the order-level tax constituents and displays it separately without changing the amount due.

The VAT total:

  • Uses the tax constituent amount.value returned by the tax calculation pipeline.
  • Includes taxes where included === true.
  • Excludes taxes where additional === true.
  • Supports multiple inclusive tax constituents by summing their amounts.
  • Displays only when the resulting amount is greater than zero.
  • Uses the existing tax-loading state and currency formatting.
  • Does not add inclusive taxes to the order total.

The checkout draft-order query now retrieves order-level tax constituent amounts. The storefront order query also retrieves the additional flag so additive taxes can be explicitly excluded.

Localized labels were added for all supported locales, including GST Included for Australia.

CleanShot 2026-09-02 at 11 34 18@2x

Changeset

  • Changeset added (docs)

Test Plan

  • Added unit tests for inclusive tax total calculation:

    • Sums multiple inclusive tax constituents.
    • Excludes additive taxes.
    • Excludes taxes marked as both included and additional.
    • Handles missing taxes and amounts.
  • Added checkout integration coverage verifying:

    • The VAT Included row renders when inclusive taxes are present.
    • Multiple inclusive tax constituents are totaled.
    • Additive taxes are not included in the VAT amount.
    • The row is hidden when no positive inclusive tax amount exists.
  • Verified the VAT row uses the existing tax-loading state.

  • Ran the following validation:

    pnpm --filter @godaddy/localizations typecheck
    pnpm --filter @godaddy/react typecheck
    pnpm --filter @godaddy/react lint
    pnpm --filter @godaddy/react exec vitest run src/components/checkout/totals/utils/get-included-tax-total.test.ts src/components/checkout/tests/checkout-totals-summary.test.tsx

All checks and 12 relevant tests passed.

@pbennett1-godaddy
pbennett1-godaddy requested a review from a team as a code owner September 2, 2026 16:34
@changeset-bot

changeset-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6b0368c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@godaddy/localizations Patch
@godaddy/react Patch
nextjs Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@wcole1-godaddy wcole1-godaddy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — the feature is small and well-scoped, typecheck and the full @godaddy/react vitest suite pass on the branch, and all 21 locales have the new key. Requesting changes for the first two items below; the rest are non-blocking but worth addressing.

Should fix before merge

1. The additional exclusion is dead code on the checkout path, so cart and checkout can disagree.
getIncludedTaxTotal filters out additional === true, but the checkout schema's LineItemTax type has no additional field and DraftOrderQuery cannot select it — only the storefront OrderTax has it. Because TaxAmount.additional is optional, tsc never surfaces the gap. For an order with a tax that is both included and additional, the cart drawer excludes it and the checkout summary counts it. The unit test asserts a shape checkout can never produce.
Suggest either dropping the filter, or typing the helper against the real query result types (CartTax plus a DraftOrder['taxes'][number] alias) so the mismatch is visible, and documenting that the exclusion is storefront-only.
packages/react/src/components/checkout/totals/utils/get-included-tax-total.ts:16

2. The 502-line checkout-env.ts regen is unrelated to this PR.
It is insertion-only and adds tips, CheckoutSessionFee, calculateCheckoutSessionFees, FundingSourceType, etc. DraftOrder.taxes and LineItemTax already existed at the merge base, so the new taxes { ... } selection type-checks without it. The introspection is generated from a gitignored schema file, so reviewers can't reproduce it or confirm which endpoint it came from. Please revert that file here and land the schema sync as its own PR.

Should fix

3. The VAT row bypasses the enableTaxes switch.
"Estimated taxes" is gated by enableTaxes (derived in checkout-form from session.enableTaxCollection || taxTotal > 0); the new row is gated only on vatIncluded > 0. Two concrete effects: the library's own storefront Cart passes enableTaxes={false} to CartTotals while vatIncluded arrives via the spread, so the cart drawer now shows "VAT included" with no taxes row above it; and a merchant with tax collection disabled but tax-inclusive pricing gets a row they can't turn off except by passing vatIncluded={0}. If showing it in the cart is intentional, please say so in the description and add a dedicated enable prop.
packages/react/src/components/checkout/totals/totals.tsx:160

4. Stale VAT amount after tax/discount/shipping mutations.
isTaxLoading only tracks the pending updateDraftOrderTaxes mutation. Its onSuccess in use-update-taxes.ts patches totals only (and writes it under the key taxesTotal — pre-existing bug), and the discount/shipping mutations don't select taxes. So after an address change from a VAT region to a non-VAT one, the skeleton clears and the old VAT amount renders next to already-updated totals until the onSettled refetch lands. The skeleton also never shows on first appearance because vatIncluded is still 0 when loading starts.

5. Missing extension anchor.
Every sibling row has a <Target id='checkout.summary.totals.<row>.before' />; the new row doesn't, so UI extensions can't position relative to it.

Minor

  • Exempted constituents are counted. An included tax with exempted: true still adds to the VAT row while "Estimated taxes" shows zero. Worth confirming the API never emits that shape, or filtering it.
  • Public prop name is jurisdiction-specific. vatIncluded lands on the exported DraftOrderTotalsProps / CartTotals, yet enAu labels it "GST included" and the API returns per-constituent name. Consider includedTaxes for the prop and keep the VAT wording only in the locale key — renaming later is a breaking change.
  • Tests are weaker than the description claims. The description lists four integration cases; the diff adds one test plus one negative assertion. That negative assertion runs against the fixture default taxes: [], so it would pass if the row rendered whenever any tax exists. getAllByText('$1.23').length > 0 can't fail on length (getAllByText throws on zero matches) and doesn't tie the amount to the VAT row.
  • Over-fetching. The new order-level taxes selection in DraftOrderQuery requests currencyCode, exempted, id, name, ratePercentage, none of which the client reads, and this query refetches on every window focus and draft-order mutation.
  • Nit. The ?? null in useDraftOrderIncludedTaxTotal is redundant (the helper accepts undefined), and the cart call site omits it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants