fix(intake): HC checkout 400 — resolve customer email/name from intake_data

The NPI/healthcare intake step persists provider email + name only into
intake_data (not the top-level state.email/state.name that the DOT/?dot=
flow sets). ReviewStep's order-create POST therefore sent empty
customer_email/customer_name -> API 400 'service_slug, customer_email, and
customer_name are required', blocking EVERY healthcare checkout at the
review step (explains 0 HC sales despite 13,425 sends).

ReviewStep now falls back to intake_data.{email,provider_name,
organization_name,legal_name,entity_name}; the Wizard cold-visitor create
path also now recognizes provider_name/organization_name. Verified the
trucking path is unaffected (it already populated top-level state).
This commit is contained in:
justin 2026-06-23 13:40:19 -05:00
parent f773718e4d
commit 60d2572f19
2 changed files with 12 additions and 3 deletions

View file

@ -622,7 +622,7 @@ const STEP_LABELS: Record<string, string> = {
// to and trucking services have no in-wizard payment step.
const d = state.intake_data || {};
const email = d.email || state.email || "";
const name = d.legal_name || d.entity_name || state.name || "";
const name = d.legal_name || d.entity_name || d.provider_name || d.organization_name || state.name || "";
if (!email || !name) {
alert("Please enter your business name and email before finishing.");
nextBtn.disabled = false;

View file

@ -85,13 +85,22 @@ const vertical = slugVertical(service_slug);
// Step 1: ensure we have an order_number for this session
let orderNumber = state.order_number;
if (!orderNumber) {
// Resolve customer email/name robustly. Some intake steps (e.g. NPI/
// healthcare) only persist these into intake_data, not the top-level
// state.email/state.name that the DOT/?dot= flow sets. Without this
// fallback the create POST sent empty strings and the API rejected it
// with HTTP 400 ("...are required"), blocking every HC checkout.
const d = (state.intake_data || {}) as any;
const customerEmail = state.email || d.email || d.contact_email || "";
const customerName = state.name || d.provider_name || d.organization_name
|| d.legal_name || d.entity_name || "";
const createResp = await fetch("/api/v1/compliance-orders", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
service_slug: slug,
customer_email: state.email,
customer_name: state.name,
customer_email: customerEmail,
customer_name: customerName,
telecom_entity_id: state.telecom_entity_id,
intake_data: state.intake_data,
// Filing mode + de minimis election (migrations 058/059)