DOT D&A binder: editable DOCX output, all 6 forms each full-page, service-aware delivery email
- Rewrite dot_da_binder_generator.py to emit an editable .docx (was reportlab PDF) so carriers/counsel can review and adapt the program. ~4000 words, 10 sections. - Render all six required forms (A-F); previously only A, D, E existed. Each form starts on its own page (page break) and fills a page. - Mode-aware policy text for FMCSA/FRA/PHMSA/FTA/FAA/USCG with correct CFR parts and random-testing rates; optional single-state Drug-Free Workplace addendum (federal DOT program is nationwide; only the optional DFWP addendum is state-keyed). - Handler now outputs .docx instead of .pdf. - job_server instant-delivery: attach DOCX (correct MIME) as well as PDF, and use DOT-specific email copy + CTA instead of the FCC/telecom boilerplate.
This commit is contained in:
parent
06e59965cc
commit
9718ab9ffa
4 changed files with 1138 additions and 672 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -790,11 +790,14 @@ def _pw_email_html(headline: str, body_paragraphs: list[str], cta_text: str = ""
|
|||
def _send_instant_delivery(
|
||||
*, customer_email: str, customer_name: str, order_number: str,
|
||||
service_name: str, minio_paths: list[str], storage,
|
||||
service_slug: str = "",
|
||||
):
|
||||
"""Email generated PDFs to the customer immediately after payment.
|
||||
"""Email generated deliverables to the customer immediately after payment.
|
||||
|
||||
Only sends PDF files — DOCX files are internal (for authority
|
||||
submission or admin review). Sends fancy branded HTML email.
|
||||
Attaches customer-facing documents (PDF and DOCX). Some services deliver an
|
||||
editable DOCX (e.g. the DOT Drug & Alcohol binder, intended for the
|
||||
carrier/its counsel to review and adopt); others deliver print-ready PDFs.
|
||||
Email copy is tailored per service. Sends fancy branded HTML email.
|
||||
"""
|
||||
import smtplib
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
|
@ -804,11 +807,16 @@ def _send_instant_delivery(
|
|||
from pathlib import Path
|
||||
import tempfile
|
||||
|
||||
# Filter to PDFs only — DOCX is for internal/authority use
|
||||
pdf_paths = [p for p in minio_paths if p.lower().endswith(".pdf")]
|
||||
if not pdf_paths:
|
||||
LOG.info("No PDFs to deliver for %s (only DOCX generated)", order_number)
|
||||
# Customer-facing deliverables: PDFs and DOCX (e.g. the editable DOT binder).
|
||||
# Anything else (xlsx working files, etc.) stays internal.
|
||||
deliver_paths = [
|
||||
p for p in minio_paths
|
||||
if p.lower().endswith(".pdf") or p.lower().endswith(".docx")
|
||||
]
|
||||
if not deliver_paths:
|
||||
LOG.info("No customer deliverables to send for %s", order_number)
|
||||
return
|
||||
pdf_paths = deliver_paths # name kept for downstream attach loop
|
||||
|
||||
smtp_host = os.environ.get("SMTP_HOST", "co.carrierone.com")
|
||||
smtp_port = int(os.environ.get("SMTP_PORT", "587"))
|
||||
|
|
@ -826,43 +834,101 @@ def _send_instant_delivery(
|
|||
for p in pdf_paths
|
||||
)
|
||||
|
||||
body_parts = [
|
||||
f"Hi {name},",
|
||||
f"Your <strong>{service_name}</strong> documents for order <strong>{order_number}</strong> are attached.",
|
||||
f"<ul style=\"margin:8px 0 14px;padding-left:20px;\">{file_list}</ul>",
|
||||
"These documents were generated automatically upon payment confirmation. "
|
||||
"If your order includes an FCC portal submission (e.g., ECFS upload for CPNI, "
|
||||
"or RMD registration), our team will handle that separately and send you a "
|
||||
"<strong>confirmation email with the filing confirmation number</strong> once submitted.",
|
||||
"If anything in the documents is incorrect, don't worry — just reply "
|
||||
"to this email or contact us at <a href=\"mailto:info@performancewest.net\" style=\"color:#059669;\">info@performancewest.net</a> "
|
||||
"and we'll fix it right away. A corrected submission will replace the original at no additional charge.",
|
||||
"<span style=\"font-size:13px;color:#6b7280;\">This fee is tax deductible as an ordinary business expense under IRC § 162.</span>",
|
||||
"— Performance West Compliance Team",
|
||||
]
|
||||
is_dot = (service_slug or "").lower() in (
|
||||
"dot-drug-alcohol", "dot-drug-alcohol-program", "dot-da",
|
||||
) or "drug & alcohol" in (service_name or "").lower()
|
||||
|
||||
if is_dot:
|
||||
body_parts = [
|
||||
f"Hi {name},",
|
||||
f"Your <strong>{service_name}</strong> for order "
|
||||
f"<strong>{order_number}</strong> is attached as an editable Word "
|
||||
"document.",
|
||||
f"<ul style=\"margin:8px 0 14px;padding-left:20px;\">{file_list}</ul>",
|
||||
"This binder is a complete, ready-to-adopt program: a written "
|
||||
"testing policy, step-by-step instructions for your Designated "
|
||||
"Employer Representative, supervisor reasonable-suspicion training "
|
||||
"materials, SAP and treatment resources, a recordkeeping schedule, "
|
||||
"and every form you need (Forms A–F).",
|
||||
"<strong>What to do next:</strong> open the document, fill in the "
|
||||
"blanks (DER name, testing provider, effective date), have it "
|
||||
"reviewed by your counsel if you wish, then sign the policy, give a "
|
||||
"copy to each covered employee, and collect a signed acknowledgment "
|
||||
"(Form A). Keep everything per the recordkeeping schedule in "
|
||||
"Section 8.",
|
||||
"Because it is a Word file, you and your attorney can edit it "
|
||||
"freely to match your operation.",
|
||||
"Questions or need a correction? Just reply to this email or "
|
||||
"contact us at <a href=\"mailto:info@performancewest.net\" "
|
||||
"style=\"color:#059669;\">info@performancewest.net</a> — "
|
||||
"we'll help right away at no additional charge.",
|
||||
"<span style=\"font-size:13px;color:#6b7280;\">This fee is tax "
|
||||
"deductible as an ordinary business expense under IRC § 162."
|
||||
"</span>",
|
||||
"— Performance West Compliance Team",
|
||||
]
|
||||
cta_text = "Manage My DOT Compliance"
|
||||
cta_url = "https://performancewest.net/services/dot-drug-alcohol"
|
||||
headline = "Your DOT Drug & Alcohol Compliance Binder is ready"
|
||||
else:
|
||||
body_parts = [
|
||||
f"Hi {name},",
|
||||
f"Your <strong>{service_name}</strong> documents for order "
|
||||
f"<strong>{order_number}</strong> are attached.",
|
||||
f"<ul style=\"margin:8px 0 14px;padding-left:20px;\">{file_list}</ul>",
|
||||
"These documents were generated automatically upon payment "
|
||||
"confirmation. If your order includes an FCC portal submission "
|
||||
"(e.g., ECFS upload for CPNI, or RMD registration), our team will "
|
||||
"handle that separately and send you a <strong>confirmation email "
|
||||
"with the filing confirmation number</strong> once submitted.",
|
||||
"If anything in the documents is incorrect, don't worry — "
|
||||
"just reply to this email or contact us at "
|
||||
"<a href=\"mailto:info@performancewest.net\" "
|
||||
"style=\"color:#059669;\">info@performancewest.net</a> and we'll "
|
||||
"fix it right away. A corrected submission will replace the "
|
||||
"original at no additional charge.",
|
||||
"<span style=\"font-size:13px;color:#6b7280;\">This fee is tax "
|
||||
"deductible as an ordinary business expense under IRC § 162."
|
||||
"</span>",
|
||||
"— Performance West Compliance Team",
|
||||
]
|
||||
cta_text = "Check My FCC Compliance Status"
|
||||
cta_url = "https://performancewest.net/tools/fcc-compliance-check"
|
||||
headline = f"Your {service_name} documents are ready"
|
||||
|
||||
html = _pw_email_html(
|
||||
headline=f"Your {service_name} documents are ready",
|
||||
headline=headline,
|
||||
body_paragraphs=body_parts,
|
||||
cta_text="Check My FCC Compliance Status",
|
||||
cta_url="https://performancewest.net/tools/fcc-compliance-check",
|
||||
cta_text=cta_text,
|
||||
cta_url=cta_url,
|
||||
)
|
||||
|
||||
msg = MIMEMultipart("mixed")
|
||||
msg["From"] = from_email
|
||||
msg["To"] = customer_email
|
||||
msg["Subject"] = f"Your {service_name} documents are ready \u2014 Order {order_number}"
|
||||
msg["Subject"] = (
|
||||
f"Your {service_name} is ready \u2014 Order {order_number}"
|
||||
if is_dot else
|
||||
f"Your {service_name} documents are ready \u2014 Order {order_number}"
|
||||
)
|
||||
msg["Reply-To"] = "info@performancewest.net"
|
||||
msg.attach(MIMEText(html, "html"))
|
||||
|
||||
# Download PDFs from MinIO and attach
|
||||
# Download deliverables from MinIO and attach (PDF + DOCX)
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
for remote_path in pdf_paths:
|
||||
local_path = os.path.join(tmpdir, Path(remote_path).name)
|
||||
try:
|
||||
storage.download(remote_path, local_path)
|
||||
if remote_path.lower().endswith(".docx"):
|
||||
subtype = (
|
||||
"vnd.openxmlformats-officedocument."
|
||||
"wordprocessingml.document"
|
||||
)
|
||||
else:
|
||||
subtype = "pdf"
|
||||
with open(local_path, "rb") as f:
|
||||
part = MIMEBase("application", "pdf")
|
||||
part = MIMEBase("application", subtype)
|
||||
part.set_payload(f.read())
|
||||
encoders.encode_base64(part)
|
||||
part.add_header(
|
||||
|
|
@ -1219,6 +1285,7 @@ def handle_process_compliance_service(payload: dict) -> dict:
|
|||
service_name=handler_cls.SERVICE_NAME if hasattr(handler_cls, "SERVICE_NAME") else service_slug,
|
||||
minio_paths=minio_paths,
|
||||
storage=storage,
|
||||
service_slug=service_slug,
|
||||
)
|
||||
LOG.info("Instant delivery sent to %s for %s (%s)",
|
||||
customer_email, effective_order_number, service_slug)
|
||||
|
|
|
|||
|
|
@ -2,20 +2,24 @@
|
|||
DOT Drug & Alcohol Compliance Program handler ($149).
|
||||
|
||||
Instant-delivery service: when a motor carrier orders the program we
|
||||
generate a complete, print-ready PDF "binder" and email it to them
|
||||
automatically (no admin step). The binder bundles the written testing
|
||||
policy, program-management instructions, supervisor-training materials and
|
||||
access, EAP / rehab / SAP resources, regulation citations, random-testing
|
||||
instructions, required forms, and recordkeeping guidance.
|
||||
generate a complete, editable Word (.docx) "binder" and email it to them
|
||||
automatically (no admin step). DOCX is used so the carrier and its counsel
|
||||
can review and adapt the program before adopting it. The binder bundles the
|
||||
written testing policy, program-management instructions, supervisor-training
|
||||
materials and access, EAP / rehab / SAP resources, regulation citations,
|
||||
random-testing instructions, all required forms (A-F, each on its own page),
|
||||
and recordkeeping guidance.
|
||||
|
||||
Policy variant (DOT operating administration) selection:
|
||||
For a trucking carrier the program is FMCSA (49 CFR Part 382) — that is
|
||||
the default. If the customer's operation falls under a different DOT mode
|
||||
(FRA, PHMSA, FTA, FAA, USCG) we honor an explicit ``dot_da_mode`` value in
|
||||
the intake data. An optional ``state_dfwp`` value appends a state
|
||||
Drug-Free Workplace addendum.
|
||||
Drug-Free Workplace addendum (keyed to the carrier's home/principal state,
|
||||
not per-employee — the federal DOT program itself is nationwide and not
|
||||
state-specific).
|
||||
|
||||
Returns the local PDF path so job_server uploads it to MinIO and the
|
||||
Returns the local DOCX path so job_server uploads it to MinIO and the
|
||||
INSTANT_DELIVERY path emails it to the customer.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
|
@ -92,7 +96,7 @@ class DrugAlcoholProgramHandler(BaseServiceHandler):
|
|||
c for c in carrier_name if c.isalnum() or c in (" ", "-", "_")
|
||||
).strip().replace(" ", "_")[:40] or "carrier"
|
||||
out_path = os.path.join(
|
||||
work_dir, f"DOT_DA_Compliance_Binder_{safe_name}_{date_str}.pdf"
|
||||
work_dir, f"DOT_DA_Compliance_Binder_{safe_name}_{date_str}.docx"
|
||||
)
|
||||
|
||||
from scripts.document_gen.templates.dot_da_binder_generator import (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue