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>
88 lines
3 KiB
Python
88 lines
3 KiB
Python
"""FCC Full Compliance Bundle.
|
|
|
|
Composes the four individual remediation handlers in sequence:
|
|
|
|
1. RMD Registration / Recertification
|
|
2. CPNI Annual Certification
|
|
3. STIR/SHAKEN Implementation Assistance (which itself runs the RMD
|
|
flow with the updated posture, plus opens the STI-CA ToDo)
|
|
4. FCC Form 499-A + 499-Q Bundle
|
|
|
|
Each sub-handler is idempotent (see
|
|
``scripts/workers/services/telecom/filing_state.py``), so running this
|
|
bundle when some filings are already current only produces net-new
|
|
submissions.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from .base_handler import BaseServiceHandler
|
|
from .rmd_filing import RMDFilingHandler
|
|
from .cpni_certification import CPNIFilingHandler
|
|
from .stir_shaken import StirShakenHandler
|
|
from .form_499a import Form499ABundleHandler
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class FullComplianceHandler(BaseServiceHandler):
|
|
SERVICE_SLUG = "fcc-full-compliance"
|
|
SERVICE_NAME = "FCC Full Compliance Bundle"
|
|
REQUIRES_LLM = False
|
|
|
|
# In run order. Each sub-handler returns its own generated files; we
|
|
# concatenate them.
|
|
SUB_HANDLERS = (
|
|
RMDFilingHandler,
|
|
CPNIFilingHandler,
|
|
StirShakenHandler,
|
|
Form499ABundleHandler,
|
|
)
|
|
|
|
async def process(self, order_data: dict) -> list[str]:
|
|
generated: list[str] = []
|
|
order_number = order_data.get("name", "")
|
|
|
|
for cls in self.SUB_HANDLERS:
|
|
sub = cls()
|
|
try:
|
|
files = await sub.process(order_data)
|
|
if files:
|
|
generated.extend(files)
|
|
logger.info(
|
|
"FullComplianceHandler: %s produced %d file(s) for %s",
|
|
cls.__name__, len(files or []), order_number,
|
|
)
|
|
except Exception as exc:
|
|
logger.exception(
|
|
"FullComplianceHandler: %s failed for %s: %s",
|
|
cls.__name__, order_number, exc,
|
|
)
|
|
# Record the failure on an admin ToDo but keep going —
|
|
# a failure in one sub-handler should not block the rest.
|
|
self._record_sub_failure(order_number, cls.__name__, exc)
|
|
|
|
return generated
|
|
|
|
def _record_sub_failure(
|
|
self, order_number: str, sub_name: str, exc: Exception
|
|
) -> None:
|
|
try:
|
|
from scripts.workers.erpnext_client import ERPNextClient
|
|
|
|
ERPNextClient().create_resource(
|
|
"ToDo",
|
|
{
|
|
"description": (
|
|
f"[{self.SERVICE_SLUG}] {order_number}\n\n"
|
|
f"Sub-handler {sub_name} failed: {exc}. The other sub-handlers "
|
|
f"ran to completion; this one needs manual follow-up."
|
|
),
|
|
"priority": "High",
|
|
"role": "Accounting Advisor",
|
|
},
|
|
)
|
|
except Exception as erp_exc:
|
|
logger.error("Could not create sub-failure ToDo: %s", erp_exc)
|