new-site/scripts/workers/services/state_puc_filing.py
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

221 lines
8.8 KiB
Python

"""State PUC/PSC Registration handler.
Processes per-state PUC registrations for VoIP, broadband, and CLEC
providers. Fans out one `state_puc_registrations` row per selected
state and creates admin todos for manual filing.
States without VoIP registration requirements are skipped with a note.
States requiring a surety bond start at 'bond_pending' status.
"""
from __future__ import annotations
import logging
import os
from typing import Optional
import psycopg2
from .base_handler import BaseServiceHandler
logger = logging.getLogger(__name__)
DATABASE_URL = os.environ.get("DATABASE_URL", "")
# Our service fee per state
PUC_SERVICE_FEE_CENTS = 39900 # $399/state
class StatePucFilingHandler(BaseServiceHandler):
SERVICE_SLUG = "state-puc"
SERVICE_NAME = "State PUC/PSC Registration"
REQUIRES_LLM = False
async def process(self, order_data: dict) -> list[str]:
order_number = order_data["name"]
entity = order_data.get("entity", {}) or {}
intake = order_data.get("intake_data", {}) or {}
# Target states from intake
target_states = intake.get("target_states") or []
if isinstance(target_states, str):
target_states = [s.strip().upper() for s in target_states.split(",") if s.strip()]
else:
target_states = [str(s).strip().upper() for s in target_states]
if not target_states:
self._create_admin_todo(
order_number,
f"{self.SERVICE_NAME}: no target states specified in intake_data. "
"Admin should add target_states and re-dispatch.",
)
return []
entity_name = (
intake.get("entity_legal_name")
or entity.get("legal_name")
or ""
)
if not entity_name:
self._create_admin_todo(
order_number,
f"{self.SERVICE_NAME}: missing entity legal name. "
"Admin should set entity_legal_name in intake_data.",
)
return []
reg_type = intake.get("registration_type", "voip")
# Normalize: empty string → None (DB CHECK constraint rejects "")
provider_type = intake.get("provider_type") or None
frn = intake.get("frn") or entity.get("frn")
conn = psycopg2.connect(DATABASE_URL)
try:
with conn.cursor() as cur:
for state_code in target_states:
# Look up state PUC requirements
cur.execute(
"""SELECT voip_registration_required, voip_registration_fee_cents,
voip_bond_required, voip_bond_amount_cents,
broadband_registration_required, broadband_registration_fee_cents,
clec_certification_required, clec_certification_fee_cents,
clec_bond_required, clec_bond_amount_cents,
agency_name
FROM state_puc_requirements
WHERE state_code = %s""",
(state_code,),
)
req = cur.fetchone()
if not req:
logger.warning("StatePucHandler: no PUC data for %s", state_code)
continue
(voip_req, voip_fee, voip_bond_req, voip_bond_amt,
bb_req, bb_fee, clec_req, clec_fee, clec_bond_req, clec_bond_amt,
agency_name) = req
# Calculate fees based on registration type
state_fee = 0
bond_amount = 0
required = False
if reg_type in ("voip", "bundle"):
if voip_req:
required = True
state_fee += voip_fee
if voip_bond_req:
bond_amount = max(bond_amount, voip_bond_amt)
if reg_type in ("broadband", "bundle"):
if bb_req:
required = True
state_fee += bb_fee
if reg_type in ("clec", "bundle"):
if clec_req:
required = True
state_fee += clec_fee
if clec_bond_req:
bond_amount = max(bond_amount, clec_bond_amt)
if not required:
logger.info(
"StatePucHandler: %s does not require %s registration — skipping",
state_code, reg_type,
)
continue
# Check for existing active registration
cur.execute(
"""SELECT id FROM state_puc_registrations
WHERE order_number = %s AND state_code = %s
AND status NOT IN ('cancelled','rejected')
LIMIT 1""",
(order_number, state_code),
)
if cur.fetchone():
logger.info(
"StatePucHandler: %s already has %s registration — skipping",
order_number, state_code,
)
continue
co_id = order_data.get("compliance_order_id") or order_data.get("id")
# Initial status: bond_pending if bond required, else filing
initial_status = "bond_pending" if bond_amount > 0 else "filing"
cur.execute(
"""INSERT INTO state_puc_registrations (
compliance_order_id, order_number,
telecom_entity_id, state_code,
registration_type, entity_legal_name, frn,
provider_type,
status,
state_fee_cents, bond_amount_cents,
service_fee_cents, retail_total_cents
) VALUES (
%s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s
)""",
(
co_id, order_number,
entity.get("id"), state_code,
reg_type, entity_name, frn,
provider_type,
initial_status,
state_fee, bond_amount,
PUC_SERVICE_FEE_CENTS,
PUC_SERVICE_FEE_CENTS + state_fee,
),
)
# Create admin todo
bond_note = (
f" BOND REQUIRED: ${bond_amount / 100:,.0f} surety bond. "
"Coordinate with surety provider before filing."
if bond_amount > 0
else ""
)
self._create_admin_todo(
order_number,
f"PUC registration in {state_code} ({agency_name}): "
f"{entity_name}{reg_type} registration. "
f"State fee: ${state_fee / 100:,.0f}.{bond_note} "
f"Provider type: {provider_type or 'not specified'}. "
f"FRN: {frn or 'N/A'}.",
)
conn.commit()
logger.info(
"StatePucHandler: created registration(s) for %s across %d state(s)",
order_number, len(target_states),
)
except Exception as exc:
logger.exception(
"StatePucHandler: DB error for %s: %s", order_number, exc,
)
conn.rollback()
self._create_admin_todo(
order_number,
f"{self.SERVICE_NAME}: failed to create registration rows — {exc}",
)
return []
finally:
conn.close()
return []
def _create_admin_todo(self, order_number: str, description: str) -> None:
try:
from scripts.workers.erpnext_client import ERPNextClient
ERPNextClient().create_resource(
"ToDo",
{
"description": (
f"[{self.SERVICE_SLUG}] {order_number}\n\n{description}"
),
"priority": "Medium",
"role": "Accounting Advisor",
},
)
except Exception as exc:
logger.error("Could not create admin ToDo: %s", exc)