diff --git a/api/src/routes/compliance-orders.ts b/api/src/routes/compliance-orders.ts
index 1cc678d..55e72ec 100644
--- a/api/src/routes/compliance-orders.ts
+++ b/api/src/routes/compliance-orders.ts
@@ -267,7 +267,7 @@ const COMPLIANCE_SERVICES: Record<
name: "DOT Drug & Alcohol Compliance Program",
price_cents: 14900,
erpnext_item: "DOT-DRUG-ALCOHOL",
- discountable: false, // passthrough cost — D&A testing provider
+ discountable: true, // instant PDF binder we generate — our own deliverable, no passthrough cost
},
"dot-audit-prep": {
name: "New Entrant Safety Audit Preparation",
diff --git a/scripts/document_gen/templates/dot_da_binder_generator.py b/scripts/document_gen/templates/dot_da_binder_generator.py
new file mode 100644
index 0000000..9f4a390
--- /dev/null
+++ b/scripts/document_gen/templates/dot_da_binder_generator.py
@@ -0,0 +1,872 @@
+"""
+DOT Drug & Alcohol Compliance Program binder generator.
+
+Produces the instant-delivery PDF "binder" that ships when a customer buys
+the $149 DOT Drug & Alcohol Compliance Program. The binder is a single,
+print-ready PDF that bundles everything a small motor carrier needs to run a
+compliant program under the applicable DOT testing regulation:
+
+ 1. How to manage your program (step-by-step instructions)
+ 2. Written drug & alcohol testing policy for employees (mode-specific)
+ 3. Supervisor reasonable-suspicion training materials + live/online access
+ 4. Employee Assistance Program (EAP) + rehab/treatment resources
+ 5. Substance Abuse Professional (SAP) access for DOT violations
+ 6. Copies / citations of the applicable regulations
+ 7. Random testing instructions (consortium / pool management)
+ 8. All required compliance forms (chain-of-custody, consent, refusal, etc.)
+ 9. Recordkeeping instructions + retention schedule
+
+DOT operating administrations (policy variants):
+ - FMCSA : 49 CFR Part 382 (motor carriers / CDL drivers) <- default
+ - FRA : 49 CFR Part 219 (railroad / MOW)
+ - PHMSA : 49 CFR Part 199 (pipeline)
+ - FTA : 49 CFR Part 655 (transit)
+ - FAA : 14 CFR Part 120 (aviation)
+ - USCG : 46 CFR Part 16 (maritime)
+Plus an optional state Drug-Free Workplace Program addendum.
+
+For a trucking carrier the program is almost always FMCSA (Part 382). The
+``mode`` argument selects the variant; ``state_dfwp`` appends a state
+Drug-Free Workplace addendum.
+
+Usage:
+ from scripts.document_gen.templates.dot_da_binder_generator import (
+ generate_da_binder,
+ )
+ pdf_path = generate_da_binder(
+ output_path="/tmp/da_binder.pdf",
+ carrier_name="Acme Trucking LLC",
+ dot_number="1234567",
+ mode="fmcsa",
+ cdl_drivers=4,
+ der_name="Jane Owner",
+ der_title="Owner / Designated Employer Representative",
+ provider_name="Performance West Consortium",
+ )
+"""
+from __future__ import annotations
+
+import logging
+from datetime import datetime
+from pathlib import Path
+from typing import Optional
+
+LOG = logging.getLogger("document_gen.da_binder")
+
+# ── Mode metadata ──────────────────────────────────────────────────────────
+# Each DOT operating administration has its own testing rule. The binder text
+# is written for the chosen mode; FMCSA is the trucking default.
+MODE_META: dict[str, dict[str, str]] = {
+ "fmcsa": {
+ "agency": "Federal Motor Carrier Safety Administration (FMCSA)",
+ "part": "49 CFR Part 382",
+ "procedures": "49 CFR Part 40",
+ "covered": "safety-sensitive employees who operate a commercial motor "
+ "vehicle (CMV) requiring a commercial driver's license (CDL)",
+ "function": "operating a commercial motor vehicle requiring a CDL",
+ "clearinghouse": True,
+ },
+ "fra": {
+ "agency": "Federal Railroad Administration (FRA)",
+ "part": "49 CFR Part 219",
+ "procedures": "49 CFR Part 40",
+ "covered": "employees who perform covered service (train and engine, "
+ "signal, dispatching, and maintenance-of-way functions)",
+ "function": "performing FRA-covered service",
+ "clearinghouse": False,
+ },
+ "phmsa": {
+ "agency": "Pipeline and Hazardous Materials Safety Administration (PHMSA)",
+ "part": "49 CFR Part 199",
+ "procedures": "49 CFR Part 40",
+ "covered": "employees who perform operation, maintenance, or emergency-"
+ "response functions on a pipeline or LNG facility",
+ "function": "performing PHMSA-covered pipeline functions",
+ "clearinghouse": False,
+ },
+ "fta": {
+ "agency": "Federal Transit Administration (FTA)",
+ "part": "49 CFR Part 655",
+ "procedures": "49 CFR Part 40",
+ "covered": "employees who perform safety-sensitive functions for a "
+ "recipient of FTA funding",
+ "function": "performing FTA safety-sensitive functions",
+ "clearinghouse": False,
+ },
+ "faa": {
+ "agency": "Federal Aviation Administration (FAA)",
+ "part": "14 CFR Part 120",
+ "procedures": "49 CFR Part 40",
+ "covered": "employees who perform safety-sensitive aviation functions",
+ "function": "performing FAA safety-sensitive functions",
+ "clearinghouse": False,
+ },
+ "uscg": {
+ "agency": "United States Coast Guard (USCG)",
+ "part": "46 CFR Part 16",
+ "procedures": "49 CFR Part 40",
+ "covered": "crewmembers who occupy or fill a position that affects the "
+ "safe operation of a vessel",
+ "function": "occupying a safety-sensitive crew position",
+ "clearinghouse": False,
+ },
+}
+
+# The five DOT test types & six prohibited-conduct categories are shared by all
+# modes (Part 40 + the mode rule). Random rates differ by mode/year; FMCSA 2024+
+# is 50% drug / 10% alcohol of the average number of covered positions.
+_RANDOM_RATES = {
+ "fmcsa": "50% (controlled substances) and 10% (alcohol)",
+ "fra": "the FRA-published annual minimum random testing rates",
+ "phmsa": "50% (controlled substances) of covered employees",
+ "fta": "50% (controlled substances) and 10% (alcohol)",
+ "faa": "the FAA-published annual minimum random testing rates",
+ "uscg": "the USCG annual minimum random testing rate (currently 25%)",
+}
+
+
+def generate_da_binder(
+ *,
+ output_path: str,
+ carrier_name: str,
+ dot_number: str = "",
+ mode: str = "fmcsa",
+ cdl_drivers: int | str = "",
+ owner_operators: int | str = "",
+ der_name: str = "",
+ der_title: str = "Designated Employer Representative (DER)",
+ provider_name: str = "Performance West Consortium / C-TPA",
+ state_dfwp: str = "",
+) -> str | None:
+ """Render the D&A compliance binder PDF. Returns the path on success."""
+ try:
+ from reportlab.lib.colors import HexColor
+ from reportlab.lib.enums import TA_CENTER, TA_LEFT
+ from reportlab.lib.pagesizes import letter
+ from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
+ from reportlab.lib.units import inch
+ from reportlab.platypus import (
+ BaseDocTemplate,
+ Frame,
+ ListFlowable,
+ ListItem,
+ PageBreak,
+ PageTemplate,
+ Paragraph,
+ Spacer,
+ Table,
+ TableStyle,
+ )
+ except ImportError:
+ LOG.warning("reportlab not installed — D&A binder generation unavailable")
+ return None
+
+ mode = (mode or "fmcsa").lower().strip()
+ meta = MODE_META.get(mode, MODE_META["fmcsa"])
+ random_rate = _RANDOM_RATES.get(mode, _RANDOM_RATES["fmcsa"])
+ today = datetime.now().strftime("%B %d, %Y")
+
+ NAVY = HexColor("#0b1f3a")
+ BLUE = HexColor("#1d4ed8")
+ SLATE = HexColor("#475569")
+ LIGHT = HexColor("#eef2f7")
+
+ styles = getSampleStyleSheet()
+ h1 = ParagraphStyle(
+ "H1", parent=styles["Heading1"], fontName="Helvetica-Bold",
+ fontSize=18, textColor=NAVY, spaceBefore=4, spaceAfter=10, leading=22,
+ )
+ h2 = ParagraphStyle(
+ "H2", parent=styles["Heading2"], fontName="Helvetica-Bold",
+ fontSize=13, textColor=NAVY, spaceBefore=14, spaceAfter=6, leading=16,
+ )
+ h3 = ParagraphStyle(
+ "H3", parent=styles["Heading3"], fontName="Helvetica-Bold",
+ fontSize=11, textColor=BLUE, spaceBefore=10, spaceAfter=4, leading=14,
+ )
+ body = ParagraphStyle(
+ "Body", parent=styles["BodyText"], fontName="Helvetica",
+ fontSize=9.5, leading=14, spaceAfter=6, textColor=HexColor("#1f2937"),
+ )
+ body_i = ParagraphStyle("BodyI", parent=body, fontName="Helvetica-Oblique")
+ small = ParagraphStyle(
+ "Small", parent=body, fontSize=8, textColor=SLATE, leading=11,
+ )
+ cover_title = ParagraphStyle(
+ "CoverTitle", parent=h1, fontSize=26, alignment=TA_CENTER, leading=30,
+ )
+ cover_sub = ParagraphStyle(
+ "CoverSub", parent=body, fontSize=13, alignment=TA_CENTER,
+ textColor=SLATE, leading=18,
+ )
+
+ def bullets(items: list[str], style=body) -> ListFlowable:
+ return ListFlowable(
+ [ListItem(Paragraph(t, style), leftIndent=10) for t in items],
+ bulletType="bullet", bulletColor=BLUE, leftIndent=14,
+ bulletFontSize=7, spaceAfter=4,
+ )
+
+ def numbered(items: list[str], style=body) -> ListFlowable:
+ return ListFlowable(
+ [ListItem(Paragraph(t, style)) for t in items],
+ bulletType="1", leftIndent=18, spaceAfter=4,
+ )
+
+ story: list = []
+
+ # ── Cover ──────────────────────────────────────────────────────────────
+ story.append(Spacer(1, 1.4 * inch))
+ story.append(Paragraph("DOT Drug & Alcohol", cover_title))
+ story.append(Paragraph("Compliance Program Binder", cover_title))
+ story.append(Spacer(1, 0.25 * inch))
+ story.append(Paragraph(
+ f"Prepared under {meta['part']} and the U.S. DOT procedures at "
+ f"{meta['procedures']}", cover_sub))
+ story.append(Spacer(1, 0.55 * inch))
+
+ cover_rows = [
+ ["Motor Carrier", carrier_name or "—"],
+ ["USDOT Number", str(dot_number) or "—"],
+ ["Regulating Agency", meta["agency"]],
+ ["Covered Employees", _covered_count(cdl_drivers, owner_operators)],
+ ["Designated Employer Rep.", f"{der_name or '—'}" +
+ (f" — {der_title}" if der_name else "")],
+ ["Testing Program / C-TPA", provider_name],
+ ["Program Effective Date", today],
+ ]
+ t = Table(cover_rows, colWidths=[2.1 * inch, 3.9 * inch])
+ t.setStyle(TableStyle([
+ ("FONTNAME", (0, 0), (0, -1), "Helvetica-Bold"),
+ ("FONTNAME", (1, 0), (1, -1), "Helvetica"),
+ ("FONTSIZE", (0, 0), (-1, -1), 10),
+ ("TEXTCOLOR", (0, 0), (0, -1), NAVY),
+ ("TEXTCOLOR", (1, 0), (1, -1), HexColor("#1f2937")),
+ ("BACKGROUND", (0, 0), (0, -1), LIGHT),
+ ("LINEBELOW", (0, 0), (-1, -1), 0.5, HexColor("#cbd5e1")),
+ ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
+ ("TOPPADDING", (0, 0), (-1, -1), 7),
+ ("BOTTOMPADDING", (0, 0), (-1, -1), 7),
+ ("LEFTPADDING", (0, 0), (-1, -1), 10),
+ ]))
+ story.append(t)
+ story.append(Spacer(1, 0.5 * inch))
+ story.append(Paragraph(
+ "Prepared by Performance West Inc. This binder is a compliance "
+ "resource, not legal advice. The motor carrier remains responsible "
+ "for implementing and maintaining its program.", small))
+ story.append(PageBreak())
+
+ # ── Table of contents ──────────────────────────────────────────────────
+ story.append(Paragraph("What's Inside This Binder", h1))
+ toc = [
+ "Section 1 — How to Manage Your Program. Step-by-step setup and "
+ "ongoing operating instructions for the Designated Employer "
+ "Representative (DER).",
+ "Section 2 — Written Testing Policy. Your company drug & "
+ "alcohol testing policy to distribute to every covered employee.",
+ "Section 3 — When Testing Is Required. The six DOT test "
+ "scenarios and what triggers each one.",
+ "Section 4 — Random Testing Program. How the consortium random "
+ "pool works and your obligations.",
+ "Section 5 — Supervisor Training. Reasonable-suspicion training "
+ "materials and how to access live/online training.",
+ "Section 6 — Violations, SAP & Return-to-Duty. What happens "
+ "after a positive test, and Substance Abuse Professional access.",
+ "Section 7 — EAP, Rehab & Treatment Resources. Employee "
+ "Assistance Program information and treatment referrals.",
+ "Section 8 — Recordkeeping. What to keep, where, and for how long.",
+ "Section 9 — Required Forms. Every form you need, ready to use.",
+ "Section 10 — The Regulations. Citations and how to read the "
+ "actual rule text.",
+ ]
+ story.append(bullets(toc))
+ if state_dfwp:
+ story.append(Spacer(1, 4))
+ story.append(Paragraph(
+ f"Addendum — {state_dfwp} Drug-Free Workplace Program. "
+ "State-specific policy supplement that runs alongside your DOT "
+ "program.", body))
+ story.append(PageBreak())
+
+ # ── Section 1 — Manage your program ────────────────────────────────────
+ story.append(Paragraph("Section 1 — How to Manage Your Program", h1))
+ story.append(Paragraph(
+ f"As a motor carrier subject to {meta['part']}, you must operate a "
+ "drug and alcohol testing program covering every "
+ f"{meta['covered']}. The person who runs the program day-to-day is the "
+ "Designated Employer Representative (DER). Follow these steps.",
+ body))
+ story.append(Paragraph("Initial setup (do once)", h3))
+ story.append(numbered([
+ "Name your DER. Record the DER's name and contact information "
+ "(this binder lists them on the cover). The DER receives test results "
+ "and removes employees from safety-sensitive duty when required.",
+ "Adopt the written policy in Section 2. Sign it, date it, and "
+ "keep the signed master copy.",
+ "Distribute the policy to every covered employee and collect a "
+ "signed acknowledgment (Form A in Section 9). Give a copy to each new "
+ "hire before they perform safety-sensitive duties.",
+ "Join a testing program / consortium (C-TPA). Your program is "
+ f"administered through {provider_name}, which manages your random "
+ "pool, scheduling, collection sites, the lab, and the Medical Review "
+ "Officer (MRO).",
+ "Conduct pre-employment drug tests with a verified negative "
+ "result before any new covered employee performs safety-sensitive "
+ "functions.",
+ ] + ([
+ "Register with the FMCSA Clearinghouse at "
+ "clearinghouse.fmcsa.dot.gov and run the required queries (see below)."
+ ] if meta.get("clearinghouse") else [])))
+
+ story.append(Paragraph("Ongoing operations (every year)", h3))
+ ongoing = [
+ "Conduct random tests throughout the year at the required "
+ f"minimum annual rate of {random_rate} of covered positions, spread "
+ "evenly across the year (see Section 4).",
+ "Test for reasonable suspicion when a trained supervisor "
+ "observes the signs (see Section 5).",
+ "Conduct post-accident testing when DOT criteria are met "
+ "(see Section 3).",
+ "Run return-to-duty and follow-up tests for any employee who "
+ "violated the rule and completed the SAP process (see Section 6).",
+ "Keep all records for the required retention periods "
+ "(see Section 8).",
+ ]
+ if meta.get("clearinghouse"):
+ ongoing.append(
+ "Run an annual FMCSA Clearinghouse query on every CDL "
+ "driver, and a full query (with driver consent) before "
+ "hiring any new driver. Report violations and refusals to the "
+ "Clearinghouse.")
+ story.append(bullets(ongoing))
+ story.append(PageBreak())
+
+ # ── Section 2 — Written policy ─────────────────────────────────────────
+ story.append(Paragraph("Section 2 — Written Drug & Alcohol Testing Policy", h1))
+ story.append(Paragraph(
+ f"This is the policy {carrier_name or 'the Company'} adopts and gives "
+ f"to every covered employee. It satisfies the written-policy "
+ f"requirement of {meta['part']} and {meta['procedures']}.", body_i))
+
+ story.append(Paragraph("1. Purpose and Authority", h3))
+ story.append(Paragraph(
+ f"{carrier_name or 'The Company'} (the \"Company\") is committed to a "
+ "safe, drug- and alcohol-free workplace. This policy implements the "
+ f"requirements of the {meta['agency']} at {meta['part']} and the U.S. "
+ f"Department of Transportation testing procedures at {meta['procedures']}. "
+ "Where this policy conflicts with DOT regulations, the regulations "
+ "govern.", body))
+
+ story.append(Paragraph("2. Who Is Covered", h3))
+ story.append(Paragraph(
+ f"This policy applies to every {meta['covered']}. A covered employee "
+ f"is subject to testing whenever {meta['function']}.", body))
+
+ story.append(Paragraph("3. Prohibited Conduct", h3))
+ story.append(Paragraph("A covered employee must not:", body))
+ story.append(bullets([
+ "Report for duty or remain on duty with an alcohol concentration of "
+ "0.04 or greater.",
+ "Use alcohol while performing safety-sensitive functions, within "
+ "4 hours before, or within 8 hours after an accident (or until "
+ "tested).",
+ "Use any illegal drug, or use a controlled substance unless under a "
+ "valid prescription consistent with safe operation.",
+ "Report for duty or remain on duty when using a controlled substance "
+ "that the prescribing physician has not authorized as consistent with "
+ "safe performance.",
+ "Refuse to submit to a required test (a refusal is treated the same as "
+ "a verified positive test).",
+ "Test positive on any DOT-required drug or alcohol test.",
+ ]))
+
+ story.append(Paragraph("4. Required Tests", h3))
+ story.append(Paragraph(
+ "The Company conducts the following DOT tests: pre-employment, random, "
+ "reasonable suspicion, post-accident, return-to-duty, and follow-up. "
+ "Section 3 explains when each applies. Drug tests screen for marijuana, "
+ "cocaine, opioids, amphetamines, and phencyclidine (PCP) using the "
+ "DOT 5-panel and are verified by a Medical Review Officer (MRO).", body))
+
+ story.append(Paragraph("5. Consequences of a Violation", h3))
+ story.append(Paragraph(
+ "An employee who has a verified positive test, an alcohol "
+ "concentration of 0.04 or greater, or who refuses a test is "
+ "immediately removed from safety-sensitive duty. The employee may not "
+ "return until they complete the return-to-duty process with a DOT-"
+ "qualified Substance Abuse Professional (SAP) and pass a return-to-duty "
+ "test (see Section 6).", body))
+
+ story.append(Paragraph("6. Designated Employer Representative", h3))
+ story.append(Paragraph(
+ f"The Company's DER is {der_name or '________________________'}"
+ f"{(', ' + der_title) if der_name else ''}. The DER receives test "
+ "results, schedules tests, and removes employees from duty as required. "
+ "Questions about this policy should be directed to the DER.", body))
+
+ story.append(Paragraph("7. Employee Assistance", h3))
+ story.append(Paragraph(
+ "Information about substance abuse, its effects, and available "
+ "treatment and Employee Assistance resources is provided in Section 7 "
+ "of this binder and is available from the DER.", body))
+ story.append(PageBreak())
+
+ # ── Section 3 — When testing is required ─────────────��─────────────────
+ story.append(Paragraph("Section 3 — When Testing Is Required", h1))
+ test_table = [
+ ["Test Type", "When It Happens"],
+ ["Pre-employment",
+ "Before a new covered employee first performs safety-sensitive "
+ "functions. Drug test with a verified negative result is required."],
+ ["Random",
+ "Unannounced, spread throughout the year, selected by the consortium "
+ "from the random pool (see Section 4)."],
+ ["Reasonable suspicion",
+ "When a trained supervisor observes specific, articulable signs of "
+ "drug or alcohol use (see Section 5)."],
+ ["Post-accident",
+ "After a DOT-recordable accident meeting the rule's criteria "
+ "(fatality; citation + injury requiring medical treatment away from "
+ "the scene; or citation + a vehicle towed from the scene). Alcohol "
+ "test within 8 hours, drug test within 32 hours."],
+ ["Return-to-duty",
+ "Before an employee who violated the rule may return to safety-"
+ "sensitive duty, after completing the SAP process. Directly observed."],
+ ["Follow-up",
+ "A SAP-directed schedule of unannounced tests (at least 6 in the "
+ "first 12 months) after return to duty. Directly observed."],
+ ]
+ tt = Table(test_table, colWidths=[1.5 * inch, 4.5 * inch])
+ tt.setStyle(TableStyle([
+ ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
+ ("FONTNAME", (0, 1), (0, -1), "Helvetica-Bold"),
+ ("FONTSIZE", (0, 0), (-1, -1), 9),
+ ("TEXTCOLOR", (0, 0), (-1, 0), HexColor("#ffffff")),
+ ("BACKGROUND", (0, 0), (-1, 0), NAVY),
+ ("BACKGROUND", (0, 1), (0, -1), LIGHT),
+ ("VALIGN", (0, 0), (-1, -1), "TOP"),
+ ("GRID", (0, 0), (-1, -1), 0.4, HexColor("#cbd5e1")),
+ ("TOPPADDING", (0, 0), (-1, -1), 6),
+ ("BOTTOMPADDING", (0, 0), (-1, -1), 6),
+ ("LEFTPADDING", (0, 0), (-1, -1), 7),
+ ("RIGHTPADDING", (0, 0), (-1, -1), 7),
+ ]))
+ story.append(tt)
+ story.append(PageBreak())
+
+ # ── Section 4 — Random testing ─────────────────────────────────────────
+ story.append(Paragraph("Section 4 — Random Testing Program", h1))
+ story.append(Paragraph(
+ f"Random testing is the backbone of your program. The minimum annual "
+ f"random testing rate is {random_rate} of your average number of "
+ "covered positions. Because most small carriers cannot meet the "
+ "spread-and-rate requirements on their own, your covered employees are "
+ f"enrolled in a random pool managed by {provider_name} "
+ "(a Consortium/Third-Party Administrator, or C-TPA).", body))
+ story.append(Paragraph("How the random pool works", h3))
+ story.append(numbered([
+ "Every covered employee is placed in the consortium's random pool.",
+ "Each selection period, the consortium randomly selects names using a "
+ "scientifically valid method.",
+ "Selected employees are notified and must proceed immediately "
+ "to the collection site — no advance notice, no delay.",
+ "Selections are spread reasonably throughout the year so testing is "
+ "truly unannounced and unpredictable.",
+ "The consortium tracks the rate and gives you a year-end summary for "
+ "your records and any DOT audit.",
+ ]))
+ story.append(Paragraph("Your responsibilities", h3))
+ story.append(bullets([
+ "Keep the consortium's roster of covered employees current — add new "
+ "hires and remove departures promptly.",
+ "Send selected employees to testing right away and document that they "
+ "went.",
+ "Never select or 'volunteer' specific people — selection must stay "
+ "random.",
+ "Keep the consortium's selection and results records (see Section 8).",
+ ]))
+ story.append(PageBreak())
+
+ # ── Section 5 — Supervisor training ────────────────────────────────────
+ story.append(Paragraph("Section 5 — Supervisor Reasonable-Suspicion Training", h1))
+ story.append(Paragraph(
+ f"{meta['part']} requires that any supervisor who may make a "
+ "reasonable-suspicion testing decision complete at least 60 minutes "
+ "of training on the symptoms of alcohol misuse and at least "
+ "60 minutes on the symptoms of controlled-substance use "
+ "(120 minutes total). Keep a record of who was trained and when.", body))
+ story.append(Paragraph("Signs a trained supervisor watches for", h3))
+ story.append(bullets([
+ "Appearance: bloodshot or watery eyes, dilated/constricted "
+ "pupils, flushed face, disheveled clothing, drug paraphernalia.",
+ "Behavior: mood swings, agitation, euphoria, drowsiness, "
+ "paranoia, unusual or unsafe risk-taking.",
+ "Speech: slurred, rapid, incoherent, or unusually talkative.",
+ "Coordination: unsteady gait, tremors, poor balance, fumbling.",
+ "Odor: alcohol or marijuana odor on breath, body, or clothing.",
+ "Performance: sudden decline, missed deadlines, accidents, "
+ "near-misses, frequent absences.",
+ ]))
+ story.append(Paragraph("Making a reasonable-suspicion decision", h3))
+ story.append(numbered([
+ "Two trained supervisors are not required — one trained supervisor's "
+ "specific, contemporaneous, articulable observations are enough.",
+ "Document the observations in writing immediately (Form D in "
+ "Section 9), signed and dated within 24 hours.",
+ "Direct the employee to testing and do not let them drive themselves.",
+ "Remove the employee from safety-sensitive duty pending results.",
+ ]))
+ story.append(Paragraph("Live / online supervisor training access", h3))
+ story.append(Paragraph(
+ "Your program includes access to DOT-compliant supervisor training. "
+ "To complete the required 120-minute course online (or schedule a live "
+ "session), contact us and we will send each supervisor an enrollment "
+ "link and issue a completion certificate for your records:", body))
+ story.append(bullets([
+ "Email: compliance@performancewest.com — subject line "
+ "\"Supervisor Training\" with your USDOT number.",
+ "What you get: self-paced online modules, a knowledge check, "
+ "and a dated certificate of completion to keep on file.",
+ ]))
+ story.append(PageBreak())
+
+ # ── Section 6 — Violations / SAP ───────────────────────────────────────
+ story.append(Paragraph("Section 6 — Violations, SAP & Return-to-Duty", h1))
+ story.append(Paragraph(
+ "If a covered employee has a verified positive test, an alcohol "
+ "concentration of 0.04 or greater, or refuses a test, you must "
+ "immediately remove them from safety-sensitive duty. They cannot "
+ "return until they complete the DOT return-to-duty process.", body))
+ story.append(Paragraph("The return-to-duty process", h3))
+ story.append(numbered([
+ "Remove from duty and give the employee the contact information "
+ "for a DOT-qualified Substance Abuse Professional (SAP).",
+ "SAP evaluation. The SAP evaluates the employee and prescribes "
+ "education and/or treatment.",
+ "Treatment / education is completed as directed by the SAP.",
+ "Follow-up evaluation. The SAP confirms the employee complied "
+ "and is eligible to return.",
+ "Return-to-duty test. The employee must pass a directly "
+ "observed return-to-duty test before resuming duties.",
+ "Follow-up testing. The SAP sets an unannounced follow-up "
+ "testing schedule (at least 6 tests in the first 12 months, for up to "
+ "5 years).",
+ ]))
+ story.append(Paragraph("SAP access", h3))
+ story.append(Paragraph(
+ "Your program includes access to a network of DOT-qualified Substance "
+ "Abuse Professionals. To get a SAP referral for an employee, contact "
+ "the DER or email compliance@performancewest.com with your USDOT "
+ "number; we will provide qualified SAP contacts in the employee's "
+ "area. You can also locate a SAP through the DOT and industry "
+ "directories listed in Section 7.", body))
+ if meta.get("clearinghouse"):
+ story.append(Paragraph("FMCSA Clearinghouse reporting", h3))
+ story.append(Paragraph(
+ "Report the violation, refusal, the SAP's name, the negative "
+ "return-to-duty test, and completion of follow-up testing to the "
+ "FMCSA Clearinghouse within the required timeframes. A driver with "
+ "an unresolved Clearinghouse violation is 'prohibited' and may not "
+ "operate a CMV.", body))
+ story.append(PageBreak())
+
+ # ── Section 7 — EAP / rehab ────────────────────────────────────────────
+ story.append(Paragraph("Section 7 — EAP, Rehab & Treatment Resources", h1))
+ story.append(Paragraph(
+ "DOT rules require that you give covered employees educational "
+ "materials that explain the requirements of the rule and the "
+ "employer's policies and procedures, plus information on the effects "
+ "of alcohol and controlled-substance use and available resources. Use "
+ "the resources below and share them with employees.", body))
+ story.append(Paragraph("National help lines and directories", h3))
+ story.append(bullets([
+ "SAMHSA National Helpline: 1-800-662-HELP (4357) — free, "
+ "confidential, 24/7 treatment referral and information service.",
+ "SAMHSA treatment locator: findtreatment.gov — searchable "
+ "directory of treatment facilities by location.",
+ "988 Suicide & Crisis Lifeline: call or text 988.",
+ "Alcoholics Anonymous: aa.org — local meeting finder.",
+ "Narcotics Anonymous: na.org — local meeting finder.",
+ "DOT SAP information: transportation.gov/odapc — Office of "
+ "Drug & Alcohol Policy and Compliance, including the SAP and "
+ "return-to-duty guidance.",
+ ]))
+ story.append(Paragraph("Employee Assistance Program (EAP)", h3))
+ story.append(Paragraph(
+ "An EAP gives employees confidential access to counseling and referral "
+ "services. If your company offers an EAP, list its contact "
+ "information on the acknowledgment you give employees. If you do not "
+ "have an EAP, the national resources above and a SAP referral satisfy "
+ "the educational and referral expectations of the rule. We can help "
+ "you add a low-cost EAP — email compliance@performancewest.com.", body))
+ story.append(PageBreak())
+
+ # ── Section 8 — Recordkeeping ──────────────────────────────────────────
+ story.append(Paragraph("Section 8 — Recordkeeping", h1))
+ story.append(Paragraph(
+ "Keep your records organized and secure; you must produce them in a "
+ "DOT audit. The DER (or your C-TPA on your behalf) maintains them. "
+ "Retention periods under Part 40 / the mode rule:", body))
+ rec_table = [
+ ["Record", "Keep For"],
+ ["Verified positive test results; refusals; SAP reports; "
+ "return-to-duty and follow-up test records; alcohol tests of 0.02+",
+ "5 years"],
+ ["Random selection records and the annual random testing rate "
+ "calculation", "5 years"],
+ ["Reasonable-suspicion and post-accident test records", "5 years"],
+ ["EBT calibration / collection-site documentation", "5 years"],
+ ["Annual MIS summary (if required of your operation)", "5 years"],
+ ["Negative test results and cancelled tests", "1 year"],
+ ["Supervisor training records", "While employed + as required"],
+ ["Employee policy acknowledgments", "Duration of employment + 1 year"],
+ ]
+ rt = Table(rec_table, colWidths=[4.4 * inch, 1.6 * inch])
+ rt.setStyle(TableStyle([
+ ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
+ ("FONTSIZE", (0, 0), (-1, -1), 9),
+ ("TEXTCOLOR", (0, 0), (-1, 0), HexColor("#ffffff")),
+ ("BACKGROUND", (0, 0), (-1, 0), NAVY),
+ ("VALIGN", (0, 0), (-1, -1), "TOP"),
+ ("GRID", (0, 0), (-1, -1), 0.4, HexColor("#cbd5e1")),
+ ("ROWBACKGROUNDS", (0, 1), (-1, -1), [HexColor("#ffffff"), LIGHT]),
+ ("TOPPADDING", (0, 0), (-1, -1), 6),
+ ("BOTTOMPADDING", (0, 0), (-1, -1), 6),
+ ("LEFTPADDING", (0, 0), (-1, -1), 7),
+ ]))
+ story.append(rt)
+ story.append(Spacer(1, 8))
+ story.append(Paragraph(
+ "Store records so they are confidential and retrievable. Your C-TPA "
+ "keeps a parallel set of consortium records; request a copy any time.",
+ small))
+ story.append(PageBreak())
+
+ # ── Section 9 — Forms ──────────────────────────────────────────────────
+ story.append(Paragraph("Section 9 — Required Compliance Forms", h1))
+ story.append(Paragraph(
+ "The forms on the following pages are ready to print and use. The "
+ "federal chain-of-custody and alcohol-testing forms (the CCF and the "
+ "DOT Alcohol Testing Form) are provided by the collection site and "
+ "lab; you do not print those yourself, but your C-TPA supplies them at "
+ "each collection.", body))
+ story.append(bullets([
+ "Form A — Employee Policy Receipt & Acknowledgment.",
+ "Form B — Pre-Employment Testing Consent & Prior-Employer "
+ "Inquiry.",
+ "Form C — Test Notification / Authorization to Test.",
+ "Form D — Reasonable-Suspicion Observation Record.",
+ "Form E — Post-Accident Testing Decision Worksheet.",
+ "Form F — Supervisor Training Completion Record.",
+ ]))
+
+ _append_form_a(story, h2, h3, body, small, carrier_name, meta)
+ _append_form_d(story, h2, body, small, carrier_name)
+ _append_form_e(story, h2, body, small, carrier_name)
+
+ # ── Section 10 — Regulations ───────────────────────────────────────────
+ story.append(Paragraph("Section 10 — The Regulations", h1))
+ story.append(Paragraph(
+ "Your program is governed by two rules that work together: the DOT-"
+ f"wide testing procedures at {meta['procedures']}, and the mode rule "
+ f"at {meta['part']} from the {meta['agency']}. Read the official, "
+ "always-current text on the free government sites below.", body))
+ story.append(bullets([
+ f"{meta['procedures']} (DOT testing procedures): "
+ "ecfr.gov/current/title-49/subtitle-A/part-40",
+ f"{meta['part']} (your mode rule): ecfr.gov — search the part "
+ "number; this is the rule that defines who is covered and the testing "
+ "scenarios.",
+ "DOT ODAPC (plain-language guidance, forms, brochures): "
+ "transportation.gov/odapc",
+ ] + ([
+ "FMCSA Drug & Alcohol Clearinghouse: "
+ "clearinghouse.fmcsa.dot.gov",
+ "FMCSA testing overview: fmcsa.dot.gov/regulations/"
+ "drug-alcohol-testing-program",
+ ] if meta.get("clearinghouse") else [])))
+ story.append(Spacer(1, 10))
+ story.append(Paragraph(
+ "Regulations change. This binder reflects the rules in effect on "
+ f"{today}. Always confirm the current rule text on ecfr.gov, and "
+ "contact us with any questions at compliance@performancewest.com.",
+ small))
+
+ # ── Optional state DFWP addendum ───────────────────────────────────────
+ if state_dfwp:
+ story.append(PageBreak())
+ story.append(Paragraph(
+ f"Addendum — {state_dfwp} Drug-Free Workplace Program", h1))
+ story.append(Paragraph(
+ f"In addition to your federal DOT program, "
+ f"{carrier_name or 'the Company'} maintains a Drug-Free Workplace "
+ f"Program consistent with {state_dfwp} law. This program runs "
+ "alongside (and does not "
+ "replace) the DOT testing program in this binder.", body))
+ story.append(bullets([
+ "The Company prohibits the unlawful manufacture, distribution, "
+ "possession, or use of controlled substances in the workplace.",
+ "Employees must notify the Company of any criminal drug statute "
+ "conviction for a violation occurring in the workplace as required "
+ "by state law.",
+ "The Company makes a good-faith effort to maintain a drug-free "
+ "workplace through this policy, the awareness materials in Section "
+ "7, and available counseling and treatment resources.",
+ f"State-specific notice, testing, and appeal rights under "
+ f"{state_dfwp} law apply where they exceed federal requirements; "
+ "DOT rules always govern DOT-required tests.",
+ ]))
+ story.append(Spacer(1, 8))
+ story.append(Paragraph(
+ f"Confirm your {state_dfwp} program registration, premium-discount, "
+ "and notice requirements with the state agency or your insurer. We "
+ "can help — email compliance@performancewest.com.", small))
+
+ # ── Footer drawing ─────────────────────────────────────────────────────
+ def _decorations(canvas, doc):
+ canvas.saveState()
+ w, h = letter
+ # top accent bar (skip cover)
+ if doc.page > 1:
+ canvas.setFillColor(NAVY)
+ canvas.rect(0, h - 0.28 * inch, w, 0.28 * inch, fill=1, stroke=0)
+ canvas.setFillColor(HexColor("#ffffff"))
+ canvas.setFont("Helvetica-Bold", 8)
+ canvas.drawString(0.85 * inch, h - 0.19 * inch,
+ "DOT Drug & Alcohol Compliance Program")
+ canvas.drawRightString(w - 0.85 * inch, h - 0.19 * inch,
+ (carrier_name or "")[:48])
+ # footer
+ canvas.setFillColor(SLATE)
+ canvas.setFont("Helvetica", 7.5)
+ canvas.drawString(0.85 * inch, 0.42 * inch,
+ f"Performance West Inc. • {meta['part']}")
+ canvas.drawRightString(w - 0.85 * inch, 0.42 * inch,
+ f"Page {doc.page}")
+ canvas.setStrokeColor(HexColor("#cbd5e1"))
+ canvas.setLineWidth(0.4)
+ canvas.line(0.85 * inch, 0.58 * inch, w - 0.85 * inch, 0.58 * inch)
+ canvas.restoreState()
+
+ out = Path(output_path)
+ out.parent.mkdir(parents=True, exist_ok=True)
+ doc = BaseDocTemplate(
+ str(out), pagesize=letter,
+ leftMargin=0.85 * inch, rightMargin=0.85 * inch,
+ topMargin=0.55 * inch, bottomMargin=0.75 * inch,
+ title="DOT Drug & Alcohol Compliance Program",
+ author="Performance West Inc.",
+ )
+ frame = Frame(
+ doc.leftMargin, doc.bottomMargin,
+ doc.width, doc.height - 0.18 * inch, id="body",
+ )
+ doc.addPageTemplates([
+ PageTemplate(id="main", frames=[frame], onPage=_decorations)
+ ])
+ doc.build(story)
+ LOG.info("Generated D&A binder (%s mode) -> %s", mode, out)
+ return str(out)
+
+
+# ── Helpers ────────────────────────────────────────────────────────────────
+def _covered_count(cdl_drivers, owner_operators) -> str:
+ try:
+ n = int(str(cdl_drivers).strip() or 0)
+ except (TypeError, ValueError):
+ n = 0
+ try:
+ oo = int(str(owner_operators).strip() or 0)
+ except (TypeError, ValueError):
+ oo = 0
+ total = n + oo
+ if total <= 0:
+ return "—"
+ extra = f" ({oo} owner-operator)" if oo else ""
+ return f"{total} covered position(s){extra}"
+
+
+def _append_form_a(story, h2, h3, body, small, carrier_name, meta):
+ from reportlab.lib.units import inch
+ from reportlab.platypus import PageBreak, Paragraph, Spacer
+ story.append(PageBreak())
+ story.append(Paragraph("Form A — Employee Policy Receipt & Acknowledgment", h2))
+ story.append(Paragraph(
+ f"I acknowledge that I have received, read, and understand the "
+ f"{carrier_name or 'Company'} Drug & Alcohol Testing Policy adopted "
+ f"under {meta['part']}. I understand that I am subject to pre-"
+ "employment, random, reasonable-suspicion, post-accident, return-to-"
+ "duty, and follow-up testing, and that a positive test or refusal will "
+ "remove me from safety-sensitive duty.", body))
+ story.append(Spacer(1, 22))
+ for label in ["Employee name (print): ______________________________________",
+ "Employee signature: _________________________________________",
+ "Date: ____________________ Position: ____________________",
+ "DER / witness: ______________________________________________"]:
+ story.append(Paragraph(label, body))
+ story.append(Spacer(1, 10))
+ story.append(Paragraph(
+ "Keep the signed original in the employee's file for the duration of "
+ "employment plus one year.", small))
+
+
+def _append_form_d(story, h2, body, small, carrier_name):
+ from reportlab.platypus import PageBreak, Paragraph, Spacer
+ story.append(PageBreak())
+ story.append(Paragraph("Form D — Reasonable-Suspicion Observation Record", h2))
+ story.append(Paragraph(
+ "Complete immediately when directing an employee to a reasonable-"
+ "suspicion test. Must be signed and dated within 24 hours.", body))
+ story.append(Spacer(1, 10))
+ for label in [
+ "Employee observed: __________________________________________",
+ "Date / time of observation: _________________________________",
+ "Location: ____________________________________________________",
+ "Specific observations (appearance, behavior, speech, odor, "
+ "coordination, performance):",
+ "_____________________________________________________________",
+ "_____________________________________________________________",
+ "_____________________________________________________________",
+ "Test directed: [ ] Drug [ ] Alcohol [ ] Both",
+ "Trained supervisor (print): _________________________________",
+ "Supervisor signature: ________________________ Date: _______",
+ ]:
+ story.append(Paragraph(label, body))
+ story.append(Spacer(1, 8))
+ story.append(Paragraph(
+ "Retain for 5 years. The supervisor must have completed the required "
+ "120 minutes of reasonable-suspicion training (see Form F).", small))
+
+
+def _append_form_e(story, h2, body, small, carrier_name):
+ from reportlab.platypus import PageBreak, Paragraph, Spacer
+ story.append(PageBreak())
+ story.append(Paragraph("Form E — Post-Accident Testing Decision Worksheet", h2))
+ story.append(Paragraph(
+ "Use immediately after any accident to decide whether DOT post-"
+ "accident testing is required. Test if ANY box below is checked.", body))
+ story.append(Spacer(1, 8))
+ for label in [
+ "[ ] The accident involved a fatality.",
+ "[ ] The driver received a citation AND a person was "
+ "injured and required medical treatment away from the scene.",
+ "[ ] The driver received a citation AND a vehicle was "
+ "towed from the scene due to disabling damage.",
+ ]:
+ story.append(Paragraph(label, body))
+ story.append(Spacer(1, 4))
+ story.append(Spacer(1, 8))
+ story.append(Paragraph(
+ "If testing is required: alcohol test as soon as possible "
+ "(within 8 hours) and drug test within 32 hours. Document any reason a "
+ "required test could not be completed.", body))
+ story.append(Spacer(1, 12))
+ for label in [
+ "Driver: ____________________________ Date/time of accident: ______",
+ "Decision: [ ] Test required [ ] Not required",
+ "DER (print): ______________________ Signature: __________________",
+ ]:
+ story.append(Paragraph(label, body))
+ story.append(Spacer(1, 10))
+ story.append(Paragraph("Retain for 5 years.", small))
diff --git a/scripts/tests/test_dot_da_binder.py b/scripts/tests/test_dot_da_binder.py
new file mode 100644
index 0000000..4ad8878
--- /dev/null
+++ b/scripts/tests/test_dot_da_binder.py
@@ -0,0 +1,117 @@
+"""Verify the DOT Drug & Alcohol compliance binder generates correctly.
+
+Renders the binder for the default FMCSA (trucking) variant plus a non-default
+DOT mode with a state Drug-Free Workplace addendum, and asserts the PDFs are
+multi-page and contain the key deliverable sections the program promises:
+written policy, program-management instructions, supervisor training, EAP/SAP
+resources, random-testing instructions, recordkeeping, forms, and regulations.
+
+Requires: reportlab, pypdf, and (for text extraction) pdfplumber.
+Run from the repo root with a venv that has those installed.
+"""
+from __future__ import annotations
+
+import importlib.util
+import os
+import tempfile
+
+_GEN = os.path.abspath(
+ os.path.join(
+ os.path.dirname(__file__), "..", "document_gen", "templates",
+ "dot_da_binder_generator.py",
+ )
+)
+_spec = importlib.util.spec_from_file_location("dot_da_binder_generator", _GEN)
+_mod = importlib.util.module_from_spec(_spec)
+_spec.loader.exec_module(_mod) # type: ignore[union-attr]
+generate_da_binder = _mod.generate_da_binder
+MODE_META = _mod.MODE_META
+
+
+def _extract_text(path: str) -> str:
+ import pypdf
+
+ reader = pypdf.PdfReader(path)
+ return "\n".join(page.extract_text() or "" for page in reader.pages)
+
+
+def test_fmcsa_binder_has_all_sections():
+ with tempfile.TemporaryDirectory() as d:
+ out = os.path.join(d, "binder.pdf")
+ path = generate_da_binder(
+ output_path=out,
+ carrier_name="Acme Trucking LLC",
+ dot_number="3456789",
+ mode="fmcsa",
+ cdl_drivers=4,
+ owner_operators=1,
+ der_name="Jane Owner",
+ provider_name="Performance West Consortium",
+ )
+ assert path and os.path.exists(path)
+
+ import pypdf
+
+ assert len(pypdf.PdfReader(path).pages) >= 10, "binder should be substantial"
+
+ text = _extract_text(path)
+ # FMCSA-specific facts
+ assert "49 CFR Part 382" in text
+ assert "Federal Motor Carrier Safety Administration" in text
+ assert "Clearinghouse" in text, "FMCSA binder must mention the Clearinghouse"
+ # The promised deliverables (one assertion each)
+ for needle in [
+ "How to Manage Your Program", # program-management instructions
+ "Written Drug & Alcohol Testing Policy", # written policy
+ "Random Testing Program", # random testing instructions
+ "Supervisor", # supervisor training materials
+ "Substance Abuse Professional", # SAP access
+ "SAMHSA", # EAP / rehab / treatment resources
+ "Recordkeeping", # recordkeeping instructions
+ "Required Compliance Forms", # required forms
+ "Acknowledgment", # an actual form
+ "The Regulations", # copies/citations of regulations
+ ]:
+ assert needle in text, f"missing deliverable section: {needle!r}"
+
+
+def test_non_fmcsa_mode_and_state_addendum():
+ with tempfile.TemporaryDirectory() as d:
+ out = os.path.join(d, "binder_phmsa.pdf")
+ path = generate_da_binder(
+ output_path=out,
+ carrier_name="Pipeline Co",
+ dot_number="111",
+ mode="phmsa",
+ cdl_drivers=3,
+ state_dfwp="Georgia",
+ )
+ assert path and os.path.exists(path)
+ text = _extract_text(path)
+ # PHMSA variant swaps in the right rule + agency, no Clearinghouse
+ assert "49 CFR Part 199" in text
+ assert "Pipeline and Hazardous Materials Safety Administration" in text
+ assert "clearinghouse.fmcsa.dot.gov" not in text.lower()
+ # State addendum present
+ assert "Georgia Drug-Free Workplace Program" in text
+
+
+def test_all_modes_render():
+ with tempfile.TemporaryDirectory() as d:
+ for mode in MODE_META:
+ out = os.path.join(d, f"{mode}.pdf")
+ path = generate_da_binder(
+ output_path=out,
+ carrier_name="Test Co",
+ dot_number="1",
+ mode=mode,
+ cdl_drivers=2,
+ )
+ assert path and os.path.exists(path), f"mode {mode} failed to render"
+
+
+if __name__ == "__main__":
+ test_fmcsa_binder_has_all_sections()
+ test_non_fmcsa_mode_and_state_addendum()
+ test_all_modes_render()
+ print("All DOT D&A binder tests passed.")
diff --git a/scripts/workers/job_server.py b/scripts/workers/job_server.py
index 6b16b0b..66ed943 100644
--- a/scripts/workers/job_server.py
+++ b/scripts/workers/job_server.py
@@ -1204,6 +1204,8 @@ def handle_process_compliance_service(payload: dict) -> dict:
"policy-development", "ccpa-audit", "privacy-policy",
"data-mapping", "breach-response", "consent-audit",
"dnc-compliance", "campaign-review",
+ # DOT / FMCSA instant-delivery binders
+ "dot-drug-alcohol", # generates the D&A compliance program binder
}
if service_slug in INSTANT_DELIVERY_SLUGS and minio_paths:
customer_email = order.get("customer_email")
diff --git a/scripts/workers/services/__init__.py b/scripts/workers/services/__init__.py
index 634693f..c90f389 100644
--- a/scripts/workers/services/__init__.py
+++ b/scripts/workers/services/__init__.py
@@ -47,6 +47,7 @@ from .state_puc_filing import StatePucFilingHandler
from .fcc_carrier_registration import FCCCarrierRegistrationHandler
# DOT / FMCSA Motor Carrier Services
from .mcs150_update import MCS150UpdateHandler
+from .dot_drug_alcohol import DrugAlcoholProgramHandler
from .boc3_filing import BOC3FilingHandler
# State-level trucking compliance (IRP, IFTA, weight taxes, MCP, etc.)
from .state_trucking import StateTruckingHandler
@@ -109,7 +110,7 @@ SERVICE_HANDLERS: dict[str, type] = {
"ucr-registration": MCS150UpdateHandler, # admin-assisted, same pattern
"dot-registration": MCS150UpdateHandler, # admin-assisted
"mc-authority": MCS150UpdateHandler, # admin-assisted
- "dot-drug-alcohol": MCS150UpdateHandler, # admin-assisted (partner enrollment)
+ "dot-drug-alcohol": DrugAlcoholProgramHandler, # instant PDF binder ($149)
"dot-audit-prep": MCS150UpdateHandler, # admin-assisted (document prep)
"dot-full-compliance": MCS150UpdateHandler, # fans out to individual services
"usdot-reactivation": MCS150UpdateHandler, # same FMCSA submission flow
diff --git a/scripts/workers/services/dot_drug_alcohol.py b/scripts/workers/services/dot_drug_alcohol.py
new file mode 100644
index 0000000..35cde2b
--- /dev/null
+++ b/scripts/workers/services/dot_drug_alcohol.py
@@ -0,0 +1,178 @@
+"""
+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.
+
+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.
+
+Returns the local PDF path so job_server uploads it to MinIO and the
+INSTANT_DELIVERY path emails it to the customer.
+"""
+from __future__ import annotations
+
+import json
+import logging
+import os
+import tempfile
+from datetime import datetime
+
+from .base_handler import BaseServiceHandler
+
+LOG = logging.getLogger("workers.services.dot_drug_alcohol")
+
+# DOT operating administrations we can build a binder for. FMCSA is the
+# trucking default; everything else requires an explicit intake override.
+_VALID_MODES = {"fmcsa", "fra", "phmsa", "fta", "faa", "uscg"}
+
+
+class DrugAlcoholProgramHandler(BaseServiceHandler):
+ """Generate and instant-deliver the DOT D&A Compliance Program binder."""
+
+ SERVICE_SLUG = "dot-drug-alcohol"
+ SERVICE_NAME = "DOT Drug & Alcohol Compliance Program"
+ REQUIRES_LLM = False
+
+ async def process(self, order_data: dict) -> list[str]:
+ order_number = order_data.get("order_number") or order_data.get("name", "")
+ LOG.info("[%s] Building DOT D&A compliance binder", order_number)
+
+ intake = order_data.get("intake_data") or {}
+ if isinstance(intake, str):
+ try:
+ intake = json.loads(intake)
+ except (TypeError, ValueError):
+ intake = {}
+
+ carrier_name = (
+ intake.get("legal_name")
+ or intake.get("entity_name")
+ or order_data.get("customer_name", "")
+ ).strip()
+ dot_number = str(intake.get("dot_number", "")).strip()
+ cdl_drivers = intake.get("cdl_drivers", "")
+ owner_operators = intake.get("owner_operators", "")
+ der_name = (intake.get("der_name") or "").strip()
+ current_provider = (intake.get("current_da_provider") or "").strip()
+
+ # ── Policy variant (DOT mode) selection ──────────────────────────
+ mode = self._resolve_mode(intake)
+
+ # Optional state Drug-Free Workplace addendum. Accept either an
+ # explicit flag/state value or derive from the carrier's base state
+ # if the intake marks it as a DFWP state.
+ state_dfwp = self._resolve_state_dfwp(intake)
+
+ # The C-TPA / consortium that administers the program. If the
+ # customer already has a provider, name it; otherwise default to our
+ # managed consortium.
+ provider_name = current_provider or "Performance West Consortium / C-TPA"
+
+ # ── Guard: need at minimum the carrier name to personalize ───────
+ if not carrier_name:
+ LOG.warning(
+ "[%s] No carrier name in intake — pausing for intake", order_number
+ )
+ self._request_intake(order_data)
+ return []
+
+ # ── Generate the binder ──────────────────────────────────────────
+ work_dir = self._safe_work_dir()
+ date_str = datetime.now().strftime("%Y%m%d")
+ safe_name = "".join(
+ 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"
+ )
+
+ from scripts.document_gen.templates.dot_da_binder_generator import (
+ generate_da_binder,
+ )
+
+ result = generate_da_binder(
+ output_path=out_path,
+ carrier_name=carrier_name,
+ dot_number=dot_number,
+ mode=mode,
+ cdl_drivers=cdl_drivers,
+ owner_operators=owner_operators,
+ der_name=der_name,
+ der_title="Designated Employer Representative (DER)",
+ provider_name=provider_name,
+ state_dfwp=state_dfwp,
+ )
+
+ if not result:
+ LOG.error("[%s] D&A binder generation returned no file", order_number)
+ return []
+
+ LOG.info(
+ "[%s] D&A binder ready (mode=%s, state_dfwp=%s) -> %s",
+ order_number, mode, state_dfwp or "none", result,
+ )
+ return [result]
+
+ # ------------------------------------------------------------------ #
+ # Variant resolution
+ # ------------------------------------------------------------------ #
+ def _resolve_mode(self, intake: dict) -> str:
+ """Pick the DOT operating-administration variant.
+
+ Trucking carriers are FMCSA (49 CFR Part 382) by default. Honor an
+ explicit ``dot_da_mode`` override for the rare non-FMCSA operation.
+ """
+ raw = (intake.get("dot_da_mode") or intake.get("dot_mode") or "").lower().strip()
+ if raw in _VALID_MODES:
+ return raw
+ # A few human-friendly aliases customers might supply.
+ aliases = {
+ "trucking": "fmcsa", "motor carrier": "fmcsa", "cdl": "fmcsa",
+ "rail": "fra", "railroad": "fra",
+ "pipeline": "phmsa", "transit": "fta", "bus": "fta",
+ "aviation": "faa", "air": "faa",
+ "maritime": "uscg", "marine": "uscg", "vessel": "uscg",
+ }
+ return aliases.get(raw, "fmcsa")
+
+ def _resolve_state_dfwp(self, intake: dict) -> str:
+ """Return a state name if a Drug-Free Workplace addendum is wanted."""
+ explicit = (intake.get("state_dfwp") or "").strip()
+ if explicit:
+ return explicit
+ # If the customer opted into a DFWP add-on, use their base/operating
+ # state. Otherwise omit the addendum (DOT program stands alone).
+ if str(intake.get("include_state_dfwp", "")).lower() in ("1", "true", "yes"):
+ return (
+ intake.get("base_state")
+ or intake.get("address_state")
+ or ""
+ ).strip()
+ return ""
+
+ # ------------------------------------------------------------------ #
+ # Helpers
+ # ------------------------------------------------------------------ #
+ def _safe_work_dir(self) -> str:
+ try:
+ return self._make_work_dir()
+ except Exception:
+ return tempfile.mkdtemp(prefix="da_binder_")
+
+ def _request_intake(self, order_data: dict) -> None:
+ """Best-effort: nudge for intake when carrier name is missing."""
+ try:
+ fn = getattr(self, "_request_entity_intake", None)
+ if callable(fn):
+ fn(order_data)
+ except Exception as exc:
+ LOG.warning("Could not request intake: %s", exc)