intake: cold ?dot= visitors can finish + correct per-state CTA links
- Wizard Finish button: for visitors with no token/order (e.g. arriving via a campaign ?dot= link), create the compliance order from collected intake data and redirect to Stripe Checkout, instead of silently doing nothing. - StateTrucking: Operating States no longer required; single-state/intrastate carriers can finish (relabeled 'Other Operating States (if any)'). - build_trucking_campaigns: per-state programs (weight_tax/emissions) now derive the CTA landing page from the deficiency flag's state suffix (e.g. state_weight_tax_OR -> OR), not the carrier base state, so a GA-based carrier flagged for OR weight-mile tax links to the OR page (not a mismatched one).
This commit is contained in:
parent
d420c49818
commit
53ae3ef870
3 changed files with 94 additions and 17 deletions
|
|
@ -266,16 +266,22 @@ def create_and_schedule_campaign(
|
|||
def send_test(base: dict, campaign_id: int, sample_row: tuple, label: str, tz: str,
|
||||
campaign_type: str) -> None:
|
||||
"""Send one test email so the owner can approve before the real blast goes out."""
|
||||
dot, email, name, state = sample_row
|
||||
# sample_row is (dot, email, name, phy_state, target_state). Older callers may
|
||||
# still pass a 4-tuple (dot, email, name, state); handle both.
|
||||
dot, email, name, phy_state = sample_row[0], sample_row[1], sample_row[2], sample_row[3]
|
||||
target_state = sample_row[4] if len(sample_row) > 4 else phy_state
|
||||
state = phy_state
|
||||
body = base["body"]
|
||||
body = body.replace("{{ .Subscriber.Attribs.company }}", name or "Sample Carrier LLC")
|
||||
body = body.replace("{{ .Subscriber.Attribs.dot_number }}", dot or "0000000")
|
||||
body = body.replace("{{ .Subscriber.Attribs.state }}", state or "TX")
|
||||
# Real subscribers get a populated lp_link attrib; the test send must mirror
|
||||
# that or the CTA button (e.g. "Check My Emissions Status") renders as a bare
|
||||
# "?dot=..." that links to nowhere. Build the same link the audience gets.
|
||||
# "?dot=..." that links to nowhere. Build the same link the audience gets,
|
||||
# using the target_state (the state the offer applies to, which for per-state
|
||||
# programs comes from the deficiency flag, not the base state).
|
||||
body = body.replace("{{ .Subscriber.Attribs.lp_link }}",
|
||||
build_lp_link(campaign_type, state))
|
||||
build_lp_link(campaign_type, target_state))
|
||||
# NOTE: leave {{ UnsubscribeURL }} alone — Listmonk renders it into a real,
|
||||
# working per-subscriber unsubscribe link (even on test sends). Overwriting it
|
||||
# produced a dead /unsubscribe link with no subscriber identity.
|
||||
|
|
@ -304,7 +310,14 @@ def fetch_carriers(
|
|||
campaign_type: str,
|
||||
limit: int,
|
||||
) -> list[tuple]:
|
||||
"""Return (dot_number, email_address, legal_name, phy_state) rows."""
|
||||
"""Return (dot_number, email_address, legal_name, phy_state, target_state) rows.
|
||||
|
||||
target_state is the state the offer applies to. For most segments that is
|
||||
the carrier's base (phy_state). For per-state programs (state_weight_tax,
|
||||
state_emissions) the relevant state is encoded in the deficiency flag suffix
|
||||
(e.g. 'state_weight_tax_OR'), which can differ from the base state, so we
|
||||
pull it out of the flag so the CTA links to the correct state's order page.
|
||||
"""
|
||||
cur = conn.cursor()
|
||||
states_placeholder = ",".join(["%s"] * len(tz_states))
|
||||
if campaign_type == "mcs150":
|
||||
|
|
@ -317,8 +330,23 @@ def fetch_carriers(
|
|||
else:
|
||||
raise ValueError(f"unknown campaign_type {campaign_type!r}")
|
||||
|
||||
# target_state expression: pull the state suffix out of the matching flag
|
||||
# for per-state programs, otherwise fall back to the base (phy_state).
|
||||
if campaign_type in ("state_weight_tax", "state_emissions"):
|
||||
prefix = f"{campaign_type}_"
|
||||
target_state_sql = (
|
||||
"COALESCE((SELECT upper(substr(f, %s)) "
|
||||
"FROM unnest(deficiency_flags) f "
|
||||
f"WHERE f LIKE '{campaign_type}_%%' LIMIT 1), phy_state)"
|
||||
)
|
||||
target_state_params = [len(prefix) + 1]
|
||||
else:
|
||||
target_state_sql = "phy_state"
|
||||
target_state_params = []
|
||||
|
||||
cur.execute(f"""
|
||||
SELECT dot_number, email_address, legal_name, phy_state
|
||||
SELECT dot_number, email_address, legal_name, phy_state,
|
||||
{target_state_sql} AS target_state
|
||||
FROM fmcsa_carriers
|
||||
WHERE {type_filter}
|
||||
AND {USABLE_FILTER}
|
||||
|
|
@ -327,7 +355,7 @@ def fetch_carriers(
|
|||
AND phy_state IN ({states_placeholder})
|
||||
ORDER BY mcs150_parsed ASC NULLS LAST
|
||||
LIMIT %s
|
||||
""", [list(BLOCKED_EMAIL_DOMAINS)] + list(tz_states) + [limit])
|
||||
""", target_state_params + [list(BLOCKED_EMAIL_DOMAINS)] + list(tz_states) + [limit])
|
||||
return cur.fetchall()
|
||||
|
||||
|
||||
|
|
@ -453,7 +481,7 @@ def run(send_date: date, dry_run: bool = False, preview: bool = False,
|
|||
"email": TEST_EMAIL,
|
||||
"name": r0[2] or "Sample Carrier",
|
||||
"attribs": {"dot_number": r0[0], "company": r0[2] or "", "state": r0[3] or "",
|
||||
"lp_link": build_lp_link(campaign_type, r0[3])},
|
||||
"lp_link": build_lp_link(campaign_type, r0[4])},
|
||||
}]
|
||||
else:
|
||||
subscribers = [
|
||||
|
|
@ -461,7 +489,7 @@ def run(send_date: date, dry_run: bool = False, preview: bool = False,
|
|||
"email": row[1],
|
||||
"name": row[2] or row[1],
|
||||
"attribs": {"dot_number": row[0], "company": row[2] or "", "state": row[3] or "",
|
||||
"lp_link": build_lp_link(campaign_type, row[3])},
|
||||
"lp_link": build_lp_link(campaign_type, row[4])},
|
||||
}
|
||||
for row in rows
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue