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:
justin 2026-06-02 21:27:44 -05:00
parent 06e59965cc
commit 9718ab9ffa
4 changed files with 1138 additions and 672 deletions

File diff suppressed because it is too large Load diff

View file

@ -790,11 +790,14 @@ def _pw_email_html(headline: str, body_paragraphs: list[str], cta_text: str = ""
def _send_instant_delivery( def _send_instant_delivery(
*, customer_email: str, customer_name: str, order_number: str, *, customer_email: str, customer_name: str, order_number: str,
service_name: str, minio_paths: list[str], storage, 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 Attaches customer-facing documents (PDF and DOCX). Some services deliver an
submission or admin review). Sends fancy branded HTML email. 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 import smtplib
from email.mime.multipart import MIMEMultipart from email.mime.multipart import MIMEMultipart
@ -804,11 +807,16 @@ def _send_instant_delivery(
from pathlib import Path from pathlib import Path
import tempfile import tempfile
# Filter to PDFs only — DOCX is for internal/authority use # Customer-facing deliverables: PDFs and DOCX (e.g. the editable DOT binder).
pdf_paths = [p for p in minio_paths if p.lower().endswith(".pdf")] # Anything else (xlsx working files, etc.) stays internal.
if not pdf_paths: deliver_paths = [
LOG.info("No PDFs to deliver for %s (only DOCX generated)", order_number) 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 return
pdf_paths = deliver_paths # name kept for downstream attach loop
smtp_host = os.environ.get("SMTP_HOST", "co.carrierone.com") smtp_host = os.environ.get("SMTP_HOST", "co.carrierone.com")
smtp_port = int(os.environ.get("SMTP_PORT", "587")) smtp_port = int(os.environ.get("SMTP_PORT", "587"))
@ -826,43 +834,101 @@ def _send_instant_delivery(
for p in pdf_paths for p in pdf_paths
) )
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 = [ body_parts = [
f"Hi {name},", f"Hi {name},",
f"Your <strong>{service_name}</strong> documents for order <strong>{order_number}</strong> are attached.", 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>", f"<ul style=\"margin:8px 0 14px;padding-left:20px;\">{file_list}</ul>",
"These documents were generated automatically upon payment confirmation. " "This binder is a complete, ready-to-adopt program: a written "
"If your order includes an FCC portal submission (e.g., ECFS upload for CPNI, " "testing policy, step-by-step instructions for your Designated "
"or RMD registration), our team will handle that separately and send you a " "Employer Representative, supervisor reasonable-suspicion training "
"<strong>confirmation email with the filing confirmation number</strong> once submitted.", "materials, SAP and treatment resources, a recordkeeping schedule, "
"If anything in the documents is incorrect, don't worry &mdash; just reply " "and every form you need (Forms A&ndash;F).",
"to this email or contact us at <a href=\"mailto:info@performancewest.net\" style=\"color:#059669;\">info@performancewest.net</a> " "<strong>What to do next:</strong> open the document, fill in the "
"and we'll fix it right away. A corrected submission will replace the original at no additional charge.", "blanks (DER name, testing provider, effective date), have it "
"<span style=\"font-size:13px;color:#6b7280;\">This fee is tax deductible as an ordinary business expense under IRC &sect; 162.</span>", "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> &mdash; "
"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 &sect; 162."
"</span>",
"&mdash; Performance West Compliance Team", "&mdash; 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 &mdash; "
"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 &sect; 162."
"</span>",
"&mdash; 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( html = _pw_email_html(
headline=f"Your {service_name} documents are ready", headline=headline,
body_paragraphs=body_parts, body_paragraphs=body_parts,
cta_text="Check My FCC Compliance Status", cta_text=cta_text,
cta_url="https://performancewest.net/tools/fcc-compliance-check", cta_url=cta_url,
) )
msg = MIMEMultipart("mixed") msg = MIMEMultipart("mixed")
msg["From"] = from_email msg["From"] = from_email
msg["To"] = customer_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["Reply-To"] = "info@performancewest.net"
msg.attach(MIMEText(html, "html")) msg.attach(MIMEText(html, "html"))
# Download PDFs from MinIO and attach # Download deliverables from MinIO and attach (PDF + DOCX)
with tempfile.TemporaryDirectory() as tmpdir: with tempfile.TemporaryDirectory() as tmpdir:
for remote_path in pdf_paths: for remote_path in pdf_paths:
local_path = os.path.join(tmpdir, Path(remote_path).name) local_path = os.path.join(tmpdir, Path(remote_path).name)
try: try:
storage.download(remote_path, local_path) 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: with open(local_path, "rb") as f:
part = MIMEBase("application", "pdf") part = MIMEBase("application", subtype)
part.set_payload(f.read()) part.set_payload(f.read())
encoders.encode_base64(part) encoders.encode_base64(part)
part.add_header( 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, service_name=handler_cls.SERVICE_NAME if hasattr(handler_cls, "SERVICE_NAME") else service_slug,
minio_paths=minio_paths, minio_paths=minio_paths,
storage=storage, storage=storage,
service_slug=service_slug,
) )
LOG.info("Instant delivery sent to %s for %s (%s)", LOG.info("Instant delivery sent to %s for %s (%s)",
customer_email, effective_order_number, service_slug) customer_email, effective_order_number, service_slug)

View file

@ -2,20 +2,24 @@
DOT Drug & Alcohol Compliance Program handler ($149). DOT Drug & Alcohol Compliance Program handler ($149).
Instant-delivery service: when a motor carrier orders the program we Instant-delivery service: when a motor carrier orders the program we
generate a complete, print-ready PDF "binder" and email it to them generate a complete, editable Word (.docx) "binder" and email it to them
automatically (no admin step). The binder bundles the written testing automatically (no admin step). DOCX is used so the carrier and its counsel
policy, program-management instructions, supervisor-training materials and can review and adapt the program before adopting it. The binder bundles the
access, EAP / rehab / SAP resources, regulation citations, random-testing written testing policy, program-management instructions, supervisor-training
instructions, required forms, and recordkeeping guidance. 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: Policy variant (DOT operating administration) selection:
For a trucking carrier the program is FMCSA (49 CFR Part 382) that is 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 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 (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 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. INSTANT_DELIVERY path emails it to the customer.
""" """
from __future__ import annotations from __future__ import annotations
@ -92,7 +96,7 @@ class DrugAlcoholProgramHandler(BaseServiceHandler):
c for c in carrier_name if c.isalnum() or c in (" ", "-", "_") c for c in carrier_name if c.isalnum() or c in (" ", "-", "_")
).strip().replace(" ", "_")[:40] or "carrier" ).strip().replace(" ", "_")[:40] or "carrier"
out_path = os.path.join( 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 ( from scripts.document_gen.templates.dot_da_binder_generator import (

View file

@ -162,8 +162,8 @@
<!-- ═══ SECTION: D&A Program (D&A, bundles) ═══ --> <!-- ═══ SECTION: D&A Program (D&A, bundles) ═══ -->
<div id="dot-sec-da" hidden> <div id="dot-sec-da" hidden>
<h3>Drug & Alcohol Compliance Program</h3> <h3>Drug &amp; Alcohol Compliance Program</h3>
<p class="pw-field-help">Required for all carriers with CDL drivers. We will enroll you in a DOT-compliant consortium and set up your program.</p> <p class="pw-field-help">Required for all carriers with CDL drivers. Your program is built under <strong>FMCSA 49 CFR Part 382</strong> (the rule for motor carriers) and delivered as a complete, ready-to-use PDF binder.</p>
<div class="pw-row-3"> <div class="pw-row-3">
<label class="pw-field"><span>CDL Drivers <em>*</em></span> <label class="pw-field"><span>CDL Drivers <em>*</em></span>
<input type="number" id="dot-cdl-drivers" min="0" placeholder="Number of CDL holders" /></label> <input type="number" id="dot-cdl-drivers" min="0" placeholder="Number of CDL holders" /></label>
@ -173,9 +173,25 @@
<input type="text" id="dot-der-name" placeholder="Designated Employer Rep (optional)" /></label> <input type="text" id="dot-der-name" placeholder="Designated Employer Rep (optional)" /></label>
</div> </div>
<div class="pw-row"> <div class="pw-row">
<label class="pw-field"><span>Current D&A Program Provider</span> <label class="pw-field"><span>Current D&amp;A Program Provider</span>
<input type="text" id="dot-current-da" placeholder="Leave blank if none / first time" /></label> <input type="text" id="dot-current-da" placeholder="Leave blank if none / first time" /></label>
</div> </div>
<!-- State Drug-Free Workplace addendum (the one variable that changes the binder) -->
<div class="pw-dfwp-box">
<label class="pw-checkbox-row">
<input type="checkbox" id="dot-da-dfwp" />
<span><strong>Add a state Drug-Free Workplace policy addendum</strong><br>
<span class="pw-field-help" style="margin:0">Some states (e.g. FL, GA, OH, SC, TN, AL, VA) offer a workers'-comp premium discount or other benefits for a registered Drug-Free Workplace Program. We'll append a state-specific policy supplement that runs alongside your federal DOT program. Optional and included.</span></span>
</label>
<div id="dot-da-dfwp-state-row" class="pw-row" hidden style="margin-top:0.75rem">
<label class="pw-field"><span>Drug-Free Workplace State</span>
<select id="dot-da-dfwp-state">
<option value="">Select state...</option>
<option value="Alabama">Alabama</option><option value="Alaska">Alaska</option><option value="Arizona">Arizona</option><option value="Arkansas">Arkansas</option><option value="California">California</option><option value="Colorado">Colorado</option><option value="Connecticut">Connecticut</option><option value="Delaware">Delaware</option><option value="Florida">Florida</option><option value="Georgia">Georgia</option><option value="Hawaii">Hawaii</option><option value="Idaho">Idaho</option><option value="Illinois">Illinois</option><option value="Indiana">Indiana</option><option value="Iowa">Iowa</option><option value="Kansas">Kansas</option><option value="Kentucky">Kentucky</option><option value="Louisiana">Louisiana</option><option value="Maine">Maine</option><option value="Maryland">Maryland</option><option value="Massachusetts">Massachusetts</option><option value="Michigan">Michigan</option><option value="Minnesota">Minnesota</option><option value="Mississippi">Mississippi</option><option value="Missouri">Missouri</option><option value="Montana">Montana</option><option value="Nebraska">Nebraska</option><option value="Nevada">Nevada</option><option value="New Hampshire">New Hampshire</option><option value="New Jersey">New Jersey</option><option value="New Mexico">New Mexico</option><option value="New York">New York</option><option value="North Carolina">North Carolina</option><option value="North Dakota">North Dakota</option><option value="Ohio">Ohio</option><option value="Oklahoma">Oklahoma</option><option value="Oregon">Oregon</option><option value="Pennsylvania">Pennsylvania</option><option value="Rhode Island">Rhode Island</option><option value="South Carolina">South Carolina</option><option value="South Dakota">South Dakota</option><option value="Tennessee">Tennessee</option><option value="Texas">Texas</option><option value="Utah">Utah</option><option value="Vermont">Vermont</option><option value="Virginia">Virginia</option><option value="Washington">Washington</option><option value="West Virginia">West Virginia</option><option value="Wisconsin">Wisconsin</option><option value="Wyoming">Wyoming</option><option value="District of Columbia">District of Columbia</option>
</select></label>
</div>
</div>
</div> </div>
<!-- ═══ SECTION: BOC-3 (BOC-3, bundles) ═══ --> <!-- ═══ SECTION: BOC-3 (BOC-3, bundles) ═══ -->
@ -316,6 +332,9 @@
.pw-cargo-grid label { display: flex; align-items: center; gap: 0.4rem; cursor: pointer; } .pw-cargo-grid label { display: flex; align-items: center; gap: 0.4rem; cursor: pointer; }
.pw-security-notice { display: flex; gap: 8px; align-items: flex-start; background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 12px 14px; margin-bottom: 1rem; font-size: 14px; color: #1e40af; line-height: 1.5; } .pw-security-notice { display: flex; gap: 8px; align-items: flex-start; background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 12px 14px; margin-bottom: 1rem; font-size: 14px; color: #1e40af; line-height: 1.5; }
.pw-upload-area { border: 2px dashed #d1d5db; border-radius: 8px; padding: 1rem; text-align: center; } .pw-upload-area { border: 2px dashed #d1d5db; border-radius: 8px; padding: 1rem; text-align: center; }
.pw-dfwp-box { background: #f0f9ff; border: 1px solid #bae6fd; border-radius: 8px; padding: 0.85rem 1rem; margin-top: 0.75rem; }
.pw-checkbox-row { display: flex; gap: 0.6rem; align-items: flex-start; cursor: pointer; font-size: 0.85rem; color: #374151; }
.pw-checkbox-row input[type="checkbox"] { margin-top: 0.25rem; width: 16px; height: 16px; flex-shrink: 0; }
.pw-err { color: #b91c1c; margin-top: 0.75rem; font-size: 0.9rem; background: #fee2e2; padding: 0.5rem 0.75rem; border-radius: 6px; } .pw-err { color: #b91c1c; margin-top: 0.75rem; font-size: 0.9rem; background: #fee2e2; padding: 0.5rem 0.75rem; border-radius: 6px; }
@media (max-width: 640px) { .pw-row-2, .pw-row-3 { grid-template-columns: 1fr; } .pw-cargo-grid { grid-template-columns: 1fr 1fr; } #dot-id-qr-section { display: none !important; } } @media (max-width: 640px) { .pw-row-2, .pw-row-3 { grid-template-columns: 1fr; } .pw-cargo-grid { grid-template-columns: 1fr 1fr; } #dot-id-qr-section { display: none !important; } }
</style> </style>
@ -379,6 +398,24 @@
ucrState.value = stateEl.value; ucrState.value = stateEl.value;
stateEl.addEventListener("change", () => { ucrState.value = stateEl.value; }); stateEl.addEventListener("change", () => { ucrState.value = stateEl.value; });
} }
// D&A: state Drug-Free Workplace addendum toggle.
// Two-letter business state -> full state name used by the binder generator.
const ST_NAMES = {AL:"Alabama",AK:"Alaska",AZ:"Arizona",AR:"Arkansas",CA:"California",CO:"Colorado",CT:"Connecticut",DE:"Delaware",FL:"Florida",GA:"Georgia",HI:"Hawaii",ID:"Idaho",IL:"Illinois",IN:"Indiana",IA:"Iowa",KS:"Kansas",KY:"Kentucky",LA:"Louisiana",ME:"Maine",MD:"Maryland",MA:"Massachusetts",MI:"Michigan",MN:"Minnesota",MS:"Mississippi",MO:"Missouri",MT:"Montana",NE:"Nebraska",NV:"Nevada",NH:"New Hampshire",NJ:"New Jersey",NM:"New Mexico",NY:"New York",NC:"North Carolina",ND:"North Dakota",OH:"Ohio",OK:"Oklahoma",OR:"Oregon",PA:"Pennsylvania",RI:"Rhode Island",SC:"South Carolina",SD:"South Dakota",TN:"Tennessee",TX:"Texas",UT:"Utah",VT:"Vermont",VA:"Virginia",WA:"Washington",WV:"West Virginia",WI:"Wisconsin",WY:"Wyoming",DC:"District of Columbia"};
const dfwpCb = document.getElementById("dot-da-dfwp");
const dfwpRow = document.getElementById("dot-da-dfwp-state-row");
const dfwpState = document.getElementById("dot-da-dfwp-state");
if (dfwpCb && dfwpRow && !dfwpCb.dataset.wired) {
dfwpCb.dataset.wired = "1";
dfwpCb.addEventListener("change", () => {
dfwpRow.hidden = !dfwpCb.checked;
// Default the DFWP state to the carrier's business state on first check.
if (dfwpCb.checked && dfwpState && !dfwpState.value) {
const full = ST_NAMES[(stateEl?.value || "").toUpperCase()];
if (full) dfwpState.value = full;
}
});
}
} }
// Show sections — retry until wizard element is found // Show sections — retry until wizard element is found
@ -413,7 +450,16 @@
const el = document.getElementById(id); const el = document.getElementById(id);
if (el && val) el.value = val; if (el && val) el.value = val;
} }
}); // Hydrate the D&A state Drug-Free Workplace addendum
const dfwpCb = document.getElementById("dot-da-dfwp");
const dfwpRow = document.getElementById("dot-da-dfwp-state-row");
const dfwpStateEl = document.getElementById("dot-da-dfwp-state");
const wantsDfwp = d.include_state_dfwp === true || d.include_state_dfwp === "yes" || !!d.state_dfwp;
if (dfwpCb && wantsDfwp) {
dfwpCb.checked = true;
if (dfwpRow) dfwpRow.hidden = false;
if (dfwpStateEl && d.state_dfwp) dfwpStateEl.value = d.state_dfwp;
}
// Save all data on step-next // Save all data on step-next
window.addEventListener("pw:step-next", (evt) => { window.addEventListener("pw:step-next", (evt) => {
@ -469,6 +515,9 @@
der_name: val("dot-der-name"), current_da_provider: val("dot-current-da"), der_name: val("dot-der-name"), current_da_provider: val("dot-current-da"),
docket_type: val("dot-docket-type"), docket_number: val("dot-docket-num"), docket_type: val("dot-docket-type"), docket_number: val("dot-docket-num"),
photo_id_uploaded: !!(window).__dotPhotoId, photo_id_uploaded: !!(window).__dotPhotoId,
// D&A: state Drug-Free Workplace addendum selection
include_state_dfwp: !!(document.getElementById("dot-da-dfwp"))?.checked,
state_dfwp: (document.getElementById("dot-da-dfwp"))?.checked ? val("dot-da-dfwp-state") : "",
}}); }});
}); });