add fax filing pipeline: VitalPBX sender, attestation cover page with digital signature, compliance checker pending filing override

- filing_attestation.py: generates cover page attesting PW submitted document
  to recipient with date/time stamp, contact info, and digital signature
- fax_sender.py: sends PDFs via VitalPBX API, polls for delivery, generates
  attested copy for customer records
- dot-lookup.ts: if DOT has pending MCS-150 order, show green 'UPDATE SUBMITTED'
  instead of red 'OVERDUE' in compliance checker
- requirements.txt: add pyhanko + cryptography for PDF digital signatures
This commit is contained in:
justin 2026-05-30 18:32:01 -05:00
parent e2c7cc582b
commit 1f1113d63c
4 changed files with 645 additions and 1 deletions

View file

@ -104,7 +104,37 @@ router.get("/api/v1/dot/lookup", async (req, res) => {
const mcs150Date = mcs150Raw ? new Date(mcs150Raw).toISOString().split("T")[0] : null; const mcs150Date = mcs150Raw ? new Date(mcs150Raw).toISOString().split("T")[0] : null;
const isOverdue = mcs150Date ? new Date(mcs150Date) < twoYearsAgo() : null; const isOverdue = mcs150Date ? new Date(mcs150Date) < twoYearsAgo() : null;
if (outdated || isOverdue) { // Check if we have a pending/recently-filed MCS-150 order for this DOT
let pendingFiling: { filed_at: string; order_number: string } | null = null;
try {
const pendingResult = await pool.query(
`SELECT order_number, updated_at, status FROM compliance_orders
WHERE intake_data->>'dot_number' = $1
AND service_slug = 'mcs150-update'
AND status IN ('filed', 'submitted', 'processing', 'in_progress')
ORDER BY updated_at DESC LIMIT 1`,
[dotNumber],
);
if (pendingResult.rows.length > 0) {
const row = pendingResult.rows[0] as Record<string, unknown>;
pendingFiling = {
filed_at: new Date(row.updated_at as string).toISOString().split("T")[0],
order_number: row.order_number as string,
};
}
} catch {}
if (pendingFiling) {
// We filed it — show green/blue instead of red
checks.push({
id: "mcs150",
label: "MCS-150 Biennial Update",
status: "green",
detail: `UPDATE SUBMITTED — filed by Performance West on ${pendingFiling.filed_at}. `
+ `FMCSA typically reflects updates within 5-10 business days. `
+ `If you need verification of this filing, contact us at (888) 411-0383.`,
});
} else if (outdated || isOverdue) {
checks.push({ checks.push({
id: "mcs150", id: "mcs150",
label: "MCS-150 Biennial Update", label: "MCS-150 Biennial Update",

View file

@ -0,0 +1,355 @@
"""Filing Attestation Cover Page Generator.
After a fax is confirmed delivered, this generates a cover page attesting
that Performance West submitted the document to the recipient, with a
date/time stamp and contact information for regulatory verification.
The cover page is prepended to the original filed PDF and stored as the
customer's proof of filing.
"""
from __future__ import annotations
import logging
import os
import tempfile
from datetime import datetime, timezone
from pathlib import Path
LOG = logging.getLogger("document_gen.filing_attestation")
try:
from pypdf import PdfReader, PdfWriter
from pypdf.generic import NameObject
except ImportError:
PdfReader = None
def generate_attestation_page(
order_number: str,
dot_number: str,
entity_name: str,
document_type: str,
submitted_at: datetime,
recipient_name: str = "Federal Motor Carrier Safety Administration (FMCSA)",
) -> str:
"""Generate a one-page attestation PDF.
Args:
order_number: Our internal order number.
dot_number: USDOT number on the filing.
entity_name: Legal entity name.
document_type: e.g. "MCS-150 Biennial Update", "MCS-150B", etc.
submitted_at: UTC datetime when the filing was transmitted.
recipient_name: Who it was sent to (don't include fax/phone numbers).
Returns:
Path to the attestation PDF.
"""
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
from reportlab.pdfgen import canvas
from reportlab.lib.colors import HexColor
work_dir = tempfile.mkdtemp(prefix="pw_attest_")
filepath = os.path.join(work_dir, f"attestation_{order_number}.pdf")
c = canvas.Canvas(filepath, pagesize=letter)
w, h = letter
# Header bar
c.setFillColor(HexColor("#1a2744"))
c.rect(0, h - 1.2 * inch, w, 1.2 * inch, fill=True, stroke=False)
c.setFillColor(HexColor("#ffffff"))
c.setFont("Helvetica-Bold", 20)
c.drawCentredString(w / 2, h - 0.6 * inch, "CERTIFICATE OF FILING")
c.setFont("Helvetica", 11)
c.drawCentredString(w / 2, h - 0.9 * inch, "Performance West Inc. — DOT Compliance Services")
# Body
y = h - 1.8 * inch
c.setFillColor(HexColor("#1a2744"))
def line(text, font="Helvetica", size=12, spacing=22):
nonlocal y
c.setFont(font, size)
c.drawString(1 * inch, y, text)
y -= spacing
def label_value(label, value, spacing=22):
nonlocal y
c.setFont("Helvetica-Bold", 11)
c.drawString(1 * inch, y, label)
c.setFont("Helvetica", 11)
c.drawString(3.2 * inch, y, str(value))
y -= spacing
# Attestation text
c.setFont("Helvetica", 12)
text_block = (
f"This is to certify that Performance West Inc., acting as the authorized "
f"compliance representative for {entity_name}, submitted the following "
f"document to {recipient_name} on the date and time indicated below."
)
# Word wrap
from reportlab.lib.utils import simpleSplit
lines = simpleSplit(text_block, "Helvetica", 12, w - 2 * inch)
for ln in lines:
c.drawString(1 * inch, y, ln)
y -= 18
y -= 10
# Filing details
label_value("Document:", document_type)
label_value("USDOT Number:", dot_number)
label_value("Entity Name:", entity_name)
label_value("Submitted To:", recipient_name)
# Format the timestamp
local_str = submitted_at.strftime("%B %d, %Y at %I:%M %p %Z")
label_value("Date/Time of Submission:", local_str)
label_value("Order Reference:", order_number)
y -= 15
# Confirmation box
c.setStrokeColor(HexColor("#059669"))
c.setFillColor(HexColor("#f0fdf4"))
c.roundRect(0.8 * inch, y - 50, w - 1.6 * inch, 55, 6, fill=True, stroke=True)
c.setFillColor(HexColor("#166534"))
c.setFont("Helvetica-Bold", 11)
c.drawString(1.1 * inch, y - 18, "TRANSMISSION CONFIRMED")
c.setFont("Helvetica", 10)
c.drawString(1.1 * inch, y - 35,
"This document was successfully transmitted and received by the recipient.")
y -= 80
# Attestation signature block
c.setFillColor(HexColor("#1a2744"))
line("", spacing=10)
c.setFont("Helvetica", 11)
c.drawString(1 * inch, y,
"This attestation is provided for regulatory verification purposes.")
y -= 16
c.drawString(1 * inch, y,
"Please retain this document with your compliance records.")
y -= 30
# Signature line
c.setStrokeColor(HexColor("#374151"))
c.line(1 * inch, y, 3.5 * inch, y)
y -= 15
c.setFont("Helvetica", 10)
c.drawString(1 * inch, y, "Performance West Inc.")
y -= 14
c.drawString(1 * inch, y, "DOT Compliance Division")
# Contact info footer
y = 1.2 * inch
c.setStrokeColor(HexColor("#e2e8f0"))
c.line(0.8 * inch, y + 15, w - 0.8 * inch, y + 15)
c.setFillColor(HexColor("#64748b"))
c.setFont("Helvetica", 9)
c.drawCentredString(w / 2, y,
"For verification of this filing, please contact:")
y -= 14
c.setFont("Helvetica-Bold", 10)
c.setFillColor(HexColor("#1a2744"))
c.drawCentredString(w / 2, y, "Performance West Inc.")
y -= 14
c.setFont("Helvetica", 9)
c.setFillColor(HexColor("#64748b"))
c.drawCentredString(w / 2, y,
"(888) 411-0383 | compliance@performancewest.net | performancewest.net")
y -= 12
c.drawCentredString(w / 2, y,
f"Generated: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}")
c.save()
LOG.info("Attestation cover page generated: %s", filepath)
return filepath
# ── Digital Signature ────────────────────────────────────────────────
# Path to the Performance West signing certificate (PKCS#12)
CERT_DIR = Path(__file__).resolve().parent.parent.parent.parent / "certs"
CERT_P12 = CERT_DIR / "performancewest-signing.p12"
CERT_PASS = os.getenv("PW_SIGNING_CERT_PASS", "performancewest2024")
def ensure_signing_cert() -> str:
"""Create the self-signed signing certificate if it doesn't exist.
Returns path to the .p12 file.
"""
if CERT_P12.exists():
return str(CERT_P12)
CERT_DIR.mkdir(parents=True, exist_ok=True)
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import pkcs12
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Texas"),
x509.NameAttribute(NameOID.LOCALITY_NAME, "Dallas"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Performance West Inc."),
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "DOT Compliance Services"),
x509.NameAttribute(NameOID.COMMON_NAME, "Performance West Filing Attestation"),
])
cert = (
x509.CertificateBuilder()
.subject_name(subject)
.issuer_name(issuer)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(datetime.now(timezone.utc))
.not_valid_after(datetime(2030, 12, 31, tzinfo=timezone.utc))
.add_extension(
x509.BasicConstraints(ca=False, path_length=None), critical=True,
)
.add_extension(
x509.KeyUsage(
digital_signature=True, content_commitment=True,
key_encipherment=False, data_encipherment=False,
key_agreement=False, key_cert_sign=False, crl_sign=False,
encipher_only=False, decipher_only=False,
),
critical=True,
)
.sign(key, hashes.SHA256())
)
p12_data = pkcs12.serialize_key_and_certificates(
name=b"Performance West Signing",
key=key,
cert=cert,
cas=None,
encryption_algorithm=serialization.BestAvailableEncryption(
CERT_PASS.encode()
),
)
CERT_P12.write_bytes(p12_data)
LOG.info("Self-signed signing certificate created: %s", CERT_P12)
return str(CERT_P12)
def digitally_sign_pdf(pdf_path: str) -> str:
"""Apply a PAdES digital signature to a PDF.
Uses the Performance West self-signed certificate. The signature
is visible in Adobe Reader and any PDF viewer that supports digital
signatures.
Args:
pdf_path: Path to the PDF to sign.
Returns:
Path to the signed PDF (overwrites input).
"""
try:
from pyhanko.sign import signers, fields as sig_fields
from pyhanko.sign.general import load_cert_from_pemder
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
from pyhanko import stamp
from cryptography.hazmat.primitives.serialization import pkcs12
cert_path = ensure_signing_cert()
p12_data = Path(cert_path).read_bytes()
private_key, cert, chain = pkcs12.load_key_and_certificates(
p12_data, CERT_PASS.encode()
)
signer = signers.SimpleSigner(
signing_cert=cert,
signing_key=private_key,
cert_registry=None,
)
with open(pdf_path, "rb") as f:
w = IncrementalPdfFileWriter(f)
sig_meta = signers.PdfSignatureMetadata(
field_name="PerformanceWestAttestation",
reason="Filing attestation — document submitted to FMCSA",
location="Dallas, TX",
contact_info="compliance@performancewest.net",
)
signed_path = pdf_path.replace(".pdf", "_signed.pdf")
with open(signed_path, "wb") as out_f:
signers.sign_pdf(
w,
sig_meta,
signer=signer,
output=out_f,
)
# Replace original with signed version
os.replace(signed_path, pdf_path)
LOG.info("PDF digitally signed: %s", pdf_path)
return pdf_path
except ImportError:
LOG.warning("pyhanko not installed — skipping digital signature")
return pdf_path
except Exception as exc:
LOG.error("Digital signature failed (PDF still valid unsigned): %s", exc)
return pdf_path
def prepend_attestation(attestation_pdf: str, original_pdf: str, output_path: str = "") -> str:
"""Prepend the attestation cover page to the original filed PDF.
Args:
attestation_pdf: Path to the attestation PDF.
original_pdf: Path to the original MCS-150 PDF.
output_path: Where to write the combined PDF. If empty, auto-generates.
Returns:
Path to the combined PDF.
"""
if PdfReader is None:
raise ImportError("pypdf not installed")
writer = PdfWriter()
# Add attestation page first
attest_reader = PdfReader(attestation_pdf)
for page in attest_reader.pages:
writer.add_page(page)
# Add original document pages
orig_reader = PdfReader(original_pdf)
for page in orig_reader.pages:
writer.add_page(page)
if not output_path:
work_dir = os.path.dirname(original_pdf)
base = os.path.splitext(os.path.basename(original_pdf))[0]
output_path = os.path.join(work_dir, f"{base}_with_attestation.pdf")
with open(output_path, "wb") as f:
writer.write(f)
LOG.info("Combined attestation + original → %s (%d pages)",
output_path, len(writer.pages))
# Apply digital signature to the final combined PDF
digitally_sign_pdf(output_path)
return output_path

View file

@ -29,6 +29,11 @@ dnspython>=2.6.0
# PDF form filling (MCS-150 official forms) # PDF form filling (MCS-150 official forms)
pypdf>=4.0.0 pypdf>=4.0.0
# PDF digital signatures (filing attestation)
pyhanko>=0.25.0
pyhanko-certvalidator>=0.26.0
cryptography>=43.0.0
# HTTP clients # HTTP clients
aiohttp>=3.9.0 aiohttp>=3.9.0
requests>=2.31.0 requests>=2.31.0

View file

@ -0,0 +1,254 @@
"""VitalPBX Fax Sender.
Sends PDFs via VitalPBX API and polls for delivery confirmation.
After confirmed delivery, generates an attestation cover page and
prepends it to the original document for the customer's records.
Usage:
from scripts.workers.fax_sender import send_fax, send_and_attest
# Just send
result = await send_fax(pdf_url, recipient="12023663477")
# Send, wait for confirmation, then generate attested copy
attested_path = await send_and_attest(
pdf_url=presigned_url,
original_pdf_path="/tmp/mcs150_filled.pdf",
recipient="12023663477",
order_number="CO-12345",
dot_number="1234567",
entity_name="ACME TRUCKING INC",
document_type="MCS-150 Biennial Update",
)
"""
from __future__ import annotations
import asyncio
import json
import logging
import os
from datetime import datetime, timezone
import httpx
LOG = logging.getLogger("workers.fax_sender")
# VitalPBX configuration
PBX_HOST = os.getenv("VITALPBX_HOST", "pbx.carrierone.com")
PBX_API_KEY = os.getenv("VITALPBX_API_KEY", "cc50de7d854f344c596855435ce40821")
PBX_TENANT = os.getenv("VITALPBX_TENANT", "VitalPBX")
PBX_FAX_ID = int(os.getenv("VITALPBX_FAX_ID", "1"))
# FMCSA fax number
FMCSA_FAX = "12023663477"
async def send_fax(
pdf_url: str,
recipient: str,
resolution: str = "medium",
retries: int = 2,
retry_time: int = 300,
) -> dict:
"""Send a fax via VitalPBX API.
Args:
pdf_url: Public URL to the PDF to fax.
recipient: Phone number to fax to (e.g. "12023663477").
resolution: "standard", "medium", or "high".
retries: Number of retry attempts on failure.
retry_time: Seconds between retries.
Returns:
dict with keys: success, log_id, device, status, error
"""
url = f"https://{PBX_HOST}/api/v2/virtual_faxes/{PBX_FAX_ID}/send"
headers = {
"app-key": PBX_API_KEY,
"tenant": PBX_TENANT,
}
form_data = {
"url": pdf_url,
"recipients": recipient,
"resolution": resolution,
"retries": str(retries),
"retry_time": str(retry_time),
}
try:
async with httpx.AsyncClient(verify=False, timeout=30) as client:
resp = await client.post(url, headers=headers, data=form_data)
data = resp.json()
if data.get("status") == "success":
log_ids = data.get("data", {}).get("logs", [])
log_id = log_ids[0] if log_ids else None
LOG.info("[fax] Sent to %s — log_id=%s, device=%s",
recipient, log_id, data["data"].get("device"))
return {
"success": True,
"log_id": log_id,
"device": data["data"].get("device"),
"file": data["data"].get("file"),
"status": "queued",
"error": None,
}
else:
LOG.error("[fax] API error: %s", data)
return {
"success": False,
"log_id": None,
"status": "error",
"error": data.get("message", "Unknown API error"),
}
except Exception as exc:
LOG.error("[fax] Send failed: %s", exc)
return {
"success": False,
"log_id": None,
"status": "error",
"error": str(exc),
}
async def poll_fax_status(log_id: str | int, timeout: int = 300, interval: int = 10) -> dict:
"""Poll VitalPBX for fax delivery status.
Args:
log_id: Fax log ID from send_fax().
timeout: Max seconds to wait.
interval: Seconds between polls.
Returns:
dict with keys: delivered, status, error, duration
"""
url = f"https://{PBX_HOST}/api/v2/virtual_faxes/log/{log_id}"
headers = {
"app-key": PBX_API_KEY,
"tenant": PBX_TENANT,
}
start = datetime.now(timezone.utc)
elapsed = 0
while elapsed < timeout:
try:
async with httpx.AsyncClient(verify=False, timeout=15) as client:
resp = await client.get(url, headers=headers)
data = resp.json()
fax = data.get("data", {})
status = fax.get("status", "").lower()
error = fax.get("error")
if status == "sent" or (status == "sent" and error == "OK"):
LOG.info("[fax] Log %s delivered in %ds", log_id, elapsed)
return {
"delivered": True,
"status": "sent",
"error": error,
"duration": elapsed,
}
elif status == "failed":
LOG.warning("[fax] Log %s failed: %s", log_id, error)
return {
"delivered": False,
"status": "failed",
"error": error,
"duration": elapsed,
}
# Still sending/queued — keep polling
except Exception as exc:
LOG.debug("[fax] Poll error (will retry): %s", exc)
await asyncio.sleep(interval)
elapsed = int((datetime.now(timezone.utc) - start).total_seconds())
LOG.warning("[fax] Log %s timed out after %ds", log_id, timeout)
return {
"delivered": False,
"status": "timeout",
"error": f"Timed out after {timeout}s",
"duration": timeout,
}
async def send_and_attest(
pdf_url: str,
original_pdf_path: str,
recipient: str = FMCSA_FAX,
order_number: str = "",
dot_number: str = "",
entity_name: str = "",
document_type: str = "MCS-150 Biennial Update",
recipient_name: str = "Federal Motor Carrier Safety Administration (FMCSA)",
) -> dict:
"""Send a fax, wait for delivery, then generate attested copy.
Returns:
dict with keys: success, attested_pdf, fax_log_id, submitted_at, error
"""
# 1. Send the fax
send_result = await send_fax(pdf_url, recipient)
if not send_result["success"]:
return {
"success": False,
"attested_pdf": None,
"fax_log_id": None,
"submitted_at": None,
"error": send_result["error"],
}
log_id = send_result["log_id"]
# 2. Poll for delivery confirmation
poll_result = await poll_fax_status(log_id, timeout=300, interval=10)
if not poll_result["delivered"]:
return {
"success": False,
"attested_pdf": None,
"fax_log_id": log_id,
"submitted_at": None,
"error": f"Fax delivery failed: {poll_result['error']}",
}
# 3. Fax delivered — generate attestation
submitted_at = datetime.now(timezone.utc)
try:
from scripts.document_gen.templates.filing_attestation import (
generate_attestation_page,
prepend_attestation,
)
attest_pdf = generate_attestation_page(
order_number=order_number,
dot_number=dot_number,
entity_name=entity_name,
document_type=document_type,
submitted_at=submitted_at,
recipient_name=recipient_name,
)
combined_pdf = prepend_attestation(attest_pdf, original_pdf_path)
LOG.info("[fax] Attested copy generated: %s", combined_pdf)
return {
"success": True,
"attested_pdf": combined_pdf,
"fax_log_id": log_id,
"submitted_at": submitted_at.isoformat(),
"error": None,
}
except Exception as exc:
LOG.error("[fax] Attestation generation failed: %s", exc)
return {
"success": True, # Fax still succeeded
"attested_pdf": None,
"fax_log_id": log_id,
"submitted_at": submitted_at.isoformat(),
"error": f"Fax sent but attestation failed: {exc}",
}