Applying a 10% coupon discount after tax rather than before it systematically overcharges US customers. In most US states, sales tax is calculated on the post-discount price — applying tax first and then the discount is incorrect under standard US sales tax rules (CWE-682, ISO 25010:2011 functional correctness). A $100 cart with a $10 coupon should produce $90 × 0.085 = $7.65 tax; applying tax before discount produces $8.50 — a $0.85 overcharge per transaction that compounds across every discounted order. When the discount/tax order differs between cart preview and checkout confirmation, customers see a lower total in the cart and a higher total at payment, which triggers abandonment and disputes.
Medium because per-order overcharges from incorrect operation order are small individually but accumulate across every discounted transaction and produce checkout total inconsistencies that customers recognize and flag.
Enforce the correct US order of operations in lib/checkout.ts: subtract discount from subtotal before computing tax:
// lib/checkout.ts — correct US: tax after discount
function calculateOrderTotal(
items: OrderItem[],
discountCode: string | undefined,
address: Address
): OrderSummary {
const subtotal = items.reduce((sum, i) => sum + i.price * i.quantity, 0)
const discount = discountCode ? applyDiscount(subtotal, discountCode) : 0
const subtotalAfterDiscount = subtotal - discount
// Tax is computed on the post-discount taxable amount
const tax = calculateTax(items, address, subtotalAfterDiscount)
const shipping = calculateShipping(items, address)
const total = subtotalAfterDiscount + tax + shipping
return { subtotal, discount, tax, shipping, total }
}
Add a code comment citing the jurisdiction rule. If cart preview uses a separate path, consolidate both onto the same calculateOrderTotal function so the operation order is never divergent.
ID: ecommerce-shipping-tax.tax-computation.discount-application
Severity: medium
What to look for: List all steps in the order total calculation function in sequence: (1) subtotal, (2) discount application, (3) tax calculation, (4) shipping, (5) total. Classify the order of operations: is tax applied to the pre-discount or post-discount subtotal? Count how many calculation paths exist (e.g., checkout vs cart preview).
Pass criteria: Tax is calculated on the post-discount subtotal for US-based stores (the standard approach), with the discount applied before the tax calculation step. The order of operations is consistent across at least 2 calculation paths (cart summary and checkout confirmation). A code comment or documentation note explains the jurisdiction rule if a non-standard approach is used.
Fail criteria: Tax is applied to the pre-discount subtotal in a US-based store (overcharging the customer), or the discount/tax order differs between cart and checkout calculation paths.
Skip (N/A) when: The business does not offer discounts (no discount/coupon code logic found) or does not collect sales tax.
Detail on fail: "Tax applied before discount in lib/checkout.ts: subtotal ($100) → tax ($8.50) → discount ($10) → total. Customer overcharged by $0.85." or "Cart calculates tax post-discount but checkout calculates pre-discount — inconsistent across 2 paths."
Remediation: Apply discounts before tax (US standard) in lib/checkout.ts:
// US: Tax after discount (standard)
function calculateOrderTotal(items: OrderItem[], discountCode?: string, address?: Address): OrderSummary {
const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0)
const discount = discountCode ? applyDiscount(subtotal, discountCode) : 0
const subtotalAfterDiscount = subtotal - discount
const tax = calculateTax(subtotalAfterDiscount, address, items)
const shipping = calculateShipping(items, address)
const total = subtotalAfterDiscount + tax + shipping
return { subtotal, discount, tax, shipping, total }
}