From a90cdc906657e91146059b5d342336714bba5b3c Mon Sep 17 00:00:00 2001 From: justin Date: Tue, 23 Jun 2026 15:19:23 -0500 Subject: [PATCH] fix(trucking-email): route order CTAs to the correct service page (not $399 catch-all) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two routing bugs that sent carriers to wrong/dead order pages: 1. MCS-150 + Inactive campaigns linked to /order/dot-full-compliance ($399) instead of their actual service: build_lp_link()/lp_slug_for() fell through to the dot-full-compliance catch-all for any campaign_type not in DEFICIENCY_SEGMENTS, ignoring the existing PRICE_SLUG_BY_CAMPAIGN map. So MCS-150 carriers (should be mcs150-update $79) and Inactive carriers (should be usdot-reactivation $149) were both quoted a 5x-priced bundle they never asked for — a severe conversion killer on the two highest-volume segments. Fix: lp_slug_for() now checks PRICE_SLUG_BY_CAMPAIGN first; build_lp_link() delegates to it (single source of truth). 2. IFTA-quarterly + UCR-annual builders set lp_link to a BARE path when no coupon was active (LP_LINK with no query). The body appends '&utm_source=...' so the CTA rendered as /order/ifta-quarterly&utm... (no '?') = 404. Fix: both now always emit a leading '?' query carrying ?dot= (and ?code= when a coupon is on), mirroring the main builder's lp_link_with_coupon(). Audited every campaign_type: all 14 order slugs now resolve 200 and match the intended service/price. Compliance-check secondary links (/tools/dot-compliance- check) verified correct and intentionally kept where a 'check status' CTA fits. --- scripts/build_ifta_quarterly_campaign.py | 11 ++++++++++- scripts/build_trucking_campaigns.py | 18 ++++++++++-------- scripts/build_ucr_annual_campaign.py | 11 ++++++++++- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/scripts/build_ifta_quarterly_campaign.py b/scripts/build_ifta_quarterly_campaign.py index c6506e3..51a1c08 100644 --- a/scripts/build_ifta_quarterly_campaign.py +++ b/scripts/build_ifta_quarterly_campaign.py @@ -249,7 +249,16 @@ def main() -> int: headline = headline_t.format(due=due_human) def attribs(dot, company, state): - lp = f"{LP_LINK}?code={coupon}" if coupon else LP_LINK + # lp_link MUST start its query with `?` so the body's `&utm_source=...` + # appends cleanly. A bare path here yields `/order/ifta-quarterly&utm...` + # (no `?`) which 404s. Carry the carrier's `?dot=` (and `?code=` when a + # coupon is on) exactly like the main builder's lp_link_with_coupon(). + params = [] + if dot: + params.append(f"dot={dot}") + if coupon: + params.append(f"code={coupon}") + lp = f"{LP_LINK}?" + "&".join(params) if params else LP_LINK a = { "dot_number": dot or "", "company": company or "", "state": state or "", "lp_link": lp, diff --git a/scripts/build_trucking_campaigns.py b/scripts/build_trucking_campaigns.py index 716a585..fd74906 100644 --- a/scripts/build_trucking_campaigns.py +++ b/scripts/build_trucking_campaigns.py @@ -232,17 +232,19 @@ def discounted_price_attribs(campaign_type: str, phy_state: str | None, def build_lp_link(campaign_type: str, phy_state: str | None) -> str: """Return the order landing-page URL for a (segment, state).""" - seg = DEFICIENCY_SEGMENTS.get(campaign_type) - slug = seg["lp_slug"] if seg else "dot-full-compliance" - if campaign_type == "state_weight_tax" and phy_state in _WEIGHT_TAX_LP: - slug = _WEIGHT_TAX_LP[phy_state] - if campaign_type == "state_emissions" and phy_state == "CA": - slug = "ca-mcp-carb" - return f"{SITE_DOMAIN}/order/{slug}" + return f"{SITE_DOMAIN}/order/{lp_slug_for(campaign_type, phy_state)}" def lp_slug_for(campaign_type: str, phy_state: str | None = None) -> str: - """The order-page slug (== the discountable service slug) for a segment.""" + """The order-page slug (== the discountable service slug) for a segment. + + Main (non-deficiency) campaigns route to their SPECIFIC service via + PRICE_SLUG_BY_CAMPAIGN (mcs150 -> mcs150-update $79, inactive -> + usdot-reactivation $149). Without this they fell through to the + `dot-full-compliance` ($399) catch-all — sending MCS-150/Inactive carriers + to a 5x-priced page they never asked for (severe conversion killer).""" + if campaign_type in PRICE_SLUG_BY_CAMPAIGN: + return PRICE_SLUG_BY_CAMPAIGN[campaign_type] seg = DEFICIENCY_SEGMENTS.get(campaign_type) slug = seg["lp_slug"] if seg else "dot-full-compliance" if campaign_type == "state_weight_tax" and phy_state in _WEIGHT_TAX_LP: diff --git a/scripts/build_ucr_annual_campaign.py b/scripts/build_ucr_annual_campaign.py index cb298fd..6e0b5b3 100644 --- a/scripts/build_ucr_annual_campaign.py +++ b/scripts/build_ucr_annual_campaign.py @@ -196,7 +196,16 @@ def main() -> int: urgency = urgency_t.format(year=year, due=due_human) def attribs(dot, company, state): - lp = f"{LP_LINK}?code={coupon}" if coupon else LP_LINK + # lp_link MUST start its query with `?` so the body's `&utm_source=...` + # appends cleanly. A bare path here yields `/order/ucr-registration&utm...` + # (no `?`) which 404s. Carry the carrier's `?dot=` (and `?code=` when a + # coupon is on) exactly like the main builder's lp_link_with_coupon(). + params = [] + if dot: + params.append(f"dot={dot}") + if coupon: + params.append(f"code={coupon}") + lp = f"{LP_LINK}?" + "&".join(params) if params else LP_LINK a = { "dot_number": dot or "", "company": company or "", "state": state or "", "lp_link": lp,