# Variant prices override base price when applicable

- **Pattern:** `ab-001122` (`ecommerce-catalog.variant-pricing.variant-price-override`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001122
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001122)

## Why it matters

When a variant has a custom price but the display and cart always use the base product price, customers see one price on the listing and are charged a different amount at checkout — or variants intended to cost more (e.g., XL size surcharge) are sold at the base price, creating a revenue shortfall on every sale of that variant. ISO 25010:2011 functional-correctness requires that price-affecting selections are reflected consistently across all display and calculation contexts. A product page showing $29.99 and a cart showing $24.99 erodes trust even when the error favors the customer.

## Severity rationale

High because ignoring variant prices causes customers to be charged the wrong amount, producing either customer complaints when overcharged or silent revenue loss when undercharged.

## Remediation

Centralize variant price resolution in `src/lib/pricing.ts` so all display components and cart calculations use a single source of truth.

```ts
export const resolvePrice = (
  product: { price: Decimal },
  variant?: { price?: Decimal | null } | null
): Decimal => {
  if (variant?.price != null) return variant.price
  return product.price
}
```

Import `resolvePrice` in `src/components/product/ProductCard.tsx`, `src/app/products/[slug]/page.tsx`, and `src/components/cart/CartItem.tsx`. Do not inline the fallback logic in each component — divergence between components is how this bug reappears.

## Detection

- **ID:** `variant-price-override`
- **Severity:** `high`
- **What to look for:** Count all price display locations in the codebase: product listing components (`src/components/product/ProductCard.tsx`), product detail pages (`src/app/products/[slug]/page.tsx`), cart line items (`src/components/cart/CartItem.tsx`), and API responses. For each location, check whether variant-specific prices are used when a variant has a custom price, or if the base product price is always displayed regardless.
- **Pass criteria:** If a variant has a custom price field, that price is used in at least 1 display location and in cart calculations. If a variant has no custom price, the base product price is used as fallback. Count all price display locations and report: "X of Y price display locations use variant price when available."
- **Fail criteria:** Variant prices are ignored in all display and calculation locations — the base product price is always used even when a variant has a different price.
- **Skip (N/A) when:** No variants have custom pricing fields in the schema — confirmed by examining the variant model and finding no price-related field.
- **Cross-reference:** For price display formatting, the Geo-Readiness audit covers locale-aware currency formatting.
- **Cross-reference:** For cart calculation accuracy, the Pre-Launch audit covers order total correctness.
- **Cross-reference:** For pricing consistency across views, the Performance Core audit covers data consistency in cached vs. fresh renders.
- **Detail on fail:** `"Variant schema has price field but src/components/product/ProductCard.tsx always displays product.price instead of variant.price"` or `"Cart in src/components/cart/CartItem.tsx uses base product price instead of variant price"`
- **Remediation:** Use variant price if present, fall back to base price in `src/lib/pricing.ts`:

  ```ts
  const getPrice = (product, variant) => {
    if (variant?.price) {
      return variant.price
    }
    return product.price
  }
  ```

## External references

- iso-25010 functional-correctness

Taxons: data-integrity

HTML version: https://auditbuffet.com/patterns/ab-001122
