Wire CPNI, CALEA, 499-A engagement, and discontinuance to generic eSign

Each handler now pauses for officer signature via the eSign portal
before filing/submitting. esign_completed callback re-dispatches
through standard pipeline with client_approved=true.

- CPNI: officer signs certification before ECFS submission (perjury)
- CALEA SSI: officer signs plan before delivery
- 499-A engagement: replaced custom JWT/email with request_esign()
- Discontinuance: officer signs deactivation letter before USAC email
- job_server: injects client_approved + order_number into order_data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
justin 2026-05-04 10:53:59 -05:00
parent 40844b2aff
commit ff47f47a37
5 changed files with 161 additions and 74 deletions

View file

@ -1136,6 +1136,19 @@ def handle_process_compliance_service(payload: dict) -> dict:
order.get("entity", {}).get("frn"), exc)
handler = handler_cls()
# Ensure order_number is always available (some handlers use it instead of name)
if order_number:
order["order_number"] = order_number
# Inject eSign approval flags from payload (set by handle_esign_completed)
if payload.get("client_approved"):
order["client_approved"] = True
if payload.get("esign_document_type"):
order["esign_document_type"] = payload["esign_document_type"]
if payload.get("esign_signer_email"):
order["esign_signer_email"] = payload["esign_signer_email"]
# Final entity check before dispatch
ent = order.get("entity", {})
LOG.info(
@ -1562,9 +1575,9 @@ def handle_esign_completed(payload: dict) -> dict:
Called by portal-esign-generic.ts after a client signs any document.
Payload: { order_number, document_type, esign_record_id, signer_email }
Looks up the compliance order for this order_number and re-dispatches
the service handler with client_approved=true so it continues past
the signing checkpoint.
Re-dispatches through the standard handle_process_compliance_service
path with client_approved=true injected into the payload so the handler
skips past its signing checkpoint on the second run.
"""
order_number = payload.get("order_number", "")
document_type = payload.get("document_type", "")
@ -1578,7 +1591,7 @@ def handle_esign_completed(payload: dict) -> dict:
conn = psycopg2.connect(os.environ.get("DATABASE_URL", ""))
with conn.cursor() as cur:
cur.execute(
"SELECT service_slug FROM compliance_orders WHERE order_number = %s",
"SELECT service_slug, erpnext_sales_order FROM compliance_orders WHERE order_number = %s",
(order_number,),
)
row = cur.fetchone()
@ -1589,22 +1602,20 @@ def handle_esign_completed(payload: dict) -> dict:
return {"warning": f"No compliance order for {order_number}"}
service_slug = row[0]
erpnext_so = row[1] or order_number
# Re-dispatch the service handler with approval flag
from scripts.workers.services import SERVICE_HANDLERS
handler_cls = SERVICE_HANDLERS.get(service_slug)
if handler_cls:
LOG.info("[esign_completed] Re-dispatching %s for %s", service_slug, order_number)
handler = handler_cls()
handler.process(order_number, {
"client_approved": True,
"esign_document_type": document_type,
"esign_signer_email": payload.get("signer_email", ""),
})
else:
LOG.warning("[esign_completed] No handler for slug=%s", service_slug)
LOG.info("[esign_completed] Re-dispatching %s for %s via standard pipeline", service_slug, order_number)
return {"success": True, "order_number": order_number, "document_type": document_type}
# Re-dispatch through the standard compliance service handler.
# client_approved is injected and will be merged into order_data.
return handle_process_compliance_service({
"order_name": erpnext_so,
"order_number": order_number,
"service_slug": service_slug,
"client_approved": True,
"esign_document_type": document_type,
"esign_signer_email": payload.get("signer_email", ""),
})
except Exception as exc:
LOG.error("[esign_completed] Error for %s: %s", order_number, exc)
return {"error": str(exc)}

View file

@ -167,6 +167,46 @@ class CALEASSIHandler(BaseServiceHandler):
except Exception as exc:
logger.warning("CALEA SSI PDF conversion failed: %s", exc)
# ── Client eSign gate ──────────────────────────────────────────
# The CALEA SSI plan requires officer signature before delivery.
client_approved = order_data.get("client_approved", False)
if not client_approved and generated:
from scripts.document_gen import MinioStorage
storage = MinioStorage()
pdf_minio_key = ""
for path in generated:
if path.endswith(".pdf"):
remote = f"compliance/{order_number}/{os.path.basename(path)}"
try:
storage.upload_file(path, remote)
pdf_minio_key = remote
except Exception as exc:
logger.warning("MinIO upload failed for %s: %s", path, exc)
break
try:
import psycopg2
conn = psycopg2.connect(os.environ.get("DATABASE_URL", ""))
from scripts.workers.services.telecom.esign_helper import request_esign
request_esign(
conn=conn,
order_number=order_number,
document_type="calea",
document_title="CALEA System Security & Integrity Plan",
entity_name=entity.get("legal_name", ""),
customer_email=order_data.get("customer_email") or entity.get("contact_email", ""),
customer_name=order_data.get("customer_name") or entity.get("contact_name", ""),
document_minio_key=pdf_minio_key,
requires_perjury=False,
metadata={"frn": entity.get("frn", "")},
)
conn.close()
except Exception as exc:
logger.warning("Could not create CALEA eSign record: %s", exc)
logger.info("CALEASSIHandler: paused for client eSign — order %s", order_number)
return generated
# Persist + schedule annual review
if entity_id:
self._persist_calea_state(

View file

@ -188,7 +188,50 @@ class CPNIFilingHandler(BaseServiceHandler):
)
return generated
# ── 2a. Auto-filing toggle ──────────────────────────────────────
# ── 2a. Client eSign gate ──────────────────────────────────────
# Officer must sign the CPNI certification before FCC submission
# (47 CFR § 64.2009(e) requires officer attestation).
client_approved = order_data.get("client_approved", False)
if not client_approved:
# Upload cert PDF to MinIO for the signing portal preview
from scripts.document_gen import MinioStorage
storage = MinioStorage()
pdf_minio_key = ""
for path in generated:
if path.endswith(".pdf") and "certification" in path.lower():
remote = f"compliance/{order_number}/{os.path.basename(path)}"
try:
storage.upload_file(path, remote)
pdf_minio_key = remote
except Exception as exc:
logger.warning("MinIO upload failed for %s: %s", path, exc)
break
# Create eSign record + send signing email
try:
import psycopg2
conn = psycopg2.connect(os.environ.get("DATABASE_URL", ""))
from scripts.workers.services.telecom.esign_helper import request_esign
request_esign(
conn=conn,
order_number=order_number,
document_type="cpni",
document_title="CPNI Annual Certification",
entity_name=entity.get("legal_name", ""),
customer_email=order_data.get("customer_email") or entity.get("contact_email", ""),
customer_name=order_data.get("customer_name") or entity.get("contact_name", ""),
document_minio_key=pdf_minio_key,
requires_perjury=True,
metadata={"frn": entity.get("frn", ""), "docket": CPNI_DOCKET},
)
conn.close()
except Exception as exc:
logger.warning("Could not create CPNI eSign record: %s", exc)
logger.info("CPNIFilingHandler: paused for client eSign — order %s", order_number)
return generated
# ── 2b. Auto-filing toggle ──────────────────────────────────────
decision = check_auto_filing(order_data)
if not decision.may_submit:
logger.info(

View file

@ -179,7 +179,7 @@ class Form499AHandler(BaseServiceHandler):
or (multi_year and len(multi_year) >= 2)
)
if needs_engagement:
esign_signed = order_data.get("engagement_esign_signed_at")
esign_signed = order_data.get("engagement_esign_signed_at") or order_data.get("client_approved")
if not esign_signed:
# Check if we already generated the letter (avoid re-sending on re-dispatch)
already_required = order_data.get("engagement_esign_required")
@ -1537,72 +1537,37 @@ class Form499AHandler(BaseServiceHandler):
cur.execute(
"""UPDATE compliance_orders
SET engagement_esign_required = TRUE,
engagement_letter_minio_key = %s,
payment_status = 'pending_esign'
engagement_letter_minio_key = %s
WHERE order_number = %s""",
(minio_key, order_number),
)
conn.commit()
cur.close()
conn.close()
except Exception as exc:
logger.warning("Could not update engagement status: %s", exc)
conn = None
# Email client the engagement signing link
if customer_email:
# Create eSign record + send signing email via generic portal
if customer_email and conn:
try:
try:
import jwt as pyjwt
except ImportError:
import PyJWT as pyjwt
secret = os.environ.get("CUSTOMER_JWT_SECRET", "changeme")
domain = os.environ.get("DOMAIN", "performancewest.net")
token = pyjwt.encode(
{"order_id": order_number, "order_type": "compliance", "email": customer_email},
secret, algorithm="HS256",
)
sign_url = f"https://{domain}/portal/engagement-sign?token={token}"
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
first_name = customer_name.split(" ")[0] if customer_name else "there"
from scripts.workers.services.telecom.esign_helper import request_esign
years_str = ", ".join(str(y) for y in multi_year) if multi_year else "current year"
subject = f"Engagement Letter — 499-A Revenue Audit for {entity.get('legal_name', order_number)}"
body = (
f"<h2>Engagement Letter Ready for Signature</h2>"
f"<p>Hi {first_name},</p>"
f"<p>Before we begin your FCC Form 499-A revenue audit and revised filing "
f"for calendar year(s) <strong>{years_str}</strong>, we need your signature "
f"on the engagement letter.</p>"
f"<p>Please review and sign the letter by clicking below:</p>"
f"<p><a href='{sign_url}' style='display:inline-block;background:#1e3a5f;color:#fff;"
f"padding:12px 28px;border-radius:6px;text-decoration:none;font-weight:600;'>"
f"Review & Sign Engagement Letter</a></p>"
f"<p style='font-size:12px;color:#9ca3af;'>Order: {order_number}</p>"
f"<p style='font-size:11px;color:#9ca3af;margin-top:16px;'>"
f"Performance West Inc. | 525 Randall Ave Ste 100-1195, Cheyenne, WY 82001 | 1-888-411-0383</p>"
request_esign(
conn=conn,
order_number=order_number,
document_type="499a-engagement",
document_title=f"Engagement Letter — 499-A Filing ({years_str})",
entity_name=entity.get("legal_name") or intake.get("entity_legal_name", ""),
customer_email=customer_email,
customer_name=customer_name,
document_minio_key=minio_key,
requires_perjury=False,
metadata={"frn": entity.get("frn", ""), "filing_years": multi_year},
)
msg = MIMEMultipart("alternative")
msg["Subject"] = subject
msg["From"] = os.environ.get("SMTP_FROM", "Performance West <noreply@performancewest.net>")
msg["To"] = customer_email
msg.attach(MIMEText(body, "html"))
smtp_host = os.environ.get("SMTP_HOST", "co.carrierone.com")
smtp_port = int(os.environ.get("SMTP_PORT", "587"))
smtp_user = os.environ.get("SMTP_USER", "")
smtp_pass = os.environ.get("SMTP_PASS", "")
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls()
if smtp_user and smtp_pass:
server.login(smtp_user, smtp_pass)
server.send_message(msg)
logger.info("Engagement letter email sent to %s for %s", customer_email, order_number)
except Exception as exc:
logger.warning("Could not send engagement email for %s: %s", order_number, exc)
logger.warning("Could not create engagement eSign record for %s: %s", order_number, exc)
finally:
conn.close()
# Create admin todo
try:

View file

@ -98,6 +98,34 @@ class Form499ADiscontinuanceHandler(BaseServiceHandler):
except Exception as exc:
logger.warning("Discontinuance letter generation failed: %s", exc)
# ── Client eSign gate ──────────────────────────────────────────
# Officer must sign the deactivation letter before we send to USAC.
client_approved = order_data.get("client_approved", False)
if not client_approved and letter_path:
minio_key = f"compliance/{order_number}/usac_deactivation_letter_{datetime.now().strftime('%Y%m%d')}.docx"
try:
import psycopg2
conn = psycopg2.connect(os.environ.get("DATABASE_URL", ""))
from scripts.workers.services.telecom.esign_helper import request_esign
request_esign(
conn=conn,
order_number=order_number,
document_type="discontinuance",
document_title="USAC Filer ID Deactivation Letter",
entity_name=legal_name,
customer_email=entity.get("contact_email") or order_data.get("customer_email", ""),
customer_name=order_data.get("customer_name") or entity.get("contact_name", ""),
document_minio_key=minio_key,
requires_perjury=False,
metadata={"frn": frn, "filer_id": filer_id},
)
conn.close()
except Exception as exc:
logger.warning("Could not create discontinuance eSign record: %s", exc)
logger.info("Form499ADiscontinuanceHandler: paused for client eSign — order %s", order_number)
return [letter_path] if letter_path else []
# Per FCC 499-A Instructions: discontinuance requires TWO steps:
# 1. File the final 499-A (may have actual revenue from the portion
# of the year the company operated — NOT required to be zero)