Customers (the DER) had no concrete how-to for onboarding/enrolling drivers or what information to collect. Add: - Section 1 'Enrolling a driver (new-hire onboarding)' subsection: exact info to collect, the onboarding sequence (collect info, sign Forms A/B, Clearinghouse query, prior-employer inquiry, add to C-TPA pool, pre-employment test, wait for MRO negative), and a driver-removal note. - Form G — Driver Enrollment & Covered-Employee Roster: per-driver enrollment block (name, DOB, SSN last4, CDL #/state, contact, hire date, test result, Clearinghouse/prior-employer status) plus a roster table for the covered pool. - TOC, email, and handler text updated A-F -> A-G.
1324 lines
62 KiB
Python
1324 lines
62 KiB
Python
"""
|
|
DOT Drug & Alcohol Compliance Program binder generator.
|
|
|
|
Produces the instant-delivery **editable DOCX** "binder" that ships when a
|
|
customer buys the DOT Drug & Alcohol Compliance Program. The binder is a
|
|
complete compliance program a small motor carrier can adopt, customise, and
|
|
have a lawyer review/edit, bundling everything needed 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. When testing is required (the six DOT test scenarios)
|
|
4. Random testing program (consortium / pool management)
|
|
5. Supervisor reasonable-suspicion training materials + live/online access
|
|
6. Violations, SAP access, return-to-duty / follow-up
|
|
7. EAP / rehab / treatment resources
|
|
8. Recordkeeping instructions + retention schedule
|
|
9. All required compliance forms (Forms A-G), each on its own page
|
|
10. The regulations (citations + how to read the actual rule text)
|
|
(+ optional state Drug-Free Workplace addendum)
|
|
|
|
Output is **DOCX** so an attorney or the carrier can review and edit it. Each
|
|
ready-to-use form starts on its own page (page break before) and the section
|
|
that follows begins on a fresh page.
|
|
|
|
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)
|
|
|
|
Usage:
|
|
from scripts.document_gen.templates.dot_da_binder_generator import (
|
|
generate_da_binder,
|
|
)
|
|
docx_path = generate_da_binder(
|
|
output_path="/tmp/da_binder.docx",
|
|
carrier_name="Acme Trucking LLC",
|
|
dot_number="1234567",
|
|
mode="fmcsa",
|
|
cdl_drivers=4,
|
|
der_name="Jane Owner",
|
|
provider_name="Performance West Consortium",
|
|
)
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
LOG = logging.getLogger("document_gen.da_binder")
|
|
|
|
try:
|
|
from docx import Document
|
|
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK
|
|
from docx.enum.table import WD_TABLE_ALIGNMENT
|
|
from docx.shared import Inches, Pt, RGBColor
|
|
from docx.oxml.ns import qn
|
|
from docx.oxml import OxmlElement
|
|
except ImportError: # pragma: no cover - exercised only when docx missing
|
|
Document = None # type: ignore[assignment, misc]
|
|
LOG.warning("python-docx not installed — D&A binder generation unavailable")
|
|
|
|
# ── Palette ────────────────────────────────────────────────────────────────
|
|
NAVY = RGBColor(0x0B, 0x1F, 0x3A) if Document else None
|
|
BLUE = RGBColor(0x1D, 0x4E, 0xD8) if Document else None
|
|
SLATE = RGBColor(0x47, 0x55, 0x69) if Document else None
|
|
INK = RGBColor(0x1F, 0x29, 0x37) if Document else None
|
|
WHITE = RGBColor(0xFF, 0xFF, 0xFF) if Document else None
|
|
NAVY_HEX = "0B1F3A"
|
|
LIGHT_HEX = "EEF2F7"
|
|
ALT_HEX = "F5F8FC"
|
|
|
|
# ── Mode metadata ──────────────────────────────────────────────────────────
|
|
MODE_META: dict[str, dict] = {
|
|
"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,
|
|
},
|
|
}
|
|
|
|
_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%)",
|
|
}
|
|
|
|
|
|
# ── Low-level docx helpers ──────────────────────────────────────────────────
|
|
def _shade(cell, hex_color: str) -> None:
|
|
"""Apply a background fill to a table cell."""
|
|
tcPr = cell._tc.get_or_add_tcPr()
|
|
shd = OxmlElement("w:shd")
|
|
shd.set(qn("w:val"), "clear")
|
|
shd.set(qn("w:color"), "auto")
|
|
shd.set(qn("w:fill"), hex_color)
|
|
tcPr.append(shd)
|
|
|
|
|
|
def _set_cell_text(cell, text, *, bold=False, color=None, size=9, white=False):
|
|
cell.text = ""
|
|
p = cell.paragraphs[0]
|
|
p.paragraph_format.space_after = Pt(2)
|
|
p.paragraph_format.space_before = Pt(2)
|
|
run = p.add_run(text)
|
|
run.bold = bold
|
|
run.font.size = Pt(size)
|
|
if white:
|
|
run.font.color.rgb = WHITE
|
|
elif color is not None:
|
|
run.font.color.rgb = color
|
|
else:
|
|
run.font.color.rgb = INK
|
|
return p
|
|
|
|
|
|
def _add_runs(p, text):
|
|
"""Render very small inline markup: **bold** segments."""
|
|
import re
|
|
|
|
for chunk in re.split(r"(\*\*.+?\*\*)", text):
|
|
if not chunk:
|
|
continue
|
|
if chunk.startswith("**") and chunk.endswith("**"):
|
|
r = p.add_run(chunk[2:-2])
|
|
r.bold = True
|
|
else:
|
|
p.add_run(chunk)
|
|
|
|
|
|
class _B:
|
|
"""Thin builder around a python-docx Document with the binder's styles."""
|
|
|
|
def __init__(self, doc, meta, carrier_name):
|
|
self.doc = doc
|
|
self.meta = meta
|
|
self.carrier_name = carrier_name
|
|
|
|
def h1(self, text):
|
|
p = self.doc.add_paragraph()
|
|
p.paragraph_format.space_before = Pt(6)
|
|
p.paragraph_format.space_after = Pt(10)
|
|
p.paragraph_format.keep_with_next = True
|
|
r = p.add_run(text)
|
|
r.bold = True
|
|
r.font.size = Pt(18)
|
|
r.font.color.rgb = NAVY
|
|
# bottom rule
|
|
pPr = p._p.get_or_add_pPr()
|
|
pbdr = OxmlElement("w:pBdr")
|
|
bottom = OxmlElement("w:bottom")
|
|
bottom.set(qn("w:val"), "single")
|
|
bottom.set(qn("w:sz"), "6")
|
|
bottom.set(qn("w:space"), "4")
|
|
bottom.set(qn("w:color"), "CBD5E1")
|
|
pbdr.append(bottom)
|
|
pPr.append(pbdr)
|
|
return p
|
|
|
|
def h2(self, text):
|
|
p = self.doc.add_paragraph()
|
|
p.paragraph_format.space_before = Pt(12)
|
|
p.paragraph_format.space_after = Pt(5)
|
|
p.paragraph_format.keep_with_next = True
|
|
r = p.add_run(text)
|
|
r.bold = True
|
|
r.font.size = Pt(13)
|
|
r.font.color.rgb = NAVY
|
|
return p
|
|
|
|
def h3(self, text):
|
|
p = self.doc.add_paragraph()
|
|
p.paragraph_format.space_before = Pt(9)
|
|
p.paragraph_format.space_after = Pt(3)
|
|
p.paragraph_format.keep_with_next = True
|
|
r = p.add_run(text)
|
|
r.bold = True
|
|
r.font.size = Pt(11)
|
|
r.font.color.rgb = BLUE
|
|
return p
|
|
|
|
def body(self, text, *, italic=False, size=10.5, color=None):
|
|
p = self.doc.add_paragraph()
|
|
p.paragraph_format.space_after = Pt(6)
|
|
_add_runs(p, text)
|
|
for r in p.runs:
|
|
r.font.size = Pt(size)
|
|
r.italic = italic
|
|
r.font.color.rgb = color or INK
|
|
return p
|
|
|
|
def small(self, text):
|
|
p = self.doc.add_paragraph()
|
|
p.paragraph_format.space_after = Pt(4)
|
|
r = p.add_run(text)
|
|
r.font.size = Pt(8)
|
|
r.font.color.rgb = SLATE
|
|
return p
|
|
|
|
def bullets(self, items):
|
|
for item in items:
|
|
p = self.doc.add_paragraph(style="List Bullet")
|
|
p.paragraph_format.space_after = Pt(3)
|
|
p.paragraph_format.left_indent = Inches(0.3)
|
|
_add_runs(p, item)
|
|
for r in p.runs:
|
|
r.font.size = Pt(10.5)
|
|
r.font.color.rgb = INK
|
|
|
|
def numbered(self, items):
|
|
for item in items:
|
|
p = self.doc.add_paragraph(style="List Number")
|
|
p.paragraph_format.space_after = Pt(3)
|
|
p.paragraph_format.left_indent = Inches(0.35)
|
|
_add_runs(p, item)
|
|
for r in p.runs:
|
|
r.font.size = Pt(10.5)
|
|
r.font.color.rgb = INK
|
|
|
|
def table(self, header, rows, widths, *, alt=True):
|
|
t = self.doc.add_table(rows=1, cols=len(header))
|
|
t.alignment = WD_TABLE_ALIGNMENT.CENTER
|
|
t.style = "Table Grid"
|
|
t.autofit = False
|
|
for i, w in enumerate(widths):
|
|
for cell in t.columns[i].cells:
|
|
cell.width = Inches(w)
|
|
for i, htext in enumerate(header):
|
|
c = t.rows[0].cells[i]
|
|
_shade(c, NAVY_HEX)
|
|
_set_cell_text(c, htext, bold=True, white=True, size=9.5)
|
|
for ri, row in enumerate(rows):
|
|
cells = t.add_row().cells
|
|
for i, w in enumerate(widths):
|
|
cells[i].width = Inches(w)
|
|
for i, val in enumerate(row):
|
|
bold_first = i == 0 and len(header) == 2
|
|
_set_cell_text(cells[i], val, bold=bold_first, size=9)
|
|
if alt and ri % 2 == 1:
|
|
for c in cells:
|
|
_shade(c, ALT_HEX)
|
|
self.doc.add_paragraph().paragraph_format.space_after = Pt(2)
|
|
return t
|
|
|
|
def page_break(self):
|
|
self.doc.add_page_break()
|
|
|
|
def spacer(self, pts=8):
|
|
p = self.doc.add_paragraph()
|
|
p.paragraph_format.space_after = Pt(pts)
|
|
return p
|
|
|
|
def fill_line(self, label, *, gap=6):
|
|
"""A labelled fill-in line for forms (underscored to right margin)."""
|
|
p = self.doc.add_paragraph()
|
|
p.paragraph_format.space_after = Pt(gap)
|
|
_add_runs(p, label)
|
|
for r in p.runs:
|
|
r.font.size = Pt(11)
|
|
r.font.color.rgb = INK
|
|
return p
|
|
|
|
def blank_lines(self, n=1, label=""):
|
|
for i in range(n):
|
|
self.fill_line((label if i == 0 else "") +
|
|
" " + "_" * 78, gap=12)
|
|
|
|
|
|
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 as an editable DOCX. Returns the path."""
|
|
if Document is None:
|
|
LOG.warning("python-docx 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")
|
|
company = carrier_name or "the Company"
|
|
|
|
doc = Document()
|
|
for section in doc.sections:
|
|
section.top_margin = Inches(0.8)
|
|
section.bottom_margin = Inches(0.8)
|
|
section.left_margin = Inches(0.9)
|
|
section.right_margin = Inches(0.9)
|
|
|
|
# Running header + page-number footer (skip styling complications: simple)
|
|
_add_header_footer(doc, meta, carrier_name)
|
|
|
|
b = _B(doc, meta, carrier_name)
|
|
|
|
# ── Cover ───────────────────────────────────────────────────────────────
|
|
b.spacer(60)
|
|
for line in ("DOT Drug & Alcohol", "Compliance Program Binder"):
|
|
p = doc.add_paragraph()
|
|
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
r = p.add_run(line)
|
|
r.bold = True
|
|
r.font.size = Pt(26)
|
|
r.font.color.rgb = NAVY
|
|
p.paragraph_format.space_after = Pt(2)
|
|
p = doc.add_paragraph()
|
|
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
p.paragraph_format.space_before = Pt(10)
|
|
r = p.add_run(
|
|
f"Prepared under {meta['part']} and the U.S. DOT procedures at "
|
|
f"{meta['procedures']}")
|
|
r.font.size = Pt(13)
|
|
r.font.color.rgb = SLATE
|
|
b.spacer(24)
|
|
|
|
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 = doc.add_table(rows=0, cols=2)
|
|
t.alignment = WD_TABLE_ALIGNMENT.CENTER
|
|
t.style = "Table Grid"
|
|
for label, val in cover_rows:
|
|
cells = t.add_row().cells
|
|
cells[0].width = Inches(2.3)
|
|
cells[1].width = Inches(4.2)
|
|
_shade(cells[0], LIGHT_HEX)
|
|
_set_cell_text(cells[0], label, bold=True, color=NAVY, size=10.5)
|
|
_set_cell_text(cells[1], val, size=10.5)
|
|
b.spacer(28)
|
|
b.small(
|
|
"Prepared by Performance West Inc. This binder is a compliance "
|
|
"resource and editable template, not legal advice. The motor carrier "
|
|
"remains responsible for adopting, customising, implementing, and "
|
|
"maintaining its own program. Have counsel review before adoption.")
|
|
b.page_break()
|
|
|
|
# ── Table of contents ───────────────────────────────────────────────────
|
|
b.h1("What's Inside This Binder")
|
|
b.bullets([
|
|
"**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 adopt and 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 (A-G).** Every form you need, ready to "
|
|
"use, each on its own page.",
|
|
"**Section 10 — The Regulations.** Citations and how to read the actual "
|
|
"rule text.",
|
|
])
|
|
if state_dfwp:
|
|
b.body(
|
|
f"**Addendum — {state_dfwp} Drug-Free Workplace Program.** "
|
|
"State-specific policy supplement that runs alongside your DOT "
|
|
"program.")
|
|
b.body(
|
|
"**How to use this binder.** Sections 1 and 9 are for you (the DER). "
|
|
"Section 2 is the policy you adopt and hand to employees. Fill in any "
|
|
"blanks (DER name, provider, EAP), sign the policy, collect signed "
|
|
"acknowledgments (Form A), and keep everything per Section 8.")
|
|
b.page_break()
|
|
|
|
# ── Section 1 — Manage your program ─────────────────────────────────────
|
|
b.h1("Section 1 — How to Manage Your Program")
|
|
b.body(
|
|
f"As a motor carrier subject to {meta['part']}, you must operate a drug "
|
|
f"and alcohol testing program covering every {meta['covered']}. The "
|
|
"person who runs the program day-to-day is the **Designated Employer "
|
|
"Representative (DER)**. The DER receives test results, schedules tests, "
|
|
"and immediately removes employees from safety-sensitive duty when "
|
|
"required. Follow these steps.")
|
|
|
|
b.h3("Initial setup (do once)")
|
|
setup = [
|
|
"**Name your DER and a backup.** Record names and contact information "
|
|
"(this binder lists the primary DER on the cover). The DER must be "
|
|
"reachable whenever covered employees are working.",
|
|
"**Adopt the written policy** in Section 2. Fill in the blanks, sign "
|
|
"it, date it, and keep the signed master copy.",
|
|
"**Distribute the policy and educational materials** to every covered "
|
|
"employee and collect a signed acknowledgment (Form A). 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, the collection site(s), the HHS-certified laboratory, and "
|
|
"the Medical Review Officer (MRO).",
|
|
"**Train your supervisors** (at least 120 minutes total) before they "
|
|
"make any reasonable-suspicion decision (Section 5; record on Form F).",
|
|
"**Conduct pre-employment drug tests** with a verified negative result "
|
|
"before any new covered employee performs safety-sensitive functions.",
|
|
]
|
|
if meta.get("clearinghouse"):
|
|
setup.append(
|
|
"**Register with the FMCSA Clearinghouse** at "
|
|
"clearinghouse.fmcsa.dot.gov, designate your C-TPA, and run the "
|
|
"required pre-employment full query (with the driver's consent).")
|
|
b.numbered(setup)
|
|
|
|
b.h3("Ongoing operations (every year)")
|
|
ongoing = [
|
|
"Conduct **random tests** throughout the year at the required minimum "
|
|
f"annual rate of {random_rate} of covered positions, spread evenly "
|
|
"across the year and kept unannounced (Section 4).",
|
|
"Test for **reasonable suspicion** when a trained supervisor observes "
|
|
"specific, articulable signs (Section 5; Form D).",
|
|
"Conduct **post-accident testing** when DOT criteria are met "
|
|
"(Section 3; Form E).",
|
|
"Run **return-to-duty and follow-up tests** for any employee who "
|
|
"violated the rule and completed the SAP process (Section 6).",
|
|
"Keep all **records** for the required retention periods (Section 8).",
|
|
"Review and re-date the policy at least annually, and re-distribute it "
|
|
"when it changes or when you hire.",
|
|
]
|
|
if meta.get("clearinghouse"):
|
|
ongoing.append(
|
|
"Run an **annual FMCSA Clearinghouse limited query** on every CDL "
|
|
"driver, and a **pre-employment full query** (with consent) before "
|
|
"hiring. **Report** violations, refusals, actual-knowledge "
|
|
"findings, negative return-to-duty results, and follow-up "
|
|
"completion to the Clearinghouse within the required timeframes.")
|
|
b.bullets(ongoing)
|
|
|
|
b.h3("The DER's quick-reference duties")
|
|
b.bullets([
|
|
"Receive results from the MRO/C-TPA and act on them the same day.",
|
|
"Immediately remove an employee from safety-sensitive duty on a "
|
|
"verified positive, a 0.04+ alcohol result, or a refusal.",
|
|
"Keep the consortium roster current (add hires, remove departures).",
|
|
"Make sure selected employees proceed to collection immediately.",
|
|
"Maintain the confidential records file and produce it on audit.",
|
|
])
|
|
|
|
b.h3("Enrolling a driver (new-hire onboarding)")
|
|
b.body(
|
|
"Every covered employee must be enrolled in your testing program and "
|
|
"random pool, and must pass a pre-employment drug test, **before** they "
|
|
"first perform safety-sensitive functions. Use Form G to capture each "
|
|
"driver's information and add them to your roster. Follow this sequence "
|
|
"for every new hire:")
|
|
enroll = [
|
|
"**Collect the driver's information** (Form G): full legal name, date "
|
|
"of birth, the last four digits of the SSN (or the full SSN if your "
|
|
"C-TPA requires it for lab matching), CDL number and state, address, "
|
|
"phone, email, hire date, and position.",
|
|
"**Have the driver sign Form A** (policy acknowledgment) and **Form B** "
|
|
"(pre-employment consent and prior-employer release).",
|
|
]
|
|
if meta.get("clearinghouse"):
|
|
enroll.append(
|
|
"**Run the FMCSA Clearinghouse pre-employment full query** (with "
|
|
"the driver's electronic consent in the Clearinghouse) and confirm "
|
|
"the driver is **not prohibited**.")
|
|
enroll.append(
|
|
"**Request the prior-employer DOT testing history** for the past "
|
|
"three years (Form B); for CDL drivers the Clearinghouse covers "
|
|
"violations on/after 1/6/2020 — still request manual records for "
|
|
"the period before that.")
|
|
else:
|
|
enroll.append(
|
|
"**Request the prior-employer DOT testing history** for the past "
|
|
"two years (Form B) and document the inquiry.")
|
|
enroll += [
|
|
"**Add the driver to your C-TPA roster / random pool.** Send Form G to "
|
|
f"{provider_name} (or enter it in their portal) so the driver is in the "
|
|
"next random selection. Do this on or before the hire date.",
|
|
"**Send the driver for the pre-employment drug test** at an approved "
|
|
"collection site. The site uses the federal chain-of-custody form "
|
|
"(CCF) — you do not supply it. Give the driver the collection site "
|
|
"name, address, hours, and any donor pass/authorization your C-TPA "
|
|
"issues.",
|
|
"**Wait for the MRO-verified negative result** before letting the "
|
|
"driver perform any safety-sensitive function. Keep the negative "
|
|
"result and all enrollment records in the driver's confidential file.",
|
|
]
|
|
b.numbered(enroll)
|
|
b.body(
|
|
"**Removing a driver:** when a covered employee leaves or stops "
|
|
"performing safety-sensitive functions, notify your C-TPA to remove "
|
|
"them from the random pool and note the departure on your roster "
|
|
"(Form G). Keep their records for the required retention period "
|
|
"(Section 8).")
|
|
b.page_break()
|
|
|
|
# ── Section 2 — Written policy ──────────────────────────────────────────
|
|
b.h1("Section 2 — Written Drug & Alcohol Testing Policy")
|
|
b.body(
|
|
f"This is the policy {company} adopts and gives to every covered "
|
|
f"employee. It satisfies the written-policy requirement of "
|
|
f"{meta['part']} and {meta['procedures']}. Replace any bracketed blanks, "
|
|
"then sign and date the adoption block at the end.", italic=True)
|
|
|
|
b.h3("1. Purpose and Authority")
|
|
b.body(
|
|
f"{company} (the \"Company\") is committed to a safe, drug- and "
|
|
"alcohol-free workplace and to protecting the public, its employees, "
|
|
"and its property. This policy implements the requirements of the "
|
|
f"{meta['agency']} at {meta['part']} and the U.S. Department of "
|
|
f"Transportation testing procedures at {meta['procedures']}. Where this "
|
|
"policy conflicts with the DOT regulations, the regulations govern. The "
|
|
"Company may also maintain separate, non-DOT workplace rules; this "
|
|
"policy governs DOT-required testing only.")
|
|
|
|
b.h3("2. Who Is Covered")
|
|
b.body(
|
|
f"This policy applies to every {meta['covered']}, including full-time, "
|
|
"part-time, intermittent, temporary, and newly hired employees, and "
|
|
"owner-operators operating under the Company's authority. A covered "
|
|
f"employee is subject to testing whenever {meta['function']}.")
|
|
|
|
b.h3("3. Safety-Sensitive Functions")
|
|
b.body(
|
|
"\"Safety-sensitive function\" includes all on-duty time performing or "
|
|
"available to perform the covered function, plus related duties such as "
|
|
"waiting to be dispatched, inspecting or servicing equipment, "
|
|
"supervising or attending the loading/unloading of a vehicle, and "
|
|
"performing required post-accident duties.")
|
|
|
|
b.h3("4. Prohibited Conduct")
|
|
b.body("A covered employee must not:")
|
|
b.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 performing them, or within **8 hours** after an "
|
|
"accident (or until tested, whichever is first).",
|
|
"Use any illegal drug, or use a controlled substance, unless the use is "
|
|
"consistent with a valid prescription that the prescribing licensed "
|
|
"medical practitioner has determined will not adversely affect the "
|
|
"employee's ability to safely perform the function.",
|
|
"Report for duty or remain on duty when using any substance that the "
|
|
"prescribing physician has not authorised as consistent with safe "
|
|
"performance.",
|
|
"**Refuse to submit** to a required test, adulterate or substitute a "
|
|
"specimen, or fail to remain readily available for post-accident "
|
|
"testing (a refusal is treated the same as a verified positive).",
|
|
"Test positive on, or tamper with, any DOT-required drug or alcohol "
|
|
"test.",
|
|
])
|
|
|
|
b.h3("5. Required Tests")
|
|
b.body(
|
|
"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.")
|
|
b.body(
|
|
"Drug tests use the DOT 5-panel and screen for marijuana, cocaine, "
|
|
"opioids (including codeine, morphine, heroin, hydrocodone, "
|
|
"hydromorphone, oxycodone, and oxymorphone), amphetamines (including "
|
|
"methamphetamine, MDMA, and MDA), and phencyclidine (PCP). A certified "
|
|
"laboratory analyses the specimen; a **Medical Review Officer (MRO)** "
|
|
"reviews and verifies any non-negative result and may contact the "
|
|
"employee for a legitimate medical explanation before reporting a "
|
|
"verified positive to the Company.")
|
|
|
|
b.h3("6. Consequences of a Violation")
|
|
b.body(
|
|
"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 DOT return-to-duty process with a qualified Substance "
|
|
"Abuse Professional (SAP) and pass a return-to-duty test (Section 6). "
|
|
"An employee with an alcohol result of 0.02 to less than 0.04 is "
|
|
"removed from safety-sensitive duty until the start of the next "
|
|
"regularly scheduled duty period, but at least 24 hours. Additional "
|
|
"employment consequences, if any, are governed by separate Company "
|
|
"rules and applicable law.")
|
|
|
|
b.h3("7. Designated Employer Representative")
|
|
b.body(
|
|
f"The Company's DER is {der_name or '[DER NAME]'}"
|
|
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.")
|
|
|
|
b.h3("8. Confidentiality and Employee Rights")
|
|
b.body(
|
|
"Test records are kept confidential and released only as authorised by "
|
|
f"{meta['procedures']} and {meta['part']} (for example, to the "
|
|
"employee, an MRO or SAP, a subsequent employer with the employee's "
|
|
"written consent, or as required by law or the DOT). On written request "
|
|
"an employee may obtain copies of records relating to the employee's "
|
|
"own tests.")
|
|
|
|
b.h3("9. Employee Assistance")
|
|
b.body(
|
|
"Information about substance abuse, its effects, the signs and symptoms "
|
|
"of a problem, and available treatment and Employee Assistance "
|
|
"resources is provided in Section 7 of this binder and is available "
|
|
"from the DER.")
|
|
|
|
b.h3("Policy Adoption")
|
|
b.body(
|
|
"The Company adopts this Drug & Alcohol Testing Policy as of the date "
|
|
"below. The signed original is retained by the DER.")
|
|
b.spacer(6)
|
|
b.fill_line("Company official (print): ___________________________________"
|
|
"__________________")
|
|
b.fill_line("Signature: _______________________________________ Title: "
|
|
"_______________________")
|
|
b.fill_line("Effective date: __________________ USDOT #: "
|
|
f"{dot_number or '________________'}")
|
|
b.page_break()
|
|
|
|
# ── Section 3 — When testing is required ───────────────────────────────
|
|
b.h1("Section 3 — When Testing Is Required")
|
|
b.body(
|
|
"DOT testing happens in six situations. The table summarises the "
|
|
"triggers; the notes below add the detail your DER needs.")
|
|
b.table(
|
|
["Test Type", "When It Happens"],
|
|
[
|
|
["Pre-employment",
|
|
"Before a new covered employee first performs safety-sensitive "
|
|
"functions. A drug test with a verified negative result is "
|
|
"required (and an FMCSA Clearinghouse pre-employment full query "
|
|
"for CDL drivers)."],
|
|
["Random",
|
|
"Unannounced and spread throughout the year, selected by the "
|
|
"consortium from the random pool (Section 4)."],
|
|
["Reasonable suspicion",
|
|
"When a trained supervisor observes specific, articulable, "
|
|
"contemporaneous signs of drug or alcohol use (Section 5)."],
|
|
["Post-accident",
|
|
"After a qualifying accident: a fatality; OR a citation to the "
|
|
"driver plus an injury requiring immediate medical treatment away "
|
|
"from the scene; OR a citation plus a vehicle towed from the scene "
|
|
"due to disabling damage. 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. Conducted under "
|
|
"direct observation."],
|
|
["Follow-up",
|
|
"A SAP-directed schedule of unannounced tests (at least 6 in the "
|
|
"first 12 months, for up to 5 years) after return to duty. "
|
|
"Conducted under direct observation."],
|
|
],
|
|
[1.5, 5.0],
|
|
)
|
|
b.h3("Post-accident testing — decide quickly")
|
|
b.body(
|
|
"Use Form E (Section 9) at the scene. Test if **any** trigger is met. "
|
|
"If a required test cannot be done in time, document why. Do not let a "
|
|
"driver who must be tested consume alcohol or leave before the alcohol "
|
|
"test, and complete the drug test within 32 hours.")
|
|
b.h3("Pre-employment exceptions")
|
|
b.body(
|
|
"A new hire may be exempt from the pre-employment drug test only if you "
|
|
"fully document a valid prior-testing exception (participation in a DOT "
|
|
"program in the prior 30 days, a DOT drug test in the prior 6 months or "
|
|
"random-pool participation for the prior 12 months, and no knowledge of "
|
|
"a prior-employer violation). When in doubt, test.")
|
|
b.page_break()
|
|
|
|
# ── Section 4 — Random testing ─────────────────────────────────────────
|
|
b.h1("Section 4 — Random Testing Program")
|
|
b.body(
|
|
"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).")
|
|
b.h3("How the random pool works")
|
|
b.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 (each employee has an equal chance each "
|
|
"time).",
|
|
"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.",
|
|
])
|
|
b.h3("Your responsibilities")
|
|
b.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 (notification time, arrival time, completion).",
|
|
"Never select, warn, or 'volunteer' specific people — selection must "
|
|
"stay random and confidential until notification.",
|
|
"For random alcohol tests, test only just before, during, or just "
|
|
"after the employee performs safety-sensitive functions.",
|
|
"Keep the consortium's selection and results records (Section 8).",
|
|
])
|
|
b.page_break()
|
|
|
|
# ── Section 5 — Supervisor training ────────────────────────────────────
|
|
b.h1("Section 5 — Supervisor Reasonable-Suspicion Training")
|
|
b.body(
|
|
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). Record each supervisor's training on Form F and "
|
|
"keep it on file.")
|
|
b.h3("Signs a trained supervisor watches for")
|
|
b.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.",
|
|
])
|
|
b.h3("Making a reasonable-suspicion decision")
|
|
b.numbered([
|
|
"One trained supervisor's specific, contemporaneous, articulable "
|
|
"observations are enough — two supervisors are not required.",
|
|
"Document the observations in writing immediately (Form D), signed and "
|
|
"dated within 24 hours.",
|
|
"For alcohol, make the observations just before, during, or just after "
|
|
"the employee performs safety-sensitive functions.",
|
|
"Direct the employee to testing and do not let them drive themselves.",
|
|
"Remove the employee from safety-sensitive duty pending results.",
|
|
])
|
|
b.h3("Live / online supervisor training access")
|
|
b.body(
|
|
"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 dated completion certificate for your records.")
|
|
b.bullets([
|
|
"**Email:** compliance@performancewest.com — subject \"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 (record on Form F).",
|
|
])
|
|
b.page_break()
|
|
|
|
# ── Section 6 — Violations / SAP ───────────────────────────────────────
|
|
b.h1("Section 6 — Violations, SAP & Return-to-Duty")
|
|
b.body(
|
|
"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.")
|
|
b.h3("The return-to-duty process")
|
|
b.numbered([
|
|
"**Remove from duty** and give the employee the contact information "
|
|
"for at least two DOT-qualified Substance Abuse Professionals (SAPs).",
|
|
"**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 (verified negative drug result, or alcohol below "
|
|
"0.02) before resuming duties.",
|
|
"**Follow-up testing.** The SAP sets an unannounced follow-up testing "
|
|
"schedule — at least 6 directly observed tests in the first 12 months, "
|
|
"and the plan may continue for up to 5 years.",
|
|
])
|
|
b.h3("SAP access")
|
|
b.body(
|
|
"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 in "
|
|
"Section 7. The employee generally bears the cost of SAP services and "
|
|
"testing; the Company is not required to return any employee to duty or "
|
|
"to provide a second chance.")
|
|
if meta.get("clearinghouse"):
|
|
b.h3("FMCSA Clearinghouse reporting")
|
|
b.body(
|
|
"Report the violation or refusal, actual-knowledge findings, 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 until the return-to-duty requirements are met "
|
|
"and recorded.")
|
|
b.page_break()
|
|
|
|
# ── Section 7 — EAP / rehab ────────────────────────────────────────────
|
|
b.h1("Section 7 — EAP, Rehab & Treatment Resources")
|
|
b.body(
|
|
"DOT rules require that you give covered employees educational "
|
|
"materials explaining the requirements of the rule, the employer's "
|
|
"policies and procedures, the effects and signs of alcohol and "
|
|
"controlled-substance use, and available resources. Distribute the "
|
|
"materials below with the policy and keep a record of distribution "
|
|
"(Form A).")
|
|
b.h3("Effects, signs, and intervention")
|
|
b.body(
|
|
"Alcohol misuse and controlled-substance use can impair judgment, "
|
|
"reaction time, coordination, perception, attention, and decision-"
|
|
"making, increasing the risk of crashes, injury, death, regulatory "
|
|
"violations, job loss, and health and family harm. Anyone who suspects "
|
|
"a problem should report it to the DER. Do not attempt to diagnose "
|
|
"impairment; document observed facts and contact the DER, who will "
|
|
"decide whether reasonable-suspicion testing applies.")
|
|
b.h3("National help lines and directories")
|
|
b.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 SAP and return-to-duty "
|
|
"guidance.",
|
|
])
|
|
b.h3("Employee Assistance Program (EAP)")
|
|
b.body(
|
|
"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.")
|
|
b.page_break()
|
|
|
|
# ── Section 8 — Recordkeeping ──────────────────────────────────────────
|
|
b.h1("Section 8 — Recordkeeping")
|
|
b.body(
|
|
"Keep your records organised, confidential, and secure; you must "
|
|
"produce them in a DOT audit. The DER (or your C-TPA on your behalf) "
|
|
f"maintains them. Retention periods under {meta['procedures']} / the "
|
|
"mode rule:")
|
|
b.table(
|
|
["Record", "Keep For"],
|
|
[
|
|
["Verified positive 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 (Form F)",
|
|
"While employed + as required"],
|
|
["Employee policy acknowledgments (Form A)",
|
|
"Duration of employment + 1 year"],
|
|
],
|
|
[4.6, 1.4],
|
|
)
|
|
b.body(
|
|
"Store records so they are confidential and retrievable. Your C-TPA "
|
|
"keeps a parallel set of consortium records; request a copy any time.",
|
|
italic=True)
|
|
b.page_break()
|
|
|
|
# ── Section 9 — Forms ──────────────────────────────────────────────────
|
|
b.h1("Section 9 — Required Compliance Forms")
|
|
b.body(
|
|
"The forms on the following pages are ready to print and use; each form "
|
|
"is on its own page. The federal chain-of-custody form (the CCF) and "
|
|
"the DOT Alcohol Testing Form (ATF) are supplied by the collection site "
|
|
"and lab at each collection — you do not print those yourself.")
|
|
b.bullets([
|
|
"**Form A** — Employee Policy Receipt & Acknowledgment.",
|
|
"**Form B** — Pre-Employment 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.",
|
|
"**Form G** — Driver Enrollment & Covered-Employee Roster.",
|
|
])
|
|
|
|
_form_a(b, carrier_name, meta)
|
|
_form_b(b, carrier_name, meta)
|
|
_form_c(b, carrier_name)
|
|
_form_d(b, carrier_name)
|
|
_form_e(b, carrier_name)
|
|
_form_f(b, carrier_name)
|
|
_form_g(b, carrier_name, meta, provider_name)
|
|
|
|
# ── Section 10 — Regulations ───────────────────────────────────────────
|
|
b.page_break()
|
|
b.h1("Section 10 — The Regulations")
|
|
b.body(
|
|
"Your program is governed by two rules that work together: the DOT-wide "
|
|
f"testing procedures at {meta['procedures']}, and the mode rule at "
|
|
f"{meta['part']} from the {meta['agency']}. Read the official, always-"
|
|
"current text on the free government sites below.")
|
|
reg_items = [
|
|
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 rule defines who is covered and the testing scenarios.",
|
|
"**DOT ODAPC (plain-language guidance, forms, brochures):** "
|
|
"transportation.gov/odapc",
|
|
]
|
|
if meta.get("clearinghouse"):
|
|
reg_items += [
|
|
"**FMCSA Drug & Alcohol Clearinghouse:** clearinghouse.fmcsa.dot.gov",
|
|
"**FMCSA testing overview:** fmcsa.dot.gov/regulations/"
|
|
"drug-alcohol-testing-program",
|
|
]
|
|
b.bullets(reg_items)
|
|
b.small(
|
|
"Regulations change. This binder reflects the rules in effect on "
|
|
f"{today}. Always confirm the current rule text on ecfr.gov, and have "
|
|
"counsel review this program before adoption. Questions: "
|
|
"compliance@performancewest.com.")
|
|
|
|
# ── Optional state DFWP addendum ───────────────────────────────────────
|
|
if state_dfwp:
|
|
b.page_break()
|
|
b.h1(f"Addendum — {state_dfwp} Drug-Free Workplace Program")
|
|
b.body(
|
|
f"In addition to your federal DOT program, {company} maintains a "
|
|
f"Drug-Free Workplace Program consistent with {state_dfwp} law. This "
|
|
"program runs alongside (and does not replace) the DOT testing "
|
|
"program in this binder.")
|
|
b.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.",
|
|
])
|
|
b.small(
|
|
f"Confirm your {state_dfwp} program registration, premium-discount, "
|
|
"and notice requirements with the state agency or your insurer, and "
|
|
"have counsel review. We can help — compliance@performancewest.com.")
|
|
|
|
out = Path(output_path)
|
|
out.parent.mkdir(parents=True, exist_ok=True)
|
|
doc.save(str(out))
|
|
LOG.info("Generated D&A binder DOCX (%s mode) -> %s", mode, out)
|
|
return str(out)
|
|
|
|
|
|
# ── Header / footer ─────────────────────────────────────────────────────────
|
|
def _add_header_footer(doc, meta, carrier_name):
|
|
section = doc.sections[0]
|
|
# Header
|
|
hp = section.header.paragraphs[0]
|
|
hp.text = ""
|
|
r = hp.add_run("DOT Drug & Alcohol Compliance Program")
|
|
r.bold = True
|
|
r.font.size = Pt(8)
|
|
r.font.color.rgb = NAVY
|
|
if carrier_name:
|
|
r2 = hp.add_run(" \u2022 " + carrier_name[:48])
|
|
r2.font.size = Pt(8)
|
|
r2.font.color.rgb = SLATE
|
|
# Footer with page number field
|
|
fp = section.footer.paragraphs[0]
|
|
fp.text = ""
|
|
r = fp.add_run(f"Performance West Inc. \u2022 {meta['part']} Page ")
|
|
r.font.size = Pt(7.5)
|
|
r.font.color.rgb = SLATE
|
|
_add_page_field(fp)
|
|
|
|
|
|
def _add_page_field(paragraph):
|
|
run = paragraph.add_run()
|
|
fldChar1 = OxmlElement("w:fldChar")
|
|
fldChar1.set(qn("w:fldCharType"), "begin")
|
|
instrText = OxmlElement("w:instrText")
|
|
instrText.set(qn("xml:space"), "preserve")
|
|
instrText.text = "PAGE"
|
|
fldChar2 = OxmlElement("w:fldChar")
|
|
fldChar2.set(qn("w:fldCharType"), "end")
|
|
run._r.append(fldChar1)
|
|
run._r.append(instrText)
|
|
run._r.append(fldChar2)
|
|
run.font.size = Pt(7.5)
|
|
run.font.color.rgb = SLATE
|
|
|
|
|
|
# ── Forms (each starts a fresh page, fills a page) ──────────────────────────
|
|
def _form_header(b, code, title):
|
|
b.page_break()
|
|
b.h2(f"Form {code} — {title}")
|
|
|
|
|
|
def _form_a(b, carrier_name, meta):
|
|
_form_header(b, "A", "Employee Policy Receipt & Acknowledgment")
|
|
b.body(
|
|
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']}, together with the educational materials on the "
|
|
"effects and signs of alcohol and controlled-substance use. I "
|
|
"understand that I am subject to pre-employment, random, reasonable-"
|
|
"suspicion, post-accident, return-to-duty, and follow-up testing, and "
|
|
"that a verified positive test, an alcohol concentration of 0.04 or "
|
|
"greater, or a refusal will remove me from safety-sensitive duty and "
|
|
"require completion of the DOT return-to-duty process before I may "
|
|
"return.")
|
|
b.body(
|
|
"I understand who the Designated Employer Representative (DER) is and "
|
|
"how to contact the DER with questions, and where to find treatment and "
|
|
"Employee Assistance resources.")
|
|
b.spacer(14)
|
|
for label in [
|
|
"Employee name (print):",
|
|
"Employee signature:",
|
|
"Date: Position:",
|
|
"DER / witness (print):",
|
|
"DER / witness signature:",
|
|
]:
|
|
b.fill_line(label + " " + "_" * max(6, 70 - len(label)), gap=18)
|
|
b.small(
|
|
"Keep the signed original in the employee's file for the duration of "
|
|
"employment plus one year.")
|
|
|
|
|
|
def _form_b(b, carrier_name, meta):
|
|
_form_header(b, "B", "Pre-Employment Consent & Prior-Employer Inquiry")
|
|
b.body(
|
|
f"Complete before a new covered employee performs safety-sensitive "
|
|
f"functions for {carrier_name or 'the Company'}. The applicant consents "
|
|
"to a DOT pre-employment drug test and to the Company's inquiry to "
|
|
"prior DOT employers about the applicant's DOT testing history.")
|
|
b.h3("Applicant consent")
|
|
b.body(
|
|
"I consent to a DOT pre-employment controlled-substances test and "
|
|
"authorise the Company to obtain my DOT drug and alcohol testing "
|
|
"history (including positives, refusals, and completed return-to-duty "
|
|
"follow-up) from my DOT-regulated employers for the past three years. "
|
|
"For CDL positions, I consent to the FMCSA Clearinghouse pre-employment "
|
|
"full query.")
|
|
b.spacer(10)
|
|
for label in [
|
|
"Applicant name (print):",
|
|
"Signature: Date:",
|
|
"Position applied for:",
|
|
"Prior DOT employer(s) contacted:",
|
|
]:
|
|
b.fill_line(label + " " + "_" * max(6, 66 - len(label)), gap=16)
|
|
b.h3("Company use — prior-employer / query results")
|
|
for label in [
|
|
"Pre-employment drug test result: [ ] Negative [ ] Positive "
|
|
"[ ] Refusal",
|
|
"Clearinghouse pre-employment full query: [ ] No prohibited status "
|
|
"[ ] Prohibited",
|
|
"Prior-employer information received: [ ] Yes [ ] No [ ] No prior "
|
|
"DOT employer",
|
|
"Cleared to perform safety-sensitive functions: [ ] Yes [ ] No",
|
|
"DER (print): Signature / date:",
|
|
]:
|
|
b.fill_line(label, gap=14)
|
|
b.small("Retain for the duration of employment plus the required period.")
|
|
|
|
|
|
def _form_c(b, carrier_name):
|
|
_form_header(b, "C", "Test Notification / Authorization to Test")
|
|
b.body(
|
|
"Use to notify an employee that they have been selected or directed for "
|
|
"a DOT test and to document the chain of timing. Give one copy to the "
|
|
"employee and keep one for the file.")
|
|
b.spacer(8)
|
|
for label in [
|
|
"Employee name (print):",
|
|
"USDOT # / Company:",
|
|
"Reason for test: [ ] Random [ ] Reasonable suspicion "
|
|
"[ ] Post-accident [ ] Return-to-duty [ ] Follow-up "
|
|
"[ ] Pre-employment",
|
|
"Type of test: [ ] Drug [ ] Alcohol [ ] Both",
|
|
"Date/time employee notified:",
|
|
"Collection site name / address:",
|
|
"Date/time employee directed to report:",
|
|
"Date/time employee arrived at collection site:",
|
|
"Notes / delays (a delay or failure to proceed may be a refusal):",
|
|
]:
|
|
b.fill_line(label + " " + "_" * max(4, 64 - len(label)), gap=14)
|
|
b.blank_lines(2)
|
|
for label in [
|
|
"Employee signature: Date:",
|
|
"DER / supervisor (print): Signature:",
|
|
]:
|
|
b.fill_line(label + " " + "_" * max(4, 60 - len(label)), gap=16)
|
|
b.small("Retain per the recordkeeping schedule in Section 8.")
|
|
|
|
|
|
def _form_d(b, carrier_name):
|
|
_form_header(b, "D", "Reasonable-Suspicion Observation Record")
|
|
b.body(
|
|
"Complete immediately when directing an employee to a reasonable-"
|
|
"suspicion test. Must be made by a supervisor trained per Section 5 and "
|
|
"signed and dated within 24 hours of the observations.")
|
|
b.spacer(8)
|
|
for label in [
|
|
"Employee observed (print):",
|
|
"Date / time of observation:",
|
|
"Location:",
|
|
]:
|
|
b.fill_line(label + " " + "_" * max(4, 60 - len(label)), gap=14)
|
|
b.body(
|
|
"Specific observations (appearance, behavior, speech, odor, "
|
|
"coordination, performance) — be factual and contemporaneous:")
|
|
b.blank_lines(5)
|
|
for label in [
|
|
"Test directed: [ ] Drug [ ] Alcohol [ ] Both",
|
|
"Employee removed from safety-sensitive duty: [ ] Yes [ ] No",
|
|
"Trained supervisor (print):",
|
|
"Supervisor signature: Date:",
|
|
]:
|
|
b.fill_line(label + (" " + "_" * max(4, 56 - len(label))
|
|
if ":" in label and "[ ]" not in label else ""),
|
|
gap=14)
|
|
b.small(
|
|
"Retain for 5 years. The supervisor must have completed the required "
|
|
"120 minutes of reasonable-suspicion training (see Form F).")
|
|
|
|
|
|
def _form_e(b, carrier_name):
|
|
_form_header(b, "E", "Post-Accident Testing Decision Worksheet")
|
|
b.body(
|
|
"Use immediately after any accident to decide whether DOT post-accident "
|
|
"testing is required. **Test if ANY box below is checked.**")
|
|
b.spacer(6)
|
|
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.",
|
|
]:
|
|
b.fill_line(label, gap=8)
|
|
b.spacer(6)
|
|
b.body(
|
|
"If testing is required: conduct the **alcohol test within 8 hours** "
|
|
"(as soon as possible) and the **drug test within 32 hours**. Do not "
|
|
"let the driver consume alcohol before the alcohol test. Document any "
|
|
"reason a required test could not be completed.")
|
|
b.spacer(10)
|
|
for label in [
|
|
"Driver (print):",
|
|
"Date / time of accident:",
|
|
"Citation issued to driver: [ ] Yes [ ] No",
|
|
"Decision: [ ] Test required [ ] Not required",
|
|
"Alcohol test completed (date/time):",
|
|
"Drug test completed (date/time):",
|
|
"DER (print): Signature / date:",
|
|
]:
|
|
b.fill_line(label + (" " + "_" * max(4, 56 - len(label))
|
|
if "[ ]" not in label else ""), gap=14)
|
|
b.small("Retain for 5 years, including any decision NOT to test.")
|
|
|
|
|
|
def _form_f(b, carrier_name):
|
|
_form_header(b, "F", "Supervisor Training Completion Record")
|
|
b.body(
|
|
f"Record each supervisor who has completed the {('')} required "
|
|
"reasonable-suspicion training: at least 60 minutes on alcohol misuse "
|
|
"and at least 60 minutes on controlled-substance use (120 minutes "
|
|
"total). Keep this record on file and produce it on audit.")
|
|
b.spacer(6)
|
|
b.table(
|
|
["Supervisor name", "Alcohol (min)", "Drugs (min)", "Date", "Trainer / source"],
|
|
[["", "", "", "", ""] for _ in range(8)],
|
|
[2.2, 0.9, 0.9, 0.9, 1.6],
|
|
alt=False,
|
|
)
|
|
b.spacer(10)
|
|
for label in [
|
|
"DER (print): Signature / date:",
|
|
]:
|
|
b.fill_line(label + " " + "_" * 20, gap=14)
|
|
b.small(
|
|
"A supervisor must complete this training before making any "
|
|
"reasonable-suspicion testing decision.")
|
|
|
|
|
|
def _form_g(b, carrier_name, meta, provider_name):
|
|
_form_header(b, "G", "Driver Enrollment & Covered-Employee Roster")
|
|
b.body(
|
|
f"Complete one enrollment block for each covered employee of "
|
|
f"{carrier_name or 'the Company'} and add them to the roster below. "
|
|
f"Send the information to {provider_name} so the employee is placed in "
|
|
"the random pool, and keep this form in your records. Enroll a driver "
|
|
"**before** they perform any safety-sensitive function.")
|
|
|
|
b.h3("New-driver enrollment")
|
|
for label in [
|
|
"Full legal name:",
|
|
"Date of birth: SSN (last 4): ____ ____",
|
|
"CDL number: CDL state:",
|
|
"Address:",
|
|
"Phone: Email:",
|
|
"Position / job title:",
|
|
"Hire date: Date added to random pool:",
|
|
]:
|
|
b.fill_line(label + " " + "_" * max(4, 58 - len(label)), gap=15)
|
|
b.spacer(4)
|
|
for label in [
|
|
"Pre-employment drug test result: [ ] Negative [ ] Pending "
|
|
"[ ] Positive/Refusal (do NOT place on duty)",
|
|
]:
|
|
b.fill_line(label, gap=8)
|
|
if meta.get("clearinghouse"):
|
|
b.fill_line(
|
|
"Clearinghouse pre-employment full query: [ ] Not prohibited "
|
|
"[ ] Prohibited Date run: ____________", gap=8)
|
|
b.fill_line(
|
|
"Prior-employer DOT testing history requested: [ ] Yes [ ] No "
|
|
"[ ] No prior DOT employer", gap=8)
|
|
b.fill_line(
|
|
"Forms collected: [ ] Form A (policy ack.) [ ] Form B "
|
|
"(consent/inquiry)", gap=12)
|
|
|
|
b.h3("Covered-employee roster")
|
|
b.body(
|
|
"Keep this roster current. Add each new hire and mark the date a "
|
|
"departing employee was removed from the random pool.", italic=True)
|
|
b.table(
|
|
["Employee name", "CDL # / state", "Position", "Added to pool",
|
|
"Removed (date)"],
|
|
[["", "", "", "", ""] for _ in range(9)],
|
|
[2.0, 1.4, 1.1, 1.0, 1.1],
|
|
alt=False,
|
|
)
|
|
b.small(
|
|
"Retain enrollment records and the negative pre-employment result in "
|
|
"each driver's confidential file. Notify your C-TPA promptly of every "
|
|
"addition and removal so your random rate stays accurate.")
|
|
|
|
|
|
# ── Misc 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}"
|