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>
210 lines
8.6 KiB
Python
210 lines
8.6 KiB
Python
"""D.C. Registered Agent service handler.
|
|
|
|
Most telecom carriers need a D.C. registered agent because the FCC
|
|
requires process-of-service in the District. We wholesale this through
|
|
Northwest Registered Agent (same pattern as state-level RA services per
|
|
``docs/go-live-todo.md:96``). Northwest's RA portal is login-only and
|
|
requires manual order entry; rather than scrape it, this handler creates
|
|
a well-formed admin ToDo with all the fields the Accounting Advisor
|
|
needs to place the wholesale order in under two minutes.
|
|
|
|
Once the Accounting Advisor completes the Northwest order, they record
|
|
the D.C. agent address on the telecom_entity's ``carrier_metadata``
|
|
field under ``dc_agent_address`` so subsequent compliance checkups read
|
|
green.
|
|
|
|
Flow:
|
|
1. Generate a simple acceptance-of-service PDF letter (for the customer's
|
|
records) acknowledging that Performance West has engaged Northwest
|
|
as their D.C. RA.
|
|
2. Create the admin ToDo with the wholesale order fields filled in.
|
|
3. Return the acceptance letter.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
from datetime import datetime
|
|
|
|
from .base_handler import BaseServiceHandler
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# Northwest Registered Agent's D.C. Registered Agent address — used on
|
|
# FCC Form 499-A Lines 209-213. This is the wholesale address we place
|
|
# orders against; confirmed via the 2025 Adaptive Communications 499-A
|
|
# filing in docs/examplefilings/. Stable across all carriers we've filed.
|
|
NWRA_DC_AGENT = {
|
|
"company": "Northwest Registered Agent Service Inc.",
|
|
"street": "1717 N Street NW STE 1",
|
|
"city": "Washington",
|
|
"state": "DC",
|
|
"zip": "20036",
|
|
"phone": "509-768-2249",
|
|
"email": "support@northwestregisteredagent.com",
|
|
}
|
|
|
|
|
|
class DCAgentHandler(BaseServiceHandler):
|
|
SERVICE_SLUG = "dc-agent"
|
|
SERVICE_NAME = "D.C. Registered Agent (Annual)"
|
|
REQUIRES_LLM = False
|
|
|
|
async def process(self, order_data: dict) -> list[str]:
|
|
work_dir = self._make_work_dir()
|
|
order_number = order_data["name"]
|
|
entity = order_data.get("entity", {})
|
|
entity_id = entity.get("id")
|
|
|
|
generated: list[str] = []
|
|
acceptance = self._write_acceptance_letter(order_number, entity, work_dir)
|
|
if acceptance:
|
|
generated.append(acceptance)
|
|
try:
|
|
generated.append(self._convert_to_pdf(acceptance))
|
|
except Exception as exc:
|
|
logger.warning("DC agent acceptance PDF conversion failed: %s", exc)
|
|
|
|
# Persist the NWRA D.C. Agent address on the telecom_entity so the
|
|
# Form 499-A checklist generator can read it for Lines 209-213
|
|
# without re-computing. Columns default to NWRA values via
|
|
# migration 048, so a new order does not need this; but an older
|
|
# entity created before migration 048 will still get them written.
|
|
if entity_id:
|
|
self._persist_dc_agent(entity_id)
|
|
|
|
self._create_wholesale_order_todo(order_number, entity)
|
|
return generated
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Persist NWRA D.C. agent address on the telecom_entity
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def _persist_dc_agent(self, entity_id: int) -> None:
|
|
try:
|
|
import psycopg2
|
|
|
|
conn = psycopg2.connect(os.environ.get("DATABASE_URL", ""))
|
|
with conn.cursor() as cur:
|
|
cur.execute(
|
|
"""
|
|
UPDATE telecom_entities SET
|
|
dc_agent_company = %s,
|
|
dc_agent_street = %s,
|
|
dc_agent_city = %s,
|
|
dc_agent_state = %s,
|
|
dc_agent_zip = %s,
|
|
dc_agent_phone = %s,
|
|
dc_agent_email = %s
|
|
WHERE id = %s
|
|
""",
|
|
(
|
|
NWRA_DC_AGENT["company"],
|
|
NWRA_DC_AGENT["street"],
|
|
NWRA_DC_AGENT["city"],
|
|
NWRA_DC_AGENT["state"],
|
|
NWRA_DC_AGENT["zip"],
|
|
NWRA_DC_AGENT["phone"],
|
|
NWRA_DC_AGENT["email"],
|
|
entity_id,
|
|
),
|
|
)
|
|
conn.commit()
|
|
conn.close()
|
|
logger.info(
|
|
"DCAgentHandler: persisted NWRA D.C. agent on entity %s",
|
|
entity_id,
|
|
)
|
|
except Exception as exc:
|
|
logger.warning(
|
|
"DCAgentHandler: could not persist D.C. agent on entity %s: %s",
|
|
entity_id, exc,
|
|
)
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Acceptance letter (plain DOCX — no template)
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def _write_acceptance_letter(
|
|
self, order_number: str, entity: dict, work_dir: str
|
|
) -> str:
|
|
from docx import Document
|
|
|
|
date_str = datetime.now().strftime("%B %d, %Y")
|
|
entity_name = entity.get("legal_name", "")
|
|
dba = entity.get("dba_name", "")
|
|
display = f"{entity_name} ({dba})" if dba else entity_name
|
|
|
|
doc = Document()
|
|
doc.add_heading("D.C. Registered Agent — Acceptance of Engagement", level=1)
|
|
doc.add_paragraph(f"Date: {date_str}")
|
|
doc.add_paragraph(f"Order: {order_number}")
|
|
doc.add_paragraph(f"Client: {display}")
|
|
doc.add_paragraph(f"FRN: {entity.get('frn', 'N/A')}")
|
|
doc.add_paragraph("")
|
|
doc.add_paragraph(
|
|
"This letter confirms that Performance West Inc. has engaged "
|
|
"Northwest Registered Agent Service Inc. as D.C. Registered "
|
|
"Agent on behalf of the client identified above. Northwest "
|
|
"maintains a registered office in the District of Columbia "
|
|
"and will receive service of process on the client's behalf "
|
|
"during the engagement period (one year from the order date)."
|
|
)
|
|
doc.add_paragraph(
|
|
"D.C. registered agent address (use on FCC Form 499-A "
|
|
"Lines 209\u2013213):"
|
|
)
|
|
doc.add_paragraph(
|
|
f" {NWRA_DC_AGENT['company']}\n"
|
|
f" {NWRA_DC_AGENT['street']}\n"
|
|
f" {NWRA_DC_AGENT['city']}, {NWRA_DC_AGENT['state']} {NWRA_DC_AGENT['zip']}\n"
|
|
f" Tel: {NWRA_DC_AGENT['phone']}\n"
|
|
f" Email: {NWRA_DC_AGENT['email']}"
|
|
)
|
|
doc.add_paragraph("")
|
|
doc.add_paragraph("Performance West Inc.")
|
|
doc.add_paragraph("Regulatory Compliance Team")
|
|
|
|
out = os.path.join(
|
|
work_dir, f"dc_agent_acceptance_{order_number}.docx"
|
|
)
|
|
doc.save(out)
|
|
return out
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Admin ToDo for wholesale order placement
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def _create_wholesale_order_todo(self, order_number: str, entity: dict) -> None:
|
|
try:
|
|
from scripts.workers.erpnext_client import ERPNextClient
|
|
|
|
description = (
|
|
f"[{self.SERVICE_SLUG}] {order_number}\n\n"
|
|
f"Place a D.C. Registered Agent wholesale order with Northwest "
|
|
f"Registered Agent for this client. Once complete, record the "
|
|
f"assigned D.C. agent address on the telecom entity's "
|
|
f"carrier_metadata.dc_agent_address and send the customer a "
|
|
f"follow-up email with the address.\n\n"
|
|
f"Wholesale order fields:\n"
|
|
f" Entity legal name: {entity.get('legal_name', '')}\n"
|
|
f" DBA: {entity.get('dba_name', '')}\n"
|
|
f" FRN: {entity.get('frn', 'N/A')}\n"
|
|
f" Contact name: {entity.get('contact_name', '')}\n"
|
|
f" Contact email: {entity.get('contact_email', '')}\n"
|
|
f" Contact phone: {entity.get('contact_phone', '')}\n"
|
|
f" Carrier category: {entity.get('carrier_category', '')}\n\n"
|
|
f"Billing: use the Relay virtual debit card (SID-0002, filing fees)."
|
|
)
|
|
ERPNextClient().create_resource(
|
|
"ToDo",
|
|
{
|
|
"description": description,
|
|
"priority": "Medium",
|
|
"role": "Accounting Advisor",
|
|
},
|
|
)
|
|
except Exception as exc:
|
|
logger.error("Could not create DC agent wholesale ToDo: %s", exc)
|