mcs150 handler: derive admin-assisted intake from census; gate ready_to_file
Admin-assisted DOT services (UCR, BOC-3) routed to this handler were marked ready_to_file with whatever intake existed -- e.g. a UCR with only a DOT number, missing legal name / state / fleet-size bracket (which sets the UCR fee tier). That made the admin 'ready to file' status dishonest and unfileable. Now, for ADMIN_ASSISTED_REQUIRED services we first enrich intake from the FMCSA census (legal_name, address_state, power_units) + the order email, and derive the UCR fleet_size_bracket from power units (UCR_FLEET_BRACKETS). If every required field is then present we persist it and mark intake validated (falls through to the admin review gate -> ready_to_file). If anything is still missing, we persist what we have, set fulfillment_status=awaiting_intake, and email the customer to complete intake -- instead of falsely showing ready_to_file.
This commit is contained in:
parent
8e1e2f16bf
commit
3df3a08221
1 changed files with 126 additions and 0 deletions
|
|
@ -69,6 +69,34 @@ class MCS150UpdateHandler:
|
|||
"dot-full-compliance",
|
||||
})
|
||||
|
||||
# Admin-assisted DOT services routed to this handler that do NOT produce an
|
||||
# MCS-150 form, but still need a minimum set of intake fields before a human
|
||||
# can actually file them. Without this, a paid order would be marked
|
||||
# ready_to_file with empty intake (e.g. UCR with only a DOT number -- no
|
||||
# legal name / state / fleet size, which determine the UCR fee bracket and
|
||||
# the filing itself). Most of these can be DERIVED from the FMCSA census +
|
||||
# the order email (see _enrich_admin_assisted_intake); we only hold the order
|
||||
# at awaiting_intake for whatever genuinely can't be filled in. Keys are
|
||||
# service slugs; values are the required intake_data fields. Mirrors
|
||||
# REQUIRED_FIELDS in api/src/routes/compliance-orders.ts.
|
||||
ADMIN_ASSISTED_REQUIRED = {
|
||||
"ucr-registration": ["dot_number", "legal_name", "address_state", "email", "fleet_size_bracket"],
|
||||
"boc3-filing": ["dot_number", "legal_name", "email"],
|
||||
}
|
||||
|
||||
# UCR fee tiers by total power units (FMCSA 2025 schedule). Used to derive
|
||||
# fleet_size_bracket from the carrier's census power-unit count so we don't
|
||||
# have to ask the customer for something the public record already states.
|
||||
# (low, high_inclusive, bracket_label)
|
||||
UCR_FLEET_BRACKETS = [
|
||||
(0, 2, "0-2"),
|
||||
(3, 5, "3-5"),
|
||||
(6, 20, "6-20"),
|
||||
(21, 100, "21-100"),
|
||||
(101, 1000, "101-1000"),
|
||||
(1001, 10**9, "1001+"),
|
||||
]
|
||||
|
||||
async def process(self, order_data: dict) -> list[str]:
|
||||
"""Entry point called by job_server. Delegates to handle()."""
|
||||
order_number = order_data.get("order_number", order_data.get("name", ""))
|
||||
|
|
@ -158,6 +186,34 @@ class MCS150UpdateHandler:
|
|||
order_number, missing)
|
||||
return []
|
||||
|
||||
# INTAKE-COMPLETENESS GATE for admin-assisted (non-MCS-150) services.
|
||||
# These don't produce a form, but we still must not mark them
|
||||
# ready_to_file with empty intake (e.g. a UCR with only a DOT number).
|
||||
# First DERIVE everything we can from the FMCSA census + the order email,
|
||||
# then -- if any required field is still missing -- email the customer to
|
||||
# complete intake and hold the order at awaiting_intake. When all
|
||||
# required fields are present (derived or supplied) we fall through to the
|
||||
# admin review gate, which marks it ready_to_file for a human to file.
|
||||
if slug in self.ADMIN_ASSISTED_REQUIRED:
|
||||
intake = self._enrich_admin_assisted_intake(slug, intake, customer_email)
|
||||
order_data["intake_data"] = intake # persist derived values downstream
|
||||
missing = [f for f in self.ADMIN_ASSISTED_REQUIRED[slug]
|
||||
if intake.get(f) in (None, "", [], {})]
|
||||
if missing:
|
||||
self._persist_intake(order_number, intake)
|
||||
self._set_fulfillment_status(order_number, "awaiting_intake")
|
||||
self._request_intake_completion(
|
||||
order_number, entity_name, customer_email, dot_number, missing)
|
||||
LOG.info("[%s] Admin-assisted %s held for intake; missing=%s",
|
||||
order_number, slug, missing)
|
||||
return []
|
||||
# All required fields present -- persist the census-derived values so
|
||||
# the admin (and validation) sees a complete intake.
|
||||
self._persist_intake(order_number, intake)
|
||||
self._mark_intake_validated(order_number)
|
||||
LOG.info("[%s] Admin-assisted %s intake complete (derived from census)",
|
||||
order_number, slug)
|
||||
|
||||
# Step 1: Fill the official MCS-150 PDF. Only services that actually file
|
||||
# an MCS-150 produce the form; the other admin-assisted DOT services
|
||||
# routed to this handler (UCR, MC authority, audit prep, ETA, name
|
||||
|
|
@ -701,6 +757,76 @@ class MCS150UpdateHandler:
|
|||
except Exception as exc:
|
||||
LOG.warning("[%s] Failed to set fulfillment_status=%s: %s", order_number, status, exc)
|
||||
|
||||
def _enrich_admin_assisted_intake(self, slug: str, intake: dict, customer_email: str) -> dict:
|
||||
"""Fill an admin-assisted service's required intake from data we already
|
||||
have: the FMCSA census (legal_name, address_state, power_units) and the
|
||||
order's customer_email. Customer-supplied values always win. Returns a
|
||||
new merged dict; never raises.
|
||||
"""
|
||||
out = dict(intake or {})
|
||||
dot = out.get("dot_number", "")
|
||||
try:
|
||||
census = self._fetch_carrier_record(dot) if dot else {}
|
||||
except Exception as exc: # noqa: BLE001
|
||||
LOG.warning("[enrich] census fetch failed for DOT %s: %s", dot, exc)
|
||||
census = {}
|
||||
# Census fills only what the customer didn't already provide.
|
||||
for k in ("legal_name", "address_state", "address_city", "address_street",
|
||||
"address_zip", "power_units", "ein", "phone"):
|
||||
if not out.get(k) and census.get(k):
|
||||
out[k] = census[k]
|
||||
# Contact email: fall back to the order's customer email.
|
||||
if not out.get("email") and customer_email:
|
||||
out["email"] = customer_email
|
||||
# UCR fee bracket: derive from power units when not supplied.
|
||||
if slug == "ucr-registration" and not out.get("fleet_size_bracket"):
|
||||
pu = out.get("power_units") or census.get("power_units")
|
||||
try:
|
||||
n = int(str(pu).strip())
|
||||
except (TypeError, ValueError):
|
||||
n = None
|
||||
if n is not None:
|
||||
for lo, hi, label in self.UCR_FLEET_BRACKETS:
|
||||
if lo <= n <= hi:
|
||||
out["fleet_size_bracket"] = label
|
||||
break
|
||||
return out
|
||||
|
||||
def _persist_intake(self, order_number: str, intake: dict):
|
||||
"""Write the (possibly census-enriched) intake_data back to the order so
|
||||
the admin view, validation, and any later re-dispatch see it."""
|
||||
try:
|
||||
import psycopg2
|
||||
conn = psycopg2.connect(os.environ.get("DATABASE_URL", ""))
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"UPDATE compliance_orders SET intake_data=%s, updated_at=now() "
|
||||
"WHERE order_number=%s",
|
||||
(json.dumps(intake), order_number),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except Exception as exc: # noqa: BLE001
|
||||
LOG.warning("[%s] Failed to persist intake_data: %s", order_number, exc)
|
||||
|
||||
def _mark_intake_validated(self, order_number: str):
|
||||
"""Flag intake as complete so the order stops getting reminder nudges and
|
||||
the admin sees a green 'intake complete'. Only call once every required
|
||||
field is present (derived or supplied)."""
|
||||
try:
|
||||
import psycopg2
|
||||
conn = psycopg2.connect(os.environ.get("DATABASE_URL", ""))
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"UPDATE compliance_orders SET intake_data_validated=TRUE, "
|
||||
"validation_errors=NULL, updated_at=now() WHERE order_number=%s",
|
||||
(order_number,),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except Exception as exc: # noqa: BLE001
|
||||
LOG.warning("[%s] Failed to mark intake validated: %s", order_number, exc)
|
||||
|
||||
def _create_admin_review_todo(self, order_number, entity_name, dot_number,
|
||||
slug, minio_path, customer_email, client_signed):
|
||||
"""High-priority admin todo: verify the prepared filing BEFORE submission.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue