""" BOC-3 Process Agent Designation Service Handler. The BOC-3 designates a process agent in every US state who can accept legal documents on behalf of a motor carrier. The process agent (not the carrier) files the form with FMCSA. Model: Performance West partners with a blanket process agent service (e.g., NWRA or similar) who covers all 48 contiguous states + DC. We collect the carrier's info, submit the designation to our process agent partner, they file the BOC-3 electronically with FMCSA. Service slug: boc3-filing Price: $149 Gov fee: $0 Intake data needed: - DOT number - MC/FF/MX number (docket number) - Legal name - DBA name (if any) - Business address - Phone number - Email - Entity type (carrier, broker, freight forwarder) Filing flow: 1. Client orders BOC-3 filing 2. We collect intake data 3. We submit designation request to process agent partner 4. Process agent files BOC-3 electronically with FMCSA 5. We verify filing on FMCSA L&I system 6. We send confirmation to client """ from __future__ import annotations import json import logging import os from datetime import datetime LOG = logging.getLogger("workers.services.boc3_filing") # Process agent partner details — update when partnership is established PROCESS_AGENT_PARTNER = { "name": "TBD — NWRA or similar", "contact_email": "", "api_endpoint": None, # Will be set when partner API is available } class BOC3FilingHandler: """Handle BOC-3 process agent designation orders.""" SERVICE_SLUG = "boc3-filing" SERVICE_NAME = "BOC-3 Process Agent Filing" def handle(self, order_data: dict, order_number: str) -> list[str]: """ Process a BOC-3 filing order. Currently creates an admin todo. When process agent partner API is available, this will automate the submission. """ LOG.info("[%s] Processing BOC-3 filing order", order_number) intake = order_data.get("intake_data") or {} if isinstance(intake, str): intake = json.loads(intake) dot_number = intake.get("dot_number", "") docket_number = intake.get("docket_number", "") # MC-XXXXXX entity_name = intake.get("entity_name", order_data.get("customer_name", "")) customer_email = order_data.get("customer_email", "") entity_type = intake.get("entity_type", "carrier") # carrier, broker, freight_forwarder if not dot_number: LOG.error("[%s] Missing DOT number", order_number) return [] # Check current BOC-3 status boc3_status = self._check_boc3_status(dot_number) # Build the designation request designation = { "dot_number": dot_number, "docket_number": docket_number, "legal_name": entity_name, "dba_name": intake.get("dba_name", ""), "business_address": { "street": intake.get("address_street", ""), "city": intake.get("address_city", ""), "state": intake.get("address_state", ""), "zip": intake.get("address_zip", ""), }, "phone": intake.get("phone", ""), "email": customer_email, "entity_type": entity_type, "requested_at": datetime.utcnow().isoformat(), } # If we have a process agent API, submit directly if PROCESS_AGENT_PARTNER.get("api_endpoint"): success = self._submit_to_process_agent(designation) if success: self._send_confirmation_email(order_number, entity_name, dot_number, customer_email) return [] # Otherwise create admin todo todo_data = { "order_number": order_number, "service": self.SERVICE_NAME, "designation": designation, "current_boc3_status": boc3_status, "steps": [ "1. Submit BOC-3 designation request to process agent partner", f" Partner: {PROCESS_AGENT_PARTNER['name']}", f" Email: {PROCESS_AGENT_PARTNER.get('contact_email', 'TBD')}", "2. Include: DOT#, MC#, legal name, address for all 48 states + DC", "3. Process agent files BOC-3 electronically with FMCSA", "4. Verify filing at https://li-public.fmcsa.dot.gov/LIVIEW/pkg_carrquery.prc_carrlist", "5. Send confirmation to client", ], } try: import psycopg2 conn = psycopg2.connect(os.environ.get("DATABASE_URL", "")) 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"BOC-3 Filing — {entity_name} (DOT {dot_number})", "filing", "high", order_number, self.SERVICE_SLUG, f"File BOC-3 process agent designation for {entity_name}.\n" f"DOT: {dot_number}\n" f"MC/Docket: {docket_number}\n" f"Type: {entity_type}\n" f"Customer: {customer_email}\n\n" f"Submit to process agent partner for electronic filing with FMCSA.", json.dumps(todo_data), )) conn.commit() conn.close() LOG.info("[%s] Admin todo created for BOC-3 filing", order_number) except Exception as exc: LOG.error("[%s] Failed to create admin todo: %s", order_number, exc) # Send status email self._send_status_email(order_number, entity_name, dot_number, customer_email) return [] def _check_boc3_status(self, dot_number: str) -> str: """Check if carrier has a BOC-3 on file via FMCSA API.""" try: import urllib.request api_key = os.environ.get("FMCSA_API_KEY", "") if not api_key: return "API key not configured" url = ( f"https://mobile.fmcsa.dot.gov/qc/services/carriers/" f"{dot_number}?webKey={api_key}" ) req = urllib.request.Request(url, headers={"Accept": "application/json"}) with urllib.request.urlopen(req, timeout=10) as resp: data = json.loads(resp.read()) carrier = data.get("content", {}).get("carrier", {}) # BOC-3 status isn't directly in the API, but we can check # if authority is active (requires BOC-3 + insurance on file) common = carrier.get("commonAuthorityStatus", "N") contract = carrier.get("contractAuthorityStatus", "N") broker = carrier.get("brokerAuthorityStatus", "N") if common == "A" or contract == "A" or broker == "A": return "Authority active (BOC-3 likely on file)" else: return "No active authority (BOC-3 may be needed)" except Exception as exc: return f"Could not check: {exc}" def _submit_to_process_agent(self, designation: dict) -> bool: """Submit designation to process agent partner via API.""" # TODO: Implement when partner API is available LOG.warning("Process agent API not configured — falling back to admin todo") return False def _send_status_email(self, order_number, entity_name, dot_number, customer_email): """Send client an email that we're working on their BOC-3.""" if not customer_email: return try: import smtplib from email.mime.text import MIMEText body = ( f"Hi,\n\n" f"We've received your BOC-3 process agent designation order for " f"{entity_name} (DOT# {dot_number}).\n\n" f"Order: {order_number}\n\n" f"We're submitting your designation to our blanket process agent " f"who covers all 48 contiguous states plus DC. Once filed with " f"FMCSA, your operating authority will reflect the active BOC-3.\n\n" f"This is typically completed within 1-2 business days.\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"BOC-3 Filing In Progress — {entity_name} (DOT {dot_number})" 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) def _send_confirmation_email(self, order_number, entity_name, dot_number, customer_email): """Send confirmation that BOC-3 has been filed.""" if not customer_email: return try: import smtplib from email.mime.text import MIMEText body = ( f"Hi,\n\n" f"Your BOC-3 process agent designation has been filed with FMCSA " f"for {entity_name} (DOT# {dot_number}).\n\n" f"Order: {order_number}\n\n" f"Your process agent is now designated in all 48 contiguous states " f"plus the District of Columbia. This designation remains active " f"as long as your carrier account is maintained.\n\n" f"You can verify your BOC-3 status at:\n" f"https://li-public.fmcsa.dot.gov/LIVIEW/pkg_carrquery.prc_carrlist\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"BOC-3 Filed — {entity_name} (DOT {dot_number})" 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] Confirmation email sent to %s", order_number, customer_email) except Exception as exc: LOG.warning("[%s] Failed to send confirmation email: %s", order_number, exc)