DOT D&A binder: add DER Quick-Start checklist, two-column vendor directory, flow sections

- Add a one-page 'DER Quick-Start Checklist' tear-off as the first content page
  (set-up-once / every-hire / ongoing checkboxes, each pointing to the relevant
  section or form).
- Add a two-column 'Suggested Vendors & Resources' directory page: C-TPA/
  consortium, collection sites & labs, MRO, SAP, supervisor training, and (mode-
  aware) FMCSA Clearinghouse or DOT resources, plus employee help lines. Marked
  as examples not endorsements; mode-aware.
- Remove forced page breaks between consecutive content sections (now a light
  section rule) so they flow continuously; page breaks kept only for the cover,
  quick-start, TOC, each form, the vendor page, regulations, and the addendum.
- New builder helpers: section_rule(), checkbox(), two_col_panels().
This commit is contained in:
justin 2026-06-02 21:54:06 -05:00
parent 501e417584
commit 843a5bfacb

View file

@ -302,6 +302,74 @@ class _B:
def page_break(self):
self.doc.add_page_break()
def section_rule(self, space_before=14, space_after=2):
"""A light divider between sections that share a page (no page break)."""
p = self.doc.add_paragraph()
p.paragraph_format.space_before = Pt(space_before)
p.paragraph_format.space_after = Pt(space_after)
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"), "4")
bottom.set(qn("w:space"), "1")
bottom.set(qn("w:color"), "DBE2EA")
pbdr.append(bottom)
pPr.append(pbdr)
return p
def _panel_into_cell(self, cell, title, lead, items):
"""Render a titled resource panel inside a table cell."""
cell.text = ""
tp = cell.paragraphs[0]
tp.paragraph_format.space_after = Pt(2)
tr = tp.add_run(title)
tr.bold = True
tr.font.size = Pt(11)
tr.font.color.rgb = NAVY
if lead:
lp = cell.add_paragraph()
lp.paragraph_format.space_after = Pt(3)
lr = lp.add_run(lead)
lr.italic = True
lr.font.size = Pt(8.5)
lr.font.color.rgb = SLATE
for it in items:
ip = cell.add_paragraph()
ip.paragraph_format.space_after = Pt(2)
ip.paragraph_format.left_indent = Inches(0.13)
ip.paragraph_format.first_line_indent = Inches(-0.13)
bullet = ip.add_run("\u2022 ")
bullet.font.size = Pt(9)
bullet.font.color.rgb = BLUE
_add_runs(ip, it)
for r in ip.runs[1:]:
r.font.size = Pt(9)
r.font.color.rgb = INK
def two_col_panels(self, panels):
"""Lay out (title, lead, [items]) panels in two columns, borderless."""
rows = (len(panels) + 1) // 2
t = self.doc.add_table(rows=rows, cols=2)
t.alignment = WD_TABLE_ALIGNMENT.CENTER
t.autofit = False
for col in t.columns:
for cell in col.cells:
cell.width = Inches(3.35)
for i, panel in enumerate(panels):
r, c = divmod(i, 2)
self._panel_into_cell(t.rows[r].cells[c], *panel)
tblPr = t._tbl.tblPr
borders = OxmlElement("w:tblBorders")
for edge in ("top", "left", "bottom", "right", "insideH", "insideV"):
el = OxmlElement(f"w:{edge}")
el.set(qn("w:val"), "none")
el.set(qn("w:sz"), "0")
el.set(qn("w:space"), "0")
borders.append(el)
tblPr.append(borders)
return t
def spacer(self, pts=8):
p = self.doc.add_paragraph()
p.paragraph_format.space_after = Pt(pts)
@ -322,6 +390,21 @@ class _B:
self.fill_line((label if i == 0 else "") +
" " + "_" * 78, gap=12)
def checkbox(self, text, *, size=10.5, gap=5, indent=0.3):
"""A checklist line beginning with an open box glyph."""
p = self.doc.add_paragraph()
p.paragraph_format.space_after = Pt(gap)
p.paragraph_format.left_indent = Inches(indent)
p.paragraph_format.first_line_indent = Inches(-0.22)
box = p.add_run("\u2750 ") # open ballot box
box.font.size = Pt(size + 1)
box.font.color.rgb = NAVY
_add_runs(p, text)
for r in p.runs[1:]:
r.font.size = Pt(size)
r.font.color.rgb = INK
return p
def generate_da_binder(
*,
@ -407,8 +490,14 @@ def generate_da_binder(
"maintaining its own program. Have counsel review before adoption.")
b.page_break()
# ── DER Quick-Start Checklist (tear-off first page) ─────────────────────
_der_quickstart(b, meta, der_name, der_title, provider_name, random_rate)
# ── Table of contents ───────────────────────────────────────────────────
b.h1("What's Inside This Binder")
b.body(
"Start with the **DER Quick-Start Checklist** on the previous page, "
"then use the sections below for the detail.")
b.bullets([
"**Section 1 — How to Manage Your Program.** Step-by-step setup and "
"ongoing operating instructions for the Designated Employer "
@ -434,6 +523,8 @@ def generate_da_binder(
"answers: owner-operators, audits and penalties, problem test results, "
"prescriptions/marijuana/CBD, what counts as a refusal, costs, and the "
"DER's do's and don'ts.",
"**Suggested Vendors & Resources.** A two-column directory of the "
"consortiums, labs, MRO/SAP, and training providers you'll need.",
])
if state_dfwp:
b.body(
@ -566,7 +657,7 @@ def generate_da_binder(
"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()
b.section_rule()
# ── Section 2 — Written policy ──────────────────────────────────────────
b.h1("Section 2 — Written Drug & Alcohol Testing Policy")
@ -686,7 +777,7 @@ def generate_da_binder(
"_______________________")
b.fill_line("Effective date: __________________ USDOT #: "
f"{dot_number or '________________'}")
b.page_break()
b.section_rule()
# ── Section 3 — When testing is required ───────────────────────────────
b.h1("Section 3 — When Testing Is Required")
@ -737,7 +828,7 @@ def generate_da_binder(
"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()
b.section_rule()
# ── Section 4 — Random testing ─────────────────────────────────────────
b.h1("Section 4 — Random Testing Program")
@ -773,7 +864,7 @@ def generate_da_binder(
"after the employee performs safety-sensitive functions.",
"Keep the consortium's selection and results records (Section 8).",
])
b.page_break()
b.section_rule()
# ── Section 5 — Supervisor training ────────────────────────────────────
b.h1("Section 5 — Supervisor Reasonable-Suspicion Training")
@ -819,7 +910,7 @@ def generate_da_binder(
"**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()
b.section_rule()
# ── Section 6 — Violations / SAP ───────────────────────────────────────
b.h1("Section 6 — Violations, SAP & Return-to-Duty")
@ -863,7 +954,7 @@ def generate_da_binder(
"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()
b.section_rule()
# ── Section 7 — EAP / rehab ────────────────────────────────────────────
b.h1("Section 7 — EAP, Rehab & Treatment Resources")
@ -904,7 +995,7 @@ def generate_da_binder(
"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()
b.section_rule()
# ── Section 8 — Recordkeeping ──────────────────────────────────────────
b.h1("Section 8 — Recordkeeping")
@ -935,7 +1026,7 @@ def generate_da_binder(
"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()
b.section_rule()
# ── Section 9 — Forms ──────────────────────────────────────────────────
b.h1("Section 9 — Required Compliance Forms")
@ -994,6 +1085,9 @@ def generate_da_binder(
# ── Section 11 — Practical guidance for the administrator ───────────────
_section_practical_guidance(b, meta, company, random_rate)
# ── Suggested vendors & resources (two-column) ──────────────────────────
_vendor_directory(b, meta)
# ── Optional state DFWP addendum ───────────────────────────────────────
if state_dfwp:
b.page_break()
@ -1028,9 +1122,78 @@ def generate_da_binder(
return str(out)
# ── DER Quick-Start Checklist (one-page tear-off) ───────────────────────────
def _der_quickstart(b, meta, der_name, der_title, provider_name, random_rate):
b.h1("DER Quick-Start Checklist")
b.body(
"A one-page summary for the Designated Employer Representative (DER). "
"Work top to bottom: do the SET-UP items once, then run the EVERY-HIRE "
"and ONGOING items continuously. Each item points to the section or "
"form with the detail. Tear this page out and keep it handy.",
italic=True)
b.h3("Set up once")
setup = [
"**Name the DER and a backup** (cover page). DER: "
f"{der_name or '____________________'}.",
"**Adopt & sign the written policy** (Section 2).",
f"**Join / confirm your consortium (C-TPA):** {provider_name} "
"(Sections 1 & 4).",
"**Train every supervisor** 120 minutes before any reasonable-suspicion "
"decision (Section 5; Form F).",
]
if meta.get("clearinghouse"):
setup.append(
"**Register with the FMCSA Clearinghouse** and designate your "
"C-TPA (Section 1).")
for item in setup:
b.checkbox(item)
b.h3("Every new hire (before they drive)")
hire = [
"**Collect driver info & add to the random pool** (Form G).",
"**Get signed Form A** (policy ack.) **and Form B** (consent / prior-"
"employer inquiry).",
]
if meta.get("clearinghouse"):
hire.append(
"**Run the Clearinghouse pre-employment full query** — confirm "
"**not prohibited**.")
hire += [
"**Send for the pre-employment drug test;** wait for the MRO **verified "
"negative** before any safety-sensitive work (Section 3).",
]
for item in hire:
b.checkbox(item)
b.h3("Ongoing")
ongoing = [
f"**Random testing** all year at {random_rate}; send selected drivers "
"**immediately**, no warning (Section 4).",
"**Reasonable suspicion** — trained supervisor documents it (Form D).",
"**Post-accident** — use the decision worksheet at the scene (Form E).",
"**Keep the roster current** (add hires, remove departures) (Form G).",
"**Act on any positive / 0.04+ / refusal the SAME day** — remove from "
"duty, start the SAP / return-to-duty process (Section 6).",
"**Keep records** confidential and for the required period (Section 8).",
]
if meta.get("clearinghouse"):
ongoing.append(
"**Annual Clearinghouse limited query** on every CDL driver; "
"**report** violations within the required timeframes (Section 1).")
for item in ongoing:
b.checkbox(item)
b.body(
"**Stuck or unsure?** See Section 11 (owner-operators, audits, problem "
"results, marijuana/CBD, refusals) or call your C-TPA/MRO. Questions: "
"compliance@performancewest.com.")
b.page_break()
# ── Section 11 — Practical guidance ─────────────────────────────────────────
def _section_practical_guidance(b, meta, company, random_rate):
b.page_break()
b.section_rule()
b.h1("Section 11 — Practical Guidance for the Administrator")
b.body(
"The regulations tell you what to do; this section covers the real-"
@ -1174,6 +1337,114 @@ def _section_practical_guidance(b, meta, company, random_rate):
])
# ── Suggested vendors & resources (two-column directory) ────────────────────
def _vendor_directory(b, meta):
b.page_break()
b.h1("Suggested Vendors & Resources")
b.body(
"Setting up your program means lining up a few service providers. The "
"panels below group the vendors a carrier typically needs, with "
"well-known national options as a starting point. These are examples "
"to help you shop, **not endorsements** — compare service, coverage, "
"and price, and confirm each provider meets DOT requirements. The "
"simplest path for most small carriers is a single Consortium/Third-"
"Party Administrator (C-TPA) that bundles the pool, scheduling, "
"collection network, lab, and MRO.", italic=True)
panels = [
(
"Consortium / C-TPA (bundles everything)",
"Manages your random pool, scheduling, collection, lab & MRO.",
[
"**Performance West** — managed program & C-TPA "
"(compliance@performancewest.com)",
"**National Drug Screening** — nationaldrugscreening.com",
"**US Drug Test Centers** — usdrugtestcenters.com",
"**Foundation / DISA Global Solutions** — disa.com",
"**National Compliance Management Service (NCMS)** — "
"ncmsmro.com",
],
),
(
"Collection sites & SAMHSA-certified labs",
"Where the specimen is collected and analyzed (DOT 5-panel).",
[
"**Quest Diagnostics** — questdiagnostics.com (nationwide "
"Patient Service Centers)",
"**Labcorp** — labcorp.com / labcorpdrugtesting.com",
"**Any Lab Test Now** — anylabtestnow.com",
"Your C-TPA assigns the nearest approved collection site.",
],
),
(
"Medical Review Officer (MRO)",
"Licensed physician who verifies non-negative results.",
[
"Usually **included with your C-TPA** — confirm before signing.",
"**American Association of MROs (AAMRO)** — aamro.com "
"(verify/locate an MRO)",
"**NCMS / NDS** MRO services (see C-TPA panel).",
],
),
(
"Substance Abuse Professional (SAP)",
"Required after a violation, for return-to-duty.",
[
"**DOT SAP locator & guidance** — transportation.gov/odapc",
"**SAPlist.com** — directory of qualified SAPs",
"Ask your C-TPA for SAP referrals in the driver's area.",
],
),
(
"Supervisor reasonable-suspicion training",
"120 minutes (60 alcohol + 60 drugs) before any decision.",
[
"**Performance West** supervisor training "
"(compliance@performancewest.com)",
"**J. J. Keller** — jjkeller.com",
"**National Drug Screening / US Drug Test Centers** online "
"courses (see C-TPA panel).",
],
),
]
if meta.get("clearinghouse"):
panels.append((
"FMCSA Clearinghouse (CDL drivers)",
"Register, designate your C-TPA, run queries, report violations.",
[
"**Official site** — clearinghouse.fmcsa.dot.gov",
"Your C-TPA can run queries and reporting on your behalf once "
"you designate them.",
"**FMCSA help** — 844-955-0207",
],
))
else:
panels.append((
"Official DOT / agency resources",
"Free, authoritative guidance and forms.",
[
f"**{meta['agency']}** rule: ecfr.gov (search the part number)",
"**DOT ODAPC** — transportation.gov/odapc",
],
))
panels.append((
"Help & treatment (for employees)",
"Give these to employees with the policy (Section 7).",
[
"**SAMHSA Helpline** — 1-800-662-HELP (4357), 24/7",
"**findtreatment.gov** — treatment locator",
"**988** Suicide & Crisis Lifeline (call/text)",
],
))
b.two_col_panels(panels)
b.small(
"Listing a provider here is not an endorsement and Performance West "
"receives no fee for these listings unless noted. Verify current "
"pricing, coverage, and DOT compliance directly with each vendor. "
"Need help choosing? Email compliance@performancewest.com.")
# ── Header / footer ─────────────────────────────────────────────────────────
def _add_header_footer(doc, meta, carrier_name):
section = doc.sections[0]