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:
parent
5a07335b2f
commit
d39e10485f
2 changed files with 31 additions and 13 deletions
|
|
@ -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 */ }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue