"""FCC Carrier / ISP Registration pipeline handler. CRTC-style multi-step pipeline that orchestrates: 1. Formation (optional — creates formation_order, waits for completion) 2. CORES/FRN Registration 3. Form 499 Initial 4. D.C. Registered Agent 5. State PUC Registrations (per selected state) 6. RMD, CPNI, CALEA, BDC (as applicable) 7. STIR/SHAKEN + OCN (if add-ons selected) 8. Final review + client notification Each step checks its idempotency timestamp before running. Reuses existing service handler logic where possible. """ from __future__ import annotations import logging import os from datetime import datetime from typing import Optional import psycopg2 import psycopg2.extras logger = logging.getLogger(__name__) DATABASE_URL = os.environ.get("DATABASE_URL", "") class FCCCarrierRegistrationHandler: """Pipeline handler for FCC Carrier / ISP Registration orders.""" async def process(self, order_data: dict) -> list[str]: order_number = order_data.get("order_number", "") logger.info("FCCCarrierRegHandler: starting pipeline for %s", order_number) # Load order from PG conn = psycopg2.connect(DATABASE_URL) try: with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur: cur.execute( "SELECT * FROM fcc_carrier_registrations WHERE order_number = %s", (order_number,), ) order = cur.fetchone() finally: conn.close() if not order: logger.error("FCCCarrierRegHandler: order %s not found", order_number) return [] generated: list[str] = [] # ── Step 1: Formation (if needed) ───────────────────────────────── if order["include_formation"] and not order.get("formation_completed_at"): formation_order = order.get("formation_order_number") if formation_order: # Check if formation is complete conn = psycopg2.connect(DATABASE_URL) try: with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur: cur.execute( "SELECT automation_status, entity_name FROM formation_orders WHERE order_number = %s", (formation_order,), ) fo = cur.fetchone() finally: conn.close() if fo and fo.get("automation_status") in ("Delivered", "delivered"): self._update_step(order_number, "formation_completed_at") self._update_status(order_number, "formation_complete") logger.info("FCCCarrierRegHandler: formation complete for %s", order_number) else: # Formation still in progress — create admin todo and pause self._update_status(order_number, "awaiting_formation") self._create_todo( order_number, f"FCC Carrier Registration {order_number} is waiting for formation " f"order {formation_order} to complete. Dispatch the formation " f"pipeline if not already running.", ) logger.info( "FCCCarrierRegHandler: %s waiting for formation %s", order_number, formation_order, ) return [] else: logger.warning( "FCCCarrierRegHandler: %s needs formation but no formation_order_number", order_number, ) self._create_todo( order_number, f"FCC Carrier Registration {order_number} needs formation but " f"formation_order_number is missing. Create one manually.", ) return [] # ── Step 2: CORES/FRN ───────────────────────────────────────────── if not order.get("cores_completed_at"): self._update_status(order_number, "cores_registration") self._create_todo( order_number, f"FCC Carrier Registration {order_number}\n\n" f"Step 2: Register with FCC CORES and obtain FRN.\n" f"Entity: {order.get('entity_legal_name', '?')}\n" f"EIN: {order.get('ein', 'N/A')}\n" f"Contact: {order.get('contact_name', '')} ({order.get('contact_email', '')})\n" f"Address: {order.get('address_street', '')}, {order.get('address_city', '')} " f"{order.get('address_state', '')} {order.get('address_zip', '')}\n\n" f"After obtaining FRN, update the order:\n" f" UPDATE fcc_carrier_registrations SET frn_obtained = 'XXXXXXXXXX', " f"cores_completed_at = NOW() WHERE order_number = '{order_number}'", ) logger.info("FCCCarrierRegHandler: %s queued for CORES registration", order_number) return generated # ── Step 3: Form 499 Initial ────────────────────────────────────── if not order.get("form_499_completed_at"): self._update_status(order_number, "form_499_initial") self._create_todo( order_number, f"FCC Carrier Registration {order_number}\n\n" f"Step 3: File Form 499 Initial Registration at USAC E-File.\n" f"FRN: {order.get('frn_obtained') or order.get('frn', 'PENDING')}\n" f"Entity: {order.get('entity_legal_name', '?')}\n\n" f"After obtaining Filer ID, update the order:\n" f" UPDATE fcc_carrier_registrations SET filer_id_obtained = 'XXXXXX', " f"form_499_completed_at = NOW() WHERE order_number = '{order_number}'", ) return generated # ── Step 4: D.C. Registered Agent ───────────────────────────────── if order["include_dc_agent"] and not order.get("dc_agent_completed_at"): self._create_todo( order_number, f"FCC Carrier Registration {order_number}\n\n" f"Step 4: Place D.C. Registered Agent wholesale order with Northwest.\n" f"Entity: {order.get('entity_legal_name', '?')}\n" f"FRN: {order.get('frn_obtained') or order.get('frn', '')}\n\n" f"After placing NW order, update:\n" f" UPDATE fcc_carrier_registrations SET dc_agent_completed_at = NOW() " f"WHERE order_number = '{order_number}'", ) self._update_step(order_number, "dc_agent_completed_at") # ── Step 5: State PUC Registrations ─────────────────────────────── puc_states = order.get("state_puc_states") or [] if puc_states and not order.get("state_puc_completed_at"): self._update_status(order_number, "state_registrations") self._create_todo( order_number, f"FCC Carrier Registration {order_number}\n\n" f"Step 5: State PUC registrations for: {', '.join(puc_states)}\n" f"Entity: {order.get('entity_legal_name', '?')}\n\n" f"Create individual state_puc_registrations rows or handle manually.\n" f"After completing all states, update:\n" f" UPDATE fcc_carrier_registrations SET state_puc_completed_at = NOW() " f"WHERE order_number = '{order_number}'", ) return generated # ── Step 6: Compliance filings (RMD, CPNI, CALEA, BDC) ─────────── self._update_status(order_number, "compliance_filings") compliance_todos = [] if order["include_rmd"] and not order.get("rmd_completed_at"): compliance_todos.append("RMD Registration") if order["include_cpni"] and not order.get("cpni_completed_at"): compliance_todos.append("CPNI Certification") if order["include_calea"] and not order.get("calea_completed_at"): compliance_todos.append("CALEA SSI Plan") if order["include_bdc"] and not order.get("bdc_completed_at"): compliance_todos.append("BDC Filing") if compliance_todos: self._create_todo( order_number, f"FCC Carrier Registration {order_number}\n\n" f"Step 6: Compliance filings needed:\n" + "\n".join(f" - {t}" for t in compliance_todos) + f"\n\nEntity: {order.get('entity_legal_name', '?')}\n" f"FRN: {order.get('frn_obtained') or order.get('frn', '')}\n" f"Filer ID: {order.get('filer_id_obtained') or order.get('filer_id_499', '')}\n\n" f"Process each filing, then update the corresponding *_completed_at timestamp.", ) # ── Step 7: Optional add-ons ────────────────────────────────────── if order["include_stir_shaken"] and not order.get("stir_shaken_completed_at"): self._create_todo( order_number, f"FCC Carrier Registration {order_number}\n\n" f"Step 7a: STIR/SHAKEN Implementation\n" f"Entity: {order.get('entity_legal_name', '?')}\n" f"FRN: {order.get('frn_obtained') or order.get('frn', '')}", ) if order["include_ocn"] and not order.get("ocn_completed_at"): self._create_todo( order_number, f"FCC Carrier Registration {order_number}\n\n" f"Step 7b: NECA OCN Registration\n" f"Entity: {order.get('entity_legal_name', '?')}\n" f"FRN: {order.get('frn_obtained') or order.get('frn', '')}", ) # ── Step 8: Final review ────────────────────────────────────────── all_done = ( (not order["include_rmd"] or order.get("rmd_completed_at")) and (not order["include_cpni"] or order.get("cpni_completed_at")) and (not order["include_calea"] or order.get("calea_completed_at")) and (not order["include_bdc"] or order.get("bdc_completed_at")) and (not order["include_stir_shaken"] or order.get("stir_shaken_completed_at")) and (not order["include_ocn"] or order.get("ocn_completed_at")) ) if all_done: self._update_status(order_number, "review") self._create_todo( order_number, f"FCC Carrier Registration {order_number} — ALL STEPS COMPLETE\n\n" f"Entity: {order.get('entity_legal_name', '?')}\n" f"FRN: {order.get('frn_obtained') or order.get('frn', '')}\n" f"Filer ID: {order.get('filer_id_obtained') or order.get('filer_id_499', '')}\n\n" f"Review all filings and send the client a completion summary.\n" f"Then mark as delivered:\n" f" UPDATE fcc_carrier_registrations SET status = 'delivered' " f"WHERE order_number = '{order_number}'", priority="High", ) # Send client notification self._send_status_email(order, "Your FCC carrier registration is nearing completion. Our team is doing a final review.") return generated # ── Helpers ─────────────────────────────────────────────────────────── def _update_status(self, order_number: str, status: str) -> None: try: conn = psycopg2.connect(DATABASE_URL) with conn.cursor() as cur: cur.execute( "UPDATE fcc_carrier_registrations SET status = %s WHERE order_number = %s", (status, order_number), ) conn.commit() conn.close() except Exception as exc: logger.warning("Could not update status for %s: %s", order_number, exc) def _update_step(self, order_number: str, column: str) -> None: try: conn = psycopg2.connect(DATABASE_URL) with conn.cursor() as cur: cur.execute( f"UPDATE fcc_carrier_registrations SET {column} = NOW() WHERE order_number = %s", (order_number,), ) conn.commit() conn.close() except Exception as exc: logger.warning("Could not update step %s for %s: %s", column, order_number, exc) def _create_todo(self, order_number: str, description: str, priority: str = "Medium") -> None: try: from scripts.workers.erpnext_client import ERPNextClient ERPNextClient().create_resource("ToDo", { "description": f"[fcc-carrier-reg] {order_number}\n\n{description}", "priority": priority, "role": "Accounting Advisor", }) except Exception as exc: logger.error("Could not create admin ToDo: %s", exc) def _send_status_email(self, order: dict, message: str) -> None: try: import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart email = order.get("customer_email", "") name = order.get("customer_name", "") if not email: return first = name.split(" ")[0] if name else "there" subject = f"FCC Carrier Registration Update — {order.get('order_number', '')}" body = ( f"
Hi {first},
" f"{message}
" f"Entity: {order.get('entity_legal_name', '')}
" f"Order: {order.get('order_number', '')}
" f"Performance West Inc. | 1-888-411-0383
" ) msg = MIMEMultipart("alternative") msg["Subject"] = subject msg["From"] = os.environ.get("SMTP_FROM", "Performance West