new-site/scripts/workers/services/form_499q.py
justin 0fc318cb38 Add 499-Q intake page, 499-Q handler, and 499-A discontinuance handler
499-Q Quarterly Filing:
- Intake page at /order/fcc-499q with simplified revenue form
  (4 fields: carrier's carrier inter/intra, end-user inter/intra)
- Zero-revenue confirmation checkbox
- Handler creates admin todo with filing details + sends client email
- Registers as fcc-499q in SERVICE_HANDLERS

499-A Discontinuance:
- Handler creates admin todo with step-by-step USAC instructions
  (file zero-revenue 499-A, request account closure, confirm CPNI/RMD)
- Sends client confirmation email explaining the process
- Compliance checker CTA: when user selects "No — cancel registration"
  in the 499-A toggle, shows discontinuance option ($299) instead of
  standard filing
- Order page maps form_499a_disc to fcc-499a-discontinuance slug

Compliance checker intelligence:
- 499-A toggle tracks _499aVariant (null/zero/discontinuance)
- CTA adapts: revenue=standard 499-A, zero=zero-revenue, cancel=discontinuance
- Reset clears variant flag

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-03 02:34:18 -05:00

130 lines
5.4 KiB
Python

"""FCC Form 499-Q Quarterly Filing Handler.
Simplified filing: the client submits quarterly revenue via the intake page,
and this handler files it at USAC E-File. Revenue calculations are minimal
compared to the 499-A — just four revenue buckets projected for the quarter.
The 499-Q determines quarterly USF contribution payments.
"""
from __future__ import annotations
import logging
import os
from datetime import datetime
from .base_handler import BaseComplianceHandler
logger = logging.getLogger("workers.services.form_499q")
class Form499QHandler(BaseComplianceHandler):
SERVICE_SLUG = "fcc-499q"
SERVICE_NAME = "FCC Form 499-Q Quarterly Filing"
async def process(self, order_data: dict) -> dict | None:
order_number = order_data.get("order_number", "")
entity = order_data.get("entity", {})
intake_data = order_data.get("intake_data", {})
if not intake_data.get("intake_completed"):
logger.info(
"Form499QHandler: %s intake not completed — waiting for client",
order_number,
)
self._create_admin_todo(
order_number,
f"499-Q {intake_data.get('quarter', '?')} for "
f"{entity.get('legal_name', '?')} — awaiting client intake. "
f"Due {intake_data.get('due_date', '?')}.",
)
return None
quarter = intake_data.get("quarter", "?")
revenue = intake_data.get("revenue", {})
filer_id = intake_data.get("filer_id_499") or entity.get("filer_id_499", "")
frn = intake_data.get("frn") or entity.get("frn", "")
logger.info(
"Form499QHandler: processing %s %s for %s (total: $%.2f)",
order_number, quarter,
entity.get("legal_name", "?"),
revenue.get("total", 0),
)
# Create admin todo with filing instructions
# (Full Playwright automation for USAC E-File 499-Q TBD)
self._create_admin_todo(
order_number,
f"FILE 499-Q {quarter} for {entity.get('legal_name', '?')} "
f"(FRN: {frn}, Filer ID: {filer_id})\n\n"
f"Revenue:\n"
f" Carrier's Carrier Interstate: ${revenue.get('carriers_carrier_interstate', 0):.2f}\n"
f" Carrier's Carrier Intrastate: ${revenue.get('carriers_carrier_intrastate', 0):.2f}\n"
f" End-User Interstate: ${revenue.get('end_user_interstate', 0):.2f}\n"
f" End-User Intrastate: ${revenue.get('end_user_intrastate', 0):.2f}\n"
f" Total: ${revenue.get('total', 0):.2f}\n\n"
f"Due: {intake_data.get('due_date', '?')}\n"
f"Parent 499-A: {intake_data.get('parent_499a_order', '?')}\n\n"
f"File at: https://forms.universalservice.org/",
)
# Send confirmation email to client
self._send_confirmation_email(
to=entity.get("contact_email") or order_data.get("customer_email", ""),
entity_name=entity.get("legal_name", ""),
order_number=order_number,
quarter=quarter,
due_date=intake_data.get("due_date", ""),
)
return {"status": "submitted_for_filing"}
def _send_confirmation_email(
self, to: str, entity_name: str, order_number: str,
quarter: str, due_date: str,
) -> None:
if not to:
return
try:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
subject = f"499-Q {quarter} Filing Received — {entity_name}"
html = f"""
<div style="font-family:Inter,sans-serif;max-width:600px;margin:0 auto;color:#1f2937">
<div style="background:#1e3a5f;padding:16px 24px;border-radius:8px 8px 0 0">
<h2 style="color:#fff;margin:0;font-size:16px">Form 499-Q {quarter} — Filing Received</h2>
</div>
<div style="padding:24px;border:1px solid #e5e7eb;border-top:none;border-radius:0 0 8px 8px">
<p>Your FCC Form 499-Q quarterly revenue data for <strong>{entity_name}</strong>
({quarter}, due {due_date}) has been received.</p>
<p>We'll file this with USAC E-File and send you a confirmation with your
filing reference number once complete.</p>
<p style="font-size:13px;color:#6b7280;margin-top:1rem">
Order: {order_number}<br>
Questions? Reply to this email or contact
<a href="mailto:ops@performancewest.net">ops@performancewest.net</a>.
</p>
</div>
</div>
"""
msg = MIMEMultipart("alternative")
msg["From"] = os.environ.get("SMTP_FROM", "Performance West <noreply@performancewest.net>")
msg["To"] = to
msg["Subject"] = subject
msg.attach(MIMEText(html, "html"))
with smtplib.SMTP(
os.environ.get("SMTP_HOST", "co.carrierone.com"),
int(os.environ.get("SMTP_PORT", "587")),
timeout=30,
) as s:
s.starttls()
s.login(
os.environ.get("SMTP_USER", ""),
os.environ.get("SMTP_PASS", ""),
)
s.send_message(msg)
except Exception as exc:
logger.warning("499-Q confirmation email failed: %s", exc)