Add URL promo code pre-fill and fix discount stacking logic

- Checkout page reads ?code= or ?promo= from URL, pre-fills and locks the
  promo field, shows the promo discount in the summary instead of the 15%
  bundle discount
- API: when a promo code % >= bundle %, replace the bundle discount entirely
  instead of stacking (e.g. MEMORIAL25 at 25% replaces the 15% bundle)
- Also checks discount code expiration in the query

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
justin 2026-05-21 15:06:19 -05:00
parent 5a07335b2f
commit d39e10485f
2 changed files with 31 additions and 13 deletions

View file

@ -975,25 +975,35 @@ router.post("/api/v1/compliance-orders/batch", async (req, res) => {
const govFeeTotal = services.reduce((sum, s) => sum + (COMPLIANCE_SERVICES[s].gov_fee_cents || 0), 0);
const subtotal = discountableTotal + nonDiscountableTotal + govFeeTotal;
// Bundle discount applies only to discountable services
const bundleDiscountPct = discountableServices.filter(s => COMPLIANCE_SERVICES[s].price_cents > 0).length >= 2 ? 15 : 0;
const bundleDiscountCents = Math.round(discountableTotal * bundleDiscountPct / 100);
// Bundle discount applies only to discountable services (2+ services = 15%)
let bundleDiscountPct = discountableServices.filter(s => COMPLIANCE_SERVICES[s].price_cents > 0).length >= 2 ? 15 : 0;
let bundleDiscountCents = Math.round(discountableTotal * bundleDiscountPct / 100);
// Referral/promo code discount also applies only to discountable services
// Referral/promo code discount — replaces bundle discount if promo is >= bundle %
let promoDiscountCents = 0;
if (discount_code) {
try {
const disc = await pool.query(
`SELECT discount_pct, discount_flat_cents FROM discount_codes WHERE code = $1 AND active = true`,
`SELECT discount_type, discount_value FROM discount_codes WHERE code = $1 AND active = true AND (expires_at IS NULL OR expires_at > now())`,
[discount_code.toUpperCase().trim()],
);
if (disc.rows.length > 0) {
const d = disc.rows[0] as Record<string, unknown>;
const discountableAfterBundle = discountableTotal - bundleDiscountCents;
if ((d.discount_pct as number) > 0) {
promoDiscountCents = Math.round(discountableAfterBundle * (d.discount_pct as number) / 100);
} else if ((d.discount_flat_cents as number) > 0) {
promoDiscountCents = Math.min(d.discount_flat_cents as number, discountableAfterBundle);
const discType = d.discount_type as string;
const discValue = d.discount_value as number;
if (discType === "percent" && discValue > 0) {
// If promo % >= bundle %, replace bundle discount entirely (don't stack)
if (discValue >= bundleDiscountPct) {
bundleDiscountPct = 0;
bundleDiscountCents = 0;
promoDiscountCents = Math.round(discountableTotal * discValue / 100);
} else {
// Smaller promo stacks on top of bundle
const afterBundle = discountableTotal - bundleDiscountCents;
promoDiscountCents = Math.round(afterBundle * discValue / 100);
}
} else if (discType === "flat" && discValue > 0) {
promoDiscountCents = Math.min(discValue, discountableTotal - bundleDiscountCents);
}
}
} catch { /* discount_codes table may not exist */ }