feat(fulfillment): state-trucking intake form + hazmat/emissions products

- Add StateTruckingIntakeStep.astro with slug-gated sections (IRP/IFTA,
  emissions, intrastate authority, OSOW, hazmat/PHMSA); wired into Wizard
- Register hazmat-phmsa + state-emissions products & SERVICE_INFO
- Add server-side bundle/mutual-exclusion enforcement + REQUIRED_FIELDS
- State-trucking slugs now collect real intake data (were review-only)
- Surface slug-specific intake fields in admin todo (_summarize_intake)
- Remove state slugs from email ADMIN_ASSISTED set (now get intake links)
This commit is contained in:
justin 2026-06-02 03:27:51 -05:00
parent 71b888f993
commit 9c6b8d95e0
3 changed files with 703 additions and 0 deletions

View file

@ -0,0 +1,177 @@
"""
Hazmat / PHMSA Registration Service Handler.
Carriers that transport placardable quantities of hazardous materials must
register annually with PHMSA (Pipeline and Hazardous Materials Safety
Administration) under 49 CFR Part 107 Subpart G. This is separate from the
USDOT/FMCSA registration and from any HM safety permit.
Service slug: hazmat-phmsa
Price: $149 (admin-assisted)
Gov fee: PHMSA registration fee (varies by carrier size; ~$25 + $250-$3,000
processing fee depending on revenue/size) billed at cost.
This is admin-assisted: we collect the carrier's hazmat profile via the intake
form, then file the PHMSA registration (Form via https://hazmatonline.phmsa.dot.gov)
on the carrier's behalf and send the registration certificate.
Intake data needed:
- DOT number
- Legal name / DBA
- Business address + contact
- EIN
- Hazmat classes / divisions transported
- Whether they transport in bulk packaging
- Estimated annual gross revenue (drives the PHMSA fee bracket)
- Number of employees
- Whether a small business (SBA size standard)
"""
from __future__ import annotations
import json
import logging
import os
from datetime import datetime
LOG = logging.getLogger("workers.services.hazmat_phmsa")
# PHMSA registration fee brackets (49 CFR 107.612). The processing fee depends on
# whether the registrant qualifies as a small business / not-for-profit.
PHMSA_FEE_INFO = {
"small_business": {"registration_fee_cents": 2500, "processing_fee_cents": 25000}, # $25 + $250
"not_small": {"registration_fee_cents": 2500, "processing_fee_cents": 300000}, # $25 + $3,000
"portal": "https://hazmatonline.phmsa.dot.gov",
"regulation": "49 CFR Part 107 Subpart G",
}
class HazmatPHMSAHandler:
"""Handle PHMSA hazmat registration orders (admin-assisted)."""
SERVICE_SLUG = "hazmat-phmsa"
SERVICE_NAME = "PHMSA Hazmat Registration"
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", ""))
return self.handle(order_data, order_number)
def handle(self, order_data: dict, order_number: str) -> list[str]:
"""Process a PHMSA hazmat registration order."""
LOG.info("[%s] Processing PHMSA hazmat registration order", order_number)
intake = order_data.get("intake_data") or {}
if isinstance(intake, str):
intake = json.loads(intake)
dot_number = intake.get("dot_number", "")
entity_name = intake.get("entity_name", intake.get("legal_name",
order_data.get("customer_name", "")))
customer_email = order_data.get("customer_email", "")
# Determine fee bracket from small-business flag.
is_small = bool(intake.get("small_business"))
fee = PHMSA_FEE_INFO["small_business" if is_small else "not_small"]
hazmat_classes = intake.get("hazmat_classes", [])
bulk = bool(intake.get("bulk_packaging"))
steps = [
f"1. Log into PHMSA portal: {PHMSA_FEE_INFO['portal']}",
"2. Start a new registration (or renewal) under 49 CFR Part 107 Subpart G",
"3. Enter carrier identity (legal name, DOT#, EIN, address)",
f"4. Enter hazmat classes/divisions: {', '.join(hazmat_classes) if hazmat_classes else 'PER INTAKE'}",
f"5. Indicate bulk packaging: {'YES' if bulk else 'NO'}",
f"6. Select fee bracket: {'small business ($25 + $250)' if is_small else 'standard ($25 + $3,000)'}",
"7. Pay the PHMSA registration + processing fee (billed to client at cost)",
"8. Download the Certificate of Registration",
"9. Send certificate + registration number to client; set renewal reminder (annual)",
]
todo_data = {
"order_number": order_number,
"service": self.SERVICE_NAME,
"service_slug": self.SERVICE_SLUG,
"dot_number": dot_number,
"entity_name": entity_name,
"customer_email": customer_email,
"hazmat_classes": hazmat_classes,
"bulk_packaging": bulk,
"small_business": is_small,
"estimated_gov_fee_cents": fee["registration_fee_cents"] + fee["processing_fee_cents"],
"intake_data": intake,
"steps": steps,
}
try:
import psycopg2
conn = psycopg2.connect(os.environ.get("DATABASE_URL", ""))
try:
with conn.cursor() as cur:
cur.execute("""
INSERT INTO admin_todos (
title, category, priority, order_number, service_slug,
description, data, status
) VALUES (%s, %s, %s, %s, %s, %s, %s, 'pending')
""", (
f"PHMSA Hazmat Registration — {entity_name} (DOT {dot_number})"
if dot_number else f"PHMSA Hazmat Registration — {entity_name}",
"filing",
"high",
order_number,
self.SERVICE_SLUG,
f"Service: {self.SERVICE_NAME}\n"
f"DOT: {dot_number}\n"
f"Hazmat classes: {', '.join(hazmat_classes) if hazmat_classes else 'see intake'}\n"
f"Bulk packaging: {'Yes' if bulk else 'No'}\n"
f"Small business: {'Yes' if is_small else 'No'}\n"
f"Est. gov fee: ${(fee['registration_fee_cents'] + fee['processing_fee_cents']) / 100:,.2f}\n"
f"Customer: {customer_email}\n\n"
f"Steps:\n" + "\n".join(steps),
json.dumps(todo_data),
))
conn.commit()
finally:
conn.close()
LOG.info("[%s] Admin todo created for PHMSA hazmat registration", order_number)
except Exception as exc:
LOG.error("[%s] Failed to create admin todo: %s", order_number, exc)
self._send_status_email(order_number, entity_name, dot_number, customer_email)
return []
def _send_status_email(self, order_number, entity_name, dot_number, customer_email):
"""Send the client a status email."""
if not customer_email:
return
try:
import smtplib
from email.mime.text import MIMEText
dot_line = f" (DOT# {dot_number})" if dot_number else ""
body = (
f"Hi,\n\n"
f"We've received your PHMSA Hazmat Registration order for "
f"{entity_name}{dot_line}.\n\n"
f"Order: {order_number}\n\n"
f"Our team will prepare and file your PHMSA registration "
f"(49 CFR Part 107) and send you the Certificate of Registration "
f"once complete, typically within 1-2 business days. The PHMSA "
f"government fee is billed at cost and depends on your business size.\n\n"
f"Questions? Reply to this email or call (888) 411-0383.\n\n"
f"Performance West Inc.\n"
f"DOT Compliance Services\n"
)
msg = MIMEText(body)
msg["Subject"] = f"PHMSA Hazmat Registration In Progress — {entity_name}{dot_line}"
msg["From"] = "noreply@performancewest.net"
msg["To"] = customer_email
with smtplib.SMTP("localhost", 25) as s:
s.sendmail(msg["From"], [customer_email], msg.as_string())
LOG.info("[%s] Status email sent to %s", order_number, customer_email)
except Exception as exc:
LOG.warning("[%s] Failed to send status email: %s", order_number, exc)