new-site/scripts/templates/create_templates.py
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

1355 lines
52 KiB
Python

"""
Performance West — DOCX Template Generator
Generates all DOCX templates used by the document generation pipeline.
Each template contains Jinja2 placeholders ({{ variable_name }}) that are
filled at runtime by DocxBuilder.
Usage:
python scripts/templates/create_templates.py
Output:
scripts/templates/*.docx (9 template files)
After generation, upload templates to MinIO:
mc cp scripts/templates/*.docx minio/performancewest/templates/
"""
from __future__ import annotations
import os
import sys
from pathlib import Path
from docx import Document
from docx.shared import Inches, Pt, RGBColor, Cm, Emu
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.section import WD_ORIENT
from docx.oxml.ns import qn, nsdecls
from docx.oxml import parse_xml
# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------
OUTPUT_DIR = Path(__file__).parent
COMPANY_NAME = "Performance West Inc."
COMPANY_ADDRESS = "525 Randall Ave Ste 100-1195, Cheyenne, WY 82001"
COMPANY_PHONE = "1-888-411-0383"
COMPANY_WEBSITE = "performancewest.net"
# Brand colors
NAVY = RGBColor(0x2D, 0x4E, 0x78) # pw-700
DARK_NAVY = RGBColor(0x1A, 0x36, 0x5D) # pw-900
LIGHT_GRAY = RGBColor(0x9C, 0xA3, 0xAF)
MEDIUM_GRAY = RGBColor(0x6B, 0x72, 0x80)
BLACK = RGBColor(0x00, 0x00, 0x00)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
CONFIDENTIALITY_NOTICE = (
"CONFIDENTIAL — This document is prepared by Performance West Inc. for the "
"exclusive use of the intended recipient. It does not constitute legal advice. "
"Unauthorized distribution is prohibited."
)
DISCLAIMER = (
"DISCLAIMER: This document is prepared by Performance West Inc. for compliance "
"consulting purposes only. It does not constitute legal advice, legal "
"representation, or create an attorney-client relationship. For legal matters, "
"consult a licensed attorney in your jurisdiction."
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def set_cell_shading(cell, color_hex: str):
"""Set background shading on a table cell."""
shading = parse_xml(
f'<w:shd {nsdecls("w")} w:fill="{color_hex}" w:val="clear"/>'
)
cell._tc.get_or_add_tcPr().append(shading)
def add_page_number(footer):
"""Add 'Page X of Y' field to a footer."""
para = footer.paragraphs[0] if footer.paragraphs else footer.add_paragraph()
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
# "Page "
run = para.add_run("Page ")
run.font.size = Pt(8)
run.font.color.rgb = LIGHT_GRAY
# PAGE field
fld_char_begin = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="begin"/>')
run_page = para.add_run()
run_page._r.append(fld_char_begin)
instr = parse_xml(f'<w:instrText {nsdecls("w")} xml:space="preserve"> PAGE </w:instrText>')
run_page2 = para.add_run()
run_page2._r.append(instr)
fld_char_end = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="end"/>')
run_page3 = para.add_run()
run_page3._r.append(fld_char_end)
# " of "
run_of = para.add_run(" of ")
run_of.font.size = Pt(8)
run_of.font.color.rgb = LIGHT_GRAY
# NUMPAGES field
fld_char_begin2 = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="begin"/>')
run_np = para.add_run()
run_np._r.append(fld_char_begin2)
instr2 = parse_xml(f'<w:instrText {nsdecls("w")} xml:space="preserve"> NUMPAGES </w:instrText>')
run_np2 = para.add_run()
run_np2._r.append(instr2)
fld_char_end2 = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="end"/>')
run_np3 = para.add_run()
run_np3._r.append(fld_char_end2)
def setup_document(title: str) -> Document:
"""Create a new Document with standard Performance West formatting."""
doc = Document()
# -- Default font: Times New Roman 11pt --
style = doc.styles["Normal"]
style.font.name = "Times New Roman"
style.font.size = Pt(11)
style.font.color.rgb = BLACK
style.paragraph_format.space_after = Pt(6)
style.paragraph_format.line_spacing = 1.15
# -- Heading styles --
for level in range(1, 4):
h = doc.styles[f"Heading {level}"]
h.font.name = "Times New Roman"
h.font.color.rgb = NAVY
h.font.bold = True
if level == 1:
h.font.size = Pt(18)
h.paragraph_format.space_before = Pt(18)
h.paragraph_format.space_after = Pt(12)
elif level == 2:
h.font.size = Pt(14)
h.paragraph_format.space_before = Pt(14)
h.paragraph_format.space_after = Pt(8)
else:
h.font.size = Pt(12)
h.paragraph_format.space_before = Pt(10)
h.paragraph_format.space_after = Pt(6)
# -- Margins --
for section in doc.sections:
section.top_margin = Cm(2.54)
section.bottom_margin = Cm(2.54)
section.left_margin = Cm(2.54)
section.right_margin = Cm(2.54)
# -- Header --
header = doc.sections[0].header
header.is_linked_to_previous = False
h_para = header.paragraphs[0] if header.paragraphs else header.add_paragraph()
h_para.alignment = WD_ALIGN_PARAGRAPH.RIGHT
run = h_para.add_run(COMPANY_NAME)
run.font.size = Pt(9)
run.font.color.rgb = NAVY
run.font.bold = True
run2 = h_para.add_run(f" | {COMPANY_PHONE}")
run2.font.size = Pt(8)
run2.font.color.rgb = LIGHT_GRAY
# -- Footer --
footer = doc.sections[0].footer
footer.is_linked_to_previous = False
# Confidentiality notice
conf_para = footer.add_paragraph()
conf_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
conf_run = conf_para.add_run(CONFIDENTIALITY_NOTICE)
conf_run.font.size = Pt(7)
conf_run.font.italic = True
conf_run.font.color.rgb = LIGHT_GRAY
# Page number
add_page_number(footer)
return doc
def add_cover_page(doc: Document, title: str, placeholders: dict[str, str]):
"""Add a branded cover page with Jinja2 placeholders."""
# Spacer
spacer = doc.add_paragraph()
spacer.space_after = Pt(72)
# Title
title_para = doc.add_paragraph()
title_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
title_run = title_para.add_run(title)
title_run.font.size = Pt(28)
title_run.font.color.rgb = NAVY
title_run.font.bold = True
# Placeholders on cover
for label, placeholder in placeholders.items():
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = p.add_run(f"{label}: {placeholder}")
r.font.size = Pt(12)
r.font.color.rgb = MEDIUM_GRAY
# Branding
brand = doc.add_paragraph()
brand.space_before = Pt(48)
brand.alignment = WD_ALIGN_PARAGRAPH.CENTER
br = brand.add_run(COMPANY_NAME)
br.font.size = Pt(10)
br.font.color.rgb = NAVY
addr = doc.add_paragraph()
addr.alignment = WD_ALIGN_PARAGRAPH.CENTER
ar = addr.add_run(f"{COMPANY_ADDRESS} | {COMPANY_PHONE}")
ar.font.size = Pt(8)
ar.font.color.rgb = LIGHT_GRAY
doc.add_page_break()
def add_article(doc: Document, number: int, title: str, body_lines: list[str]):
"""Add an article/section with heading and body paragraphs."""
doc.add_heading(f"Article {number}: {title}", level=1)
for line in body_lines:
doc.add_paragraph(line)
def add_section(doc: Document, title: str, body_lines: list[str], level: int = 1):
"""Add a section with heading and body paragraphs."""
doc.add_heading(title, level=level)
for line in body_lines:
doc.add_paragraph(line)
def add_signature_block(doc: Document, signer_label: str = "{{ member_name }}"):
"""Add a signature line."""
doc.add_paragraph("")
p = doc.add_paragraph()
p.add_run("_" * 50)
name_p = doc.add_paragraph()
r = name_p.add_run(signer_label)
r.font.size = Pt(11)
date_p = doc.add_paragraph()
date_p.add_run("Date: ____________________")
def add_table(doc: Document, headers: list[str], rows: list[list[str]]):
"""Add a formatted table."""
table = doc.add_table(rows=1 + len(rows), cols=len(headers))
table.alignment = WD_TABLE_ALIGNMENT.CENTER
# Header row
for i, header in enumerate(headers):
cell = table.rows[0].cells[i]
cell.text = header
for para in cell.paragraphs:
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
for run in para.runs:
run.font.bold = True
run.font.color.rgb = WHITE
run.font.size = Pt(10)
set_cell_shading(cell, "2D4E78")
# Data rows
for r_idx, row in enumerate(rows):
for c_idx, text in enumerate(row):
cell = table.rows[r_idx + 1].cells[c_idx]
cell.text = text
for para in cell.paragraphs:
for run in para.runs:
run.font.size = Pt(10)
return table
def add_disclaimer(doc: Document):
"""Add the standard disclaimer at the end."""
doc.add_paragraph("")
p = doc.add_paragraph()
r = p.add_run(DISCLAIMER)
r.font.size = Pt(8)
r.font.italic = True
r.font.color.rgb = LIGHT_GRAY
def save_template(doc: Document, name: str):
"""Save a template to the output directory."""
path = OUTPUT_DIR / f"{name}.docx"
doc.save(str(path))
print(f" Created: {path}")
# ---------------------------------------------------------------------------
# Template Generators
# ---------------------------------------------------------------------------
def create_operating_agreement():
"""Generate the standard LLC Operating Agreement template."""
doc = setup_document("Operating Agreement")
add_cover_page(doc, "Operating Agreement", {
"Entity": "{{ entity_name }}",
"State": "{{ state_name }}",
"Formation Date": "{{ formation_date }}",
})
doc.add_heading("Operating Agreement of {{ entity_name }}", level=1)
doc.add_paragraph(
"This Operating Agreement (the \"Agreement\") of {{ entity_name }}, "
"a limited liability company organized under the laws of the State of "
"{{ state_name }}, is entered into and effective as of {{ formation_date }}, "
"by and among the Members identified herein."
)
# Article I: Formation
add_article(doc, 1, "Formation", [
"1.1 Name. The name of the Company is {{ entity_name }}.",
"1.2 Formation. The Company was formed on {{ formation_date }} by filing "
"Articles of Organization with the Secretary of State of {{ state_name }}.",
"1.3 Principal Office. The principal office of the Company shall be at "
"{{ principal_address }}.",
"1.4 Registered Agent. The Company's registered agent is {{ registered_agent }} "
"at {{ registered_agent_address }}.",
"1.5 Term. The Company shall continue until dissolved in accordance with this "
"Agreement or applicable law.",
"1.6 Purpose. The Company is formed for any lawful purpose permitted under "
"the laws of the State of {{ state_name }}.",
])
# Article II: Members
add_article(doc, 2, "Members", [
"2.1 Initial Members. The initial Members of the Company and their respective "
"ownership interests are as follows:",
])
add_table(doc,
["Member Name", "Ownership %", "Capital Contribution", "Membership Units"],
[
["{{ members[0].name }}", "{{ members[0].ownership_pct }}", "{{ members[0].capital }}", "{{ members[0].units }}"],
["{{ members[1].name }}", "{{ members[1].ownership_pct }}", "{{ members[1].capital }}", "{{ members[1].units }}"],
],
)
doc.add_paragraph(
"{% for member in members %}\n"
"{{ member.name }} — {{ member.ownership_pct }}% ownership\n"
"{% endfor %}"
)
# Article III: Management
add_article(doc, 3, "Management", [
"3.1 Management Structure. The Company shall be {{ management_type }}-managed.",
"3.2 Manager(s). {% if management_type == 'manager' %}The Manager(s) of the Company "
"shall be {{ managers }}.{% else %}All Members shall have the authority to manage the "
"business and affairs of the Company.{% endif %}",
"3.3 Voting. Each Member shall have voting rights proportional to their ownership "
"interest. Decisions requiring a vote shall be decided by a majority of ownership "
"interests, unless otherwise specified in this Agreement.",
"3.4 Officers. The Manager(s) or Members may appoint officers as needed.",
])
# Article IV: Capital Contributions
add_article(doc, 4, "Capital Contributions", [
"4.1 Initial Contributions. Each Member shall contribute the amount set forth "
"in Article 2.",
"4.2 Additional Contributions. No Member shall be required to make additional "
"capital contributions without the unanimous consent of all Members.",
"4.3 No Interest. No interest shall be paid on capital contributions.",
"4.4 Capital Accounts. A separate capital account shall be maintained for each "
"Member in accordance with applicable tax regulations.",
])
# Article V: Distributions
add_article(doc, 5, "Distributions", [
"5.1 Distributions. Distributions shall be made at such times and in such "
"amounts as determined by the Members. Distributions shall be allocated to "
"Members in proportion to their ownership interests.",
"5.2 Tax Distributions. The Company shall make quarterly tax distributions "
"to the Members sufficient to cover their estimated tax liability arising "
"from Company income.",
])
# Article VI: Meetings
add_article(doc, 6, "Meetings", [
"6.1 Annual Meeting. The Members shall hold an annual meeting at a time "
"and place determined by the Members.",
"6.2 Special Meetings. Any Member may call a special meeting with at least "
"10 days' written notice to all other Members.",
"6.3 Quorum. A quorum shall consist of Members holding a majority of the "
"total ownership interests.",
"6.4 Action Without Meeting. Any action that may be taken at a meeting may "
"be taken without a meeting if the Members holding the required votes consent "
"in writing.",
])
# Article VII: Transfer of Interest
add_article(doc, 7, "Transfer of Interest", [
"7.1 Restriction on Transfer. No Member may sell, assign, transfer, or "
"encumber their membership interest without the prior written consent of "
"Members holding a majority of the remaining ownership interests.",
"7.2 Right of First Refusal. Before any transfer, the selling Member must "
"first offer their interest to the remaining Members on the same terms.",
"7.3 Permitted Transfers. A Member may transfer their interest to a trust "
"for the benefit of the Member or the Member's immediate family without "
"the consent of other Members.",
])
# Article VIII: Dissolution
add_article(doc, 8, "Dissolution", [
"8.1 Events of Dissolution. The Company shall dissolve upon: (a) the written "
"consent of Members holding a majority of ownership interests; (b) the entry "
"of a judicial decree of dissolution; or (c) any event that makes it unlawful "
"for the Company to continue.",
"8.2 Winding Up. Upon dissolution, the Company's affairs shall be wound up "
"in accordance with applicable law. Assets shall be distributed in the "
"following order: (a) to creditors; (b) to Members for unreturned capital "
"contributions; (c) to Members in proportion to ownership interests.",
])
# Article IX: Miscellaneous
add_article(doc, 9, "Miscellaneous", [
"9.1 Governing Law. This Agreement shall be governed by the laws of the "
"State of {{ state_name }}.",
"9.2 Amendments. This Agreement may be amended only by the written consent "
"of Members holding a majority of ownership interests.",
"9.3 Severability. If any provision of this Agreement is found invalid, "
"the remaining provisions shall remain in full force and effect.",
"9.4 Entire Agreement. This Agreement constitutes the entire agreement among "
"the Members and supersedes all prior agreements.",
"9.5 Indemnification. The Company shall indemnify each Member and Manager "
"against all liabilities incurred in connection with Company business, "
"except for willful misconduct or gross negligence.",
])
# Article X: Signatures
add_article(doc, 10, "Signatures", [
"IN WITNESS WHEREOF, the undersigned Members have executed this Operating "
"Agreement as of the date first written above.",
])
doc.add_paragraph(
"{% for member in members %}"
)
add_signature_block(doc, "{{ member.name }}")
doc.add_paragraph(
"{% endfor %}"
)
add_disclaimer(doc)
save_template(doc, "operating-agreement")
def create_privacy_policy():
"""Generate the Website Privacy Policy template."""
doc = setup_document("Privacy Policy")
add_cover_page(doc, "Privacy Policy", {
"Company": "{{ company_name }}",
"Website": "{{ website_url }}",
"Effective Date": "{{ effective_date }}",
})
doc.add_heading("Privacy Policy", level=1)
doc.add_paragraph(
"Last updated: {{ effective_date }}"
)
doc.add_paragraph(
"{{ company_name }} (\"Company,\" \"we,\" \"us,\" or \"our\") operates the "
"website {{ website_url }} (the \"Site\"). This Privacy Policy explains how "
"we collect, use, disclose, and safeguard your information when you visit "
"our Site."
)
add_section(doc, "1. Information We Collect", [
"We collect information that you provide directly to us, including:",
"- Name, email address, phone number, and mailing address",
"- Company name and business information",
"- Payment information (processed securely by third-party processors)",
"- Communications you send to us (e.g., support requests)",
"",
"We automatically collect certain information when you visit our Site:",
"- IP address and browser type",
"- Pages viewed and time spent on each page",
"- Referring website or search terms",
"- Device information and operating system",
])
add_section(doc, "2. How We Use Your Information", [
"We use collected information to:",
"- Process orders and provide requested services",
"- Communicate with you about your account or services",
"- Send marketing communications (with your consent)",
"- Improve our website and services",
"- Comply with legal obligations",
"- Detect and prevent fraud",
])
add_section(doc, "3. Information Sharing", [
"We do not sell your personal information. We may share information with:",
"- Service providers who assist in operating our business",
"- State agencies as required for business formation services",
"- Legal authorities when required by law",
"- Business partners with your explicit consent",
])
add_section(doc, "4. California Privacy Rights (CCPA/CPRA)", [
"{{ ccpa_section }}",
])
add_section(doc, "5. Cookies and Tracking", [
"We use cookies and similar technologies to:",
"- Maintain your session and preferences",
"- Analyze site usage (via privacy-respecting analytics)",
"- Improve site performance",
"",
"You may disable cookies in your browser settings. Some site features may "
"not function properly without cookies.",
])
add_section(doc, "6. Data Security", [
"We implement reasonable administrative, technical, and physical security "
"measures to protect your personal information, including:",
"- Encryption of data in transit (TLS) and at rest",
"- Access controls and authentication requirements",
"- Regular security assessments",
"",
"No method of transmission over the Internet is 100% secure. We cannot "
"guarantee absolute security of your data.",
])
add_section(doc, "7. Children's Privacy", [
"Our Site is not directed to individuals under 13 years of age. We do not "
"knowingly collect personal information from children under 13. If we learn "
"we have collected such information, we will take steps to delete it.",
])
add_section(doc, "8. Changes to This Policy", [
"We may update this Privacy Policy from time to time. We will notify you of "
"any material changes by posting the new policy on our Site with a revised "
"effective date.",
])
add_section(doc, "9. Contact Us", [
"If you have questions about this Privacy Policy, contact us at:",
"",
"{{ company_name }}",
"{{ physical_address }}",
"Email: {{ contact_email }}",
])
add_disclaimer(doc)
save_template(doc, "privacy-policy")
def create_breach_response_plan():
"""Generate the Data Breach Response Plan template."""
doc = setup_document("Data Breach Response Plan")
add_cover_page(doc, "Data Breach Response Plan", {
"Company": "{{ company_name }}",
"Contact": "{{ contact_name }}",
})
doc.add_heading("Data Breach Response Plan", level=1)
doc.add_paragraph(
"Prepared for {{ company_name }}"
)
add_section(doc, "1. Purpose", [
"This Data Breach Response Plan (\"Plan\") establishes procedures for "
"{{ company_name }} to follow in the event of a suspected or confirmed data "
"breach involving personal information. The Plan is designed to ensure rapid "
"containment, thorough investigation, timely notification, and effective "
"remediation.",
])
add_section(doc, "2. Scope", [
"This Plan applies to all employees, contractors, and agents of "
"{{ company_name }} who create, receive, maintain, or transmit personal "
"information. It covers all forms of personal information, whether in "
"electronic or physical form.",
])
add_section(doc, "3. Incident Response Team (IRT)", [
"The following individuals comprise the Incident Response Team:",
])
add_table(doc,
["Role", "Name", "Phone", "Email"],
[
["IRT Lead", "{{ irt_members[0].name }}", "{{ irt_members[0].phone }}", "{{ irt_members[0].email }}"],
["IT Security", "{{ irt_members[1].name }}", "{{ irt_members[1].phone }}", "{{ irt_members[1].email }}"],
["Legal Counsel", "{{ irt_members[2].name }}", "{{ irt_members[2].phone }}", "{{ irt_members[2].email }}"],
["Communications", "{{ irt_members[3].name }}", "{{ irt_members[3].phone }}", "{{ irt_members[3].email }}"],
],
)
add_section(doc, "4. Incident Classification", [
"Incidents shall be classified by severity:",
"",
"Level 1 (Low): Suspected but unconfirmed breach with no evidence of data "
"exfiltration. Fewer than 100 records potentially affected.",
"",
"Level 2 (Medium): Confirmed breach with limited data exposure. 100-1,000 "
"records affected. No financial or health data involved.",
"",
"Level 3 (High): Confirmed breach involving sensitive data (SSN, financial, "
"health). More than 1,000 records affected, or any number of records "
"involving highly sensitive data.",
"",
"Level 4 (Critical): Large-scale breach affecting more than 10,000 records, "
"or involving data that poses immediate risk of identity theft or financial harm.",
])
add_section(doc, "5. Response Procedures", [
"5.1 Discovery and Reporting",
"Any employee who suspects a data breach must immediately notify the IRT Lead "
"at {{ contact_name }}. Do not attempt to investigate independently or "
"communicate externally about the incident.",
"",
"5.2 Containment (0-4 hours)",
"- Isolate affected systems from the network",
"- Preserve forensic evidence (do not wipe or rebuild)",
"- Change compromised credentials",
"- Engage IT Security for initial assessment",
"",
"5.3 Investigation (4-48 hours)",
"- Determine the type and scope of data compromised",
"- Identify the attack vector or root cause",
"- Assess the number of affected individuals",
"- Document all findings in the incident log",
"",
"5.4 Eradication and Recovery (48-72 hours)",
"- Remove the cause of the breach",
"- Patch vulnerabilities",
"- Restore systems from clean backups",
"- Verify system integrity before returning to production",
])
add_section(doc, "6. Notification Requirements", [
"Notification timelines and requirements vary by state. The following "
"summarizes requirements for states where {{ company_name }} operates:",
"",
"{{ state_notification_requirements }}",
])
add_table(doc,
["State", "Notification Deadline", "AG Notification", "Threshold"],
[
["{{ state_reqs[0].state }}", "{{ state_reqs[0].deadline }}", "{{ state_reqs[0].ag_notify }}", "{{ state_reqs[0].threshold }}"],
["{{ state_reqs[1].state }}", "{{ state_reqs[1].deadline }}", "{{ state_reqs[1].ag_notify }}", "{{ state_reqs[1].threshold }}"],
],
)
add_section(doc, "7. Communication Templates", [
"7.1 Individual Notification Letter",
"A template notification letter is maintained as Appendix A and shall be "
"customized for each incident based on the type of data compromised.",
"",
"7.2 Regulator Notification",
"Attorney General notifications shall follow the format specified by each "
"state's data breach notification statute.",
"",
"7.3 Media Statement",
"Public statements shall be reviewed by Legal Counsel and Communications "
"before release.",
])
add_section(doc, "8. Post-Incident Review", [
"Within 30 days of incident resolution, the IRT shall conduct a "
"post-incident review covering:",
"- Timeline of events",
"- Effectiveness of response procedures",
"- Root cause analysis",
"- Lessons learned and recommendations",
"- Updates to this Plan",
])
add_disclaimer(doc)
save_template(doc, "breach-response-plan")
def create_flsa_audit_report():
"""Generate the FLSA/Wage & Hour Audit Report template."""
doc = setup_document("FLSA Audit Report")
add_cover_page(doc, "FLSA / Wage & Hour\nAudit Report", {
"Company": "{{ company_name }}",
"Audit Date": "{{ audit_date }}",
"Employees Reviewed": "{{ employee_count }}",
})
doc.add_heading("FLSA / Wage & Hour Audit Report", level=1)
doc.add_paragraph("Prepared for {{ company_name }} | {{ audit_date }}")
add_section(doc, "1. Executive Summary", [
"{{ executive_summary }}",
])
add_section(doc, "2. Scope and Methodology", [
"This audit reviewed {{ company_name }}'s compliance with the Fair Labor "
"Standards Act (FLSA) and applicable state wage and hour laws. The review "
"encompassed {{ employee_count }} employees across all departments.",
"",
"The audit methodology included:",
"- Review of employee classification records (exempt vs. non-exempt)",
"- Analysis of overtime calculation and payment practices",
"- Examination of timekeeping and recordkeeping procedures",
"- Review of pay stubs and payroll records",
"- Interviews with HR personnel and department managers",
])
add_section(doc, "3. Employee Classification Analysis", [
"{{ classification_analysis }}",
])
add_table(doc,
["Position", "Current Classification", "Recommended Classification", "Risk Level"],
[
["{{ positions[0].title }}", "{{ positions[0].current }}", "{{ positions[0].recommended }}", "{{ positions[0].risk }}"],
["{{ positions[1].title }}", "{{ positions[1].current }}", "{{ positions[1].recommended }}", "{{ positions[1].risk }}"],
],
)
add_section(doc, "4. Overtime Compliance Analysis", [
"{{ overtime_analysis }}",
])
add_section(doc, "5. Recordkeeping Review", [
"{{ recordkeeping_review }}",
])
add_table(doc,
["Requirement", "Status", "Finding", "Priority"],
[
["Time records maintained", "{{ records[0].status }}", "{{ records[0].finding }}", "{{ records[0].priority }}"],
["Wage notices provided", "{{ records[1].status }}", "{{ records[1].finding }}", "{{ records[1].priority }}"],
["Pay stubs compliant", "{{ records[2].status }}", "{{ records[2].finding }}", "{{ records[2].priority }}"],
],
)
add_section(doc, "6. Remediation Plan", [
"{{ remediation_plan }}",
])
add_table(doc,
["Finding", "Action Required", "Responsible Party", "Deadline", "Priority"],
[
["{{ actions[0].finding }}", "{{ actions[0].action }}", "{{ actions[0].owner }}", "{{ actions[0].deadline }}", "{{ actions[0].priority }}"],
["{{ actions[1].finding }}", "{{ actions[1].action }}", "{{ actions[1].owner }}", "{{ actions[1].deadline }}", "{{ actions[1].priority }}"],
],
)
add_disclaimer(doc)
save_template(doc, "flsa-audit-report")
def create_contractor_assessment():
"""Generate the Contractor Classification Assessment template."""
doc = setup_document("Contractor Classification Assessment")
add_cover_page(doc, "Independent Contractor\nClassification Assessment", {
"Company": "{{ company_name }}",
"Worker": "{{ worker_name }}",
"Assessment Date": "{{ assessment_date }}",
})
doc.add_heading("Independent Contractor Classification Assessment", level=1)
doc.add_paragraph(
"Assessment of {{ worker_name }} for {{ company_name }} | {{ assessment_date }}"
)
add_section(doc, "1. Worker Information", [
"Worker Name: {{ worker_name }}",
"Engagement Start Date: {{ engagement_start }}",
"Job Title/Role: {{ job_title }}",
"Current Classification: {{ current_classification }}",
"Compensation Structure: {{ compensation_structure }}",
])
add_section(doc, "2. IRS 20-Factor Analysis", [
"The IRS uses a 20-factor test (Revenue Ruling 87-41) to determine worker "
"classification. The following analysis applies these factors to the "
"engagement between {{ company_name }} and {{ worker_name }}.",
"",
"{{ irs_analysis }}",
])
add_table(doc,
["Factor", "Description", "Indicates", "Notes"],
[
["1. Instructions", "Level of control over how work is done", "{{ irs_factors[0].indicates }}", "{{ irs_factors[0].notes }}"],
["2. Training", "Whether company provides training", "{{ irs_factors[1].indicates }}", "{{ irs_factors[1].notes }}"],
["3. Integration", "Integration into business operations", "{{ irs_factors[2].indicates }}", "{{ irs_factors[2].notes }}"],
],
)
add_section(doc, "3. DOL Economic Reality Test", [
"The Department of Labor uses the economic reality test to determine whether "
"a worker is an employee under the FLSA.",
"",
"{{ dol_analysis }}",
])
add_section(doc, "4. State-Specific Analysis", [
"{{ state_analysis }}",
])
add_section(doc, "5. Risk Assessment", [
"Overall Risk Level: {{ risk_level }}",
"",
"Factors contributing to risk assessment:",
"{{ risk_factors }}",
])
add_section(doc, "6. Recommendation", [
"{{ recommendation }}",
])
add_section(doc, "7. Next Steps", [
"If reclassification is recommended:",
"- Calculate back taxes and benefits owed",
"- Prepare amended tax filings (Form 941-X, Form W-2c)",
"- Update employment agreements and policies",
"- Implement prospective changes within 30 days",
"",
"If current classification is appropriate:",
"- Document supporting factors",
"- Review and update independent contractor agreement",
"- Schedule periodic reassessment (recommended annually)",
])
add_disclaimer(doc)
save_template(doc, "contractor-assessment")
def create_handbook_review():
"""Generate the Employee Handbook Review Report template."""
doc = setup_document("Employee Handbook Review Report")
add_cover_page(doc, "Employee Handbook\nReview Report", {
"Company": "{{ company_name }}",
"Review Date": "{{ review_date }}",
})
doc.add_heading("Employee Handbook Review Report", level=1)
doc.add_paragraph("Prepared for {{ company_name }} | {{ review_date }}")
add_section(doc, "1. Executive Summary", [
"{{ summary }}",
])
add_section(doc, "2. Review Methodology", [
"This review assessed {{ company_name }}'s employee handbook against:",
"- Federal employment law requirements (FLSA, FMLA, ADA, Title VII, OSHA)",
"- State-specific employment law requirements",
"- Industry best practices for employee handbooks",
"- Recent regulatory changes and court decisions",
"",
"Each policy was evaluated for legal compliance, clarity, completeness, "
"and consistency with actual company practices.",
])
add_section(doc, "3. Detailed Findings", [
"{{ findings }}",
])
add_table(doc,
["Policy Area", "Status", "Finding", "Severity", "Reference"],
[
["{{ finding_items[0].area }}", "{{ finding_items[0].status }}", "{{ finding_items[0].finding }}", "{{ finding_items[0].severity }}", "{{ finding_items[0].reference }}"],
["{{ finding_items[1].area }}", "{{ finding_items[1].status }}", "{{ finding_items[1].finding }}", "{{ finding_items[1].severity }}", "{{ finding_items[1].reference }}"],
],
)
add_section(doc, "4. Gap Analysis", [
"The following required policies are missing from the current handbook:",
"",
"{{ gap_analysis }}",
])
add_table(doc,
["Required Policy", "Legal Basis", "Priority", "Template Available"],
[
["{{ gaps[0].policy }}", "{{ gaps[0].legal_basis }}", "{{ gaps[0].priority }}", "{{ gaps[0].template }}"],
["{{ gaps[1].policy }}", "{{ gaps[1].legal_basis }}", "{{ gaps[1].priority }}", "{{ gaps[1].template }}"],
],
)
add_section(doc, "5. Recommendations", [
"{{ recommendations }}",
])
add_section(doc, "6. Prioritized Action Plan", [
"Critical (within 30 days):",
"{{ critical_items }}",
"",
"High (within 60 days):",
"{{ high_items }}",
"",
"Medium (within 90 days):",
"{{ medium_items }}",
"",
"Low (within 180 days):",
"{{ low_items }}",
])
add_disclaimer(doc)
save_template(doc, "handbook-review")
def create_ccpa_audit_report():
"""Generate the CCPA/CPRA Compliance Audit Report template."""
doc = setup_document("CCPA/CPRA Compliance Audit Report")
add_cover_page(doc, "CCPA/CPRA Compliance\nAudit Report", {
"Company": "{{ company_name }}",
"Audit Date": "{{ audit_date }}",
})
doc.add_heading("CCPA/CPRA Compliance Audit Report", level=1)
doc.add_paragraph("Prepared for {{ company_name }} | {{ audit_date }}")
add_section(doc, "1. Executive Summary", [
"{{ executive_summary }}",
])
add_section(doc, "2. Applicability Assessment", [
"The California Consumer Privacy Act (CCPA), as amended by the California "
"Privacy Rights Act (CPRA), applies to for-profit businesses that:",
"- Have annual gross revenue exceeding $25 million",
"- Buy, sell, or share the personal information of 100,000+ California "
"residents, households, or devices",
"- Derive 50% or more of annual revenue from selling/sharing personal information",
"",
"Assessment of {{ company_name }}'s applicability:",
"{{ applicability_assessment }}",
])
add_section(doc, "3. Data Inventory", [
"{{ data_inventory }}",
])
add_table(doc,
["Data Category", "Collected", "Source", "Purpose", "Shared With", "Retention"],
[
["{{ inventory[0].category }}", "{{ inventory[0].collected }}", "{{ inventory[0].source }}", "{{ inventory[0].purpose }}", "{{ inventory[0].shared }}", "{{ inventory[0].retention }}"],
["{{ inventory[1].category }}", "{{ inventory[1].collected }}", "{{ inventory[1].source }}", "{{ inventory[1].purpose }}", "{{ inventory[1].shared }}", "{{ inventory[1].retention }}"],
],
)
add_section(doc, "4. Privacy Notice Review", [
"{{ privacy_notice_review }}",
])
add_table(doc,
["Requirement", "Status", "Finding", "Recommendation"],
[
["Notice at collection", "{{ notice[0].status }}", "{{ notice[0].finding }}", "{{ notice[0].recommendation }}"],
["Right to know", "{{ notice[1].status }}", "{{ notice[1].finding }}", "{{ notice[1].recommendation }}"],
["Right to delete", "{{ notice[2].status }}", "{{ notice[2].finding }}", "{{ notice[2].recommendation }}"],
["Right to opt-out", "{{ notice[3].status }}", "{{ notice[3].finding }}", "{{ notice[3].recommendation }}"],
["Right to correct", "{{ notice[4].status }}", "{{ notice[4].finding }}", "{{ notice[4].recommendation }}"],
["Right to limit use", "{{ notice[5].status }}", "{{ notice[5].finding }}", "{{ notice[5].recommendation }}"],
],
)
add_section(doc, "5. Consumer Rights Assessment", [
"{{ consumer_rights_assessment }}",
])
add_section(doc, "6. Vendor/Service Provider Assessment", [
"{{ vendor_assessment }}",
])
add_table(doc,
["Vendor", "Data Shared", "DPA in Place", "CCPA Clause", "Risk Level"],
[
["{{ vendors[0].name }}", "{{ vendors[0].data }}", "{{ vendors[0].dpa }}", "{{ vendors[0].ccpa_clause }}", "{{ vendors[0].risk }}"],
["{{ vendors[1].name }}", "{{ vendors[1].data }}", "{{ vendors[1].dpa }}", "{{ vendors[1].ccpa_clause }}", "{{ vendors[1].risk }}"],
],
)
add_section(doc, "7. Remediation Plan", [
"{{ remediation_plan }}",
])
add_table(doc,
["Finding", "Action Required", "Owner", "Deadline", "Status"],
[
["{{ ccpa_actions[0].finding }}", "{{ ccpa_actions[0].action }}", "{{ ccpa_actions[0].owner }}", "{{ ccpa_actions[0].deadline }}", "{{ ccpa_actions[0].status }}"],
["{{ ccpa_actions[1].finding }}", "{{ ccpa_actions[1].action }}", "{{ ccpa_actions[1].owner }}", "{{ ccpa_actions[1].deadline }}", "{{ ccpa_actions[1].status }}"],
],
)
add_disclaimer(doc)
save_template(doc, "ccpa-audit-report")
def create_tcpa_audit_report():
"""Generate the TCPA Consent Audit Report template."""
doc = setup_document("TCPA Consent Audit Report")
add_cover_page(doc, "TCPA Consent\nAudit Report", {
"Company": "{{ company_name }}",
"Audit Date": "{{ audit_date }}",
})
doc.add_heading("TCPA Consent Audit Report", level=1)
doc.add_paragraph("Prepared for {{ company_name }} | {{ audit_date }}")
add_section(doc, "1. Executive Summary", [
"{{ executive_summary }}",
])
add_section(doc, "2. Regulatory Background", [
"The Telephone Consumer Protection Act (TCPA), 47 U.S.C. 227, restricts "
"telemarketing calls, auto-dialed calls, prerecorded/artificial voice "
"messages, text messages, and unsolicited faxes. Violations carry statutory "
"damages of $500-$1,500 per violation.",
"",
"Key requirements include:",
"- Prior express written consent for marketing calls/texts using an ATDS "
"or prerecorded voice",
"- Prior express consent for non-marketing calls using an ATDS",
"- Maintaining an internal Do-Not-Call (DNC) list",
"- Honoring the National DNC Registry",
"- Identifying the caller and providing opt-out mechanisms",
])
add_section(doc, "3. Consent Analysis", [
"{{ consent_analysis }}",
])
add_table(doc,
["Consent Type", "Required For", "Current Status", "Compliant", "Notes"],
[
["Express written", "Marketing ATDS/prerecorded", "{{ consent[0].status }}", "{{ consent[0].compliant }}", "{{ consent[0].notes }}"],
["Express (oral)", "Non-marketing ATDS", "{{ consent[1].status }}", "{{ consent[1].compliant }}", "{{ consent[1].notes }}"],
["None (exempted)", "Manual dialing, existing relationship", "{{ consent[2].status }}", "{{ consent[2].compliant }}", "{{ consent[2].notes }}"],
],
)
add_section(doc, "4. Do-Not-Call Compliance", [
"{{ dnc_compliance }}",
])
add_table(doc,
["DNC Requirement", "Status", "Finding"],
[
["Internal DNC list maintained", "{{ dnc[0].status }}", "{{ dnc[0].finding }}"],
["National DNC Registry subscribed", "{{ dnc[1].status }}", "{{ dnc[1].finding }}"],
["DNC requests honored within 30 days", "{{ dnc[2].status }}", "{{ dnc[2].finding }}"],
["DNC records retained 5+ years", "{{ dnc[3].status }}", "{{ dnc[3].finding }}"],
],
)
add_section(doc, "5. Campaign Review", [
"{{ campaign_review }}",
])
add_table(doc,
["Campaign", "Channel", "Consent Type", "Volume", "Compliant", "Issues"],
[
["{{ campaigns[0].name }}", "{{ campaigns[0].channel }}", "{{ campaigns[0].consent }}", "{{ campaigns[0].volume }}", "{{ campaigns[0].compliant }}", "{{ campaigns[0].issues }}"],
["{{ campaigns[1].name }}", "{{ campaigns[1].channel }}", "{{ campaigns[1].consent }}", "{{ campaigns[1].volume }}", "{{ campaigns[1].compliant }}", "{{ campaigns[1].issues }}"],
],
)
add_section(doc, "6. Remediation Plan", [
"{{ remediation_plan }}",
])
add_table(doc,
["Finding", "Action Required", "Owner", "Deadline", "Priority"],
[
["{{ tcpa_actions[0].finding }}", "{{ tcpa_actions[0].action }}", "{{ tcpa_actions[0].owner }}", "{{ tcpa_actions[0].deadline }}", "{{ tcpa_actions[0].priority }}"],
["{{ tcpa_actions[1].finding }}", "{{ tcpa_actions[1].action }}", "{{ tcpa_actions[1].owner }}", "{{ tcpa_actions[1].deadline }}", "{{ tcpa_actions[1].priority }}"],
],
)
add_disclaimer(doc)
save_template(doc, "tcpa-audit-report")
def create_invoice():
"""Generate the Service Invoice template."""
doc = setup_document("Invoice")
# No cover page for invoices — more compact format
# Company header
brand = doc.add_paragraph()
brand.alignment = WD_ALIGN_PARAGRAPH.LEFT
br = brand.add_run(COMPANY_NAME)
br.font.size = Pt(16)
br.font.color.rgb = NAVY
br.font.bold = True
addr = doc.add_paragraph()
ar = addr.add_run(f"{COMPANY_ADDRESS}\n{COMPANY_PHONE} | {COMPANY_WEBSITE}")
ar.font.size = Pt(9)
ar.font.color.rgb = MEDIUM_GRAY
# Invoice title
inv_title = doc.add_paragraph()
inv_title.alignment = WD_ALIGN_PARAGRAPH.RIGHT
inv_run = inv_title.add_run("INVOICE")
inv_run.font.size = Pt(24)
inv_run.font.color.rgb = NAVY
inv_run.font.bold = True
# Invoice metadata
meta = doc.add_paragraph()
meta.alignment = WD_ALIGN_PARAGRAPH.RIGHT
meta.add_run("Invoice #: {{ invoice_number }}\n").font.size = Pt(10)
meta.add_run("Date: {{ invoice_date }}\n").font.size = Pt(10)
meta.add_run("Due Date: {{ due_date }}").font.size = Pt(10)
doc.add_paragraph("")
# Bill To
doc.add_heading("Bill To:", level=2)
doc.add_paragraph("{{ customer_name }}")
doc.add_paragraph("{{ customer_address }}")
doc.add_paragraph("")
# Line items table
add_table(doc,
["Description", "Quantity", "Unit Price", "Amount"],
[
["{{ line_items[0].description }}", "{{ line_items[0].quantity }}", "{{ line_items[0].unit_price }}", "{{ line_items[0].amount }}"],
["{{ line_items[1].description }}", "{{ line_items[1].quantity }}", "{{ line_items[1].unit_price }}", "{{ line_items[1].amount }}"],
["{{ line_items[2].description }}", "{{ line_items[2].quantity }}", "{{ line_items[2].unit_price }}", "{{ line_items[2].amount }}"],
],
)
doc.add_paragraph("")
# Totals
totals = doc.add_paragraph()
totals.alignment = WD_ALIGN_PARAGRAPH.RIGHT
totals.add_run("Subtotal: {{ subtotal }}\n").font.size = Pt(11)
discount_line = doc.add_paragraph()
discount_line.alignment = WD_ALIGN_PARAGRAPH.RIGHT
discount_line.add_run("Discount: {{ discount }}\n").font.size = Pt(11)
total_line = doc.add_paragraph()
total_line.alignment = WD_ALIGN_PARAGRAPH.RIGHT
total_run = total_line.add_run("TOTAL: {{ total }}")
total_run.font.size = Pt(14)
total_run.font.bold = True
total_run.font.color.rgb = NAVY
doc.add_paragraph("")
# Payment instructions
add_section(doc, "Payment Instructions", [
"Payment is due within 30 days of invoice date.",
"",
"Accepted payment methods:",
"- ACH / Wire Transfer",
"- Credit Card (3% processing fee applies)",
"- Check (payable to Performance West Inc.)",
"",
"For questions about this invoice, contact billing@performancewest.net.",
])
# Thank you
thanks = doc.add_paragraph()
thanks.space_before = Pt(24)
thanks.alignment = WD_ALIGN_PARAGRAPH.CENTER
thanks_run = thanks.add_run("Thank you for your business.")
thanks_run.font.italic = True
thanks_run.font.color.rgb = MEDIUM_GRAY
save_template(doc, "invoice")
def create_fcc_compliance_report():
"""Generate the FCC Carrier Compliance Checkup Report template."""
doc = setup_document("FCC Carrier Compliance Checkup Report")
add_cover_page(doc, "FCC Carrier Compliance\nCheckup Report", {
"Prepared for": "{{ customer_name }}",
"Entity": "{{ entity_name }}",
"FRN": "{{ frn }}",
"Order": "{{ order_number }}",
"Date": "{{ date }}",
})
doc.add_page_break()
# Executive Summary
doc.add_heading("Executive Summary", level=1)
doc.add_paragraph("{{ executive_summary }}")
# Section 1: CORES Registration
doc.add_heading("1. CORES Registration Status", level=1)
t1 = doc.add_table(rows=4, cols=2)
t1.style = "Table Grid"
for i, (label, placeholder) in enumerate([
("Registration Status", "{{ cores_status }}"),
("Red-Light Status", "{{ cores_red_light }}"),
("Entity Name on File", "{{ cores_entity_name }}"),
("Address on File", "{{ cores_address }}"),
]):
t1.rows[i].cells[0].paragraphs[0].add_run(label).bold = True
t1.rows[i].cells[1].text = placeholder
doc.add_paragraph()
doc.add_paragraph("{{ cores_detail }}")
# Section 2: RMD Filing Status
doc.add_heading("2. Robocall Mitigation Database (RMD) Status", level=1)
t2 = doc.add_table(rows=5, cols=2)
t2.style = "Table Grid"
for i, (label, placeholder) in enumerate([
("RMD Registration", "{{ rmd_status }}"),
("RMD Number", "{{ rmd_number }}"),
("Last Certification", "{{ rmd_last_cert }}"),
("Recertification Due", "{{ rmd_recert_due }}"),
("Removal Status", "{{ rmd_removal_status }}"),
]):
t2.rows[i].cells[0].paragraphs[0].add_run(label).bold = True
t2.rows[i].cells[1].text = placeholder
doc.add_paragraph()
doc.add_paragraph("{{ rmd_detail }}")
# Section 3: STIR/SHAKEN
doc.add_heading("3. STIR/SHAKEN Compliance", level=1)
t3 = doc.add_table(rows=3, cols=2)
t3.style = "Table Grid"
for i, (label, placeholder) in enumerate([
("Implementation Type", "{{ stir_shaken_type }}"),
("Certificate Authority", "{{ stir_shaken_cert }}"),
("Status", "{{ stir_shaken_status }}"),
]):
t3.rows[i].cells[0].paragraphs[0].add_run(label).bold = True
t3.rows[i].cells[1].text = placeholder
doc.add_paragraph()
doc.add_paragraph("{{ stir_shaken_detail }}")
# Section 4: CPNI
doc.add_heading("4. CPNI Annual Certification Status", level=1)
t4 = doc.add_table(rows=2, cols=2)
t4.style = "Table Grid"
for i, (label, placeholder) in enumerate([
("Certification Status", "{{ cpni_status }}"),
("Due Date", "{{ cpni_due_date }}"),
]):
t4.rows[i].cells[0].paragraphs[0].add_run(label).bold = True
t4.rows[i].cells[1].text = placeholder
doc.add_paragraph()
doc.add_paragraph("{{ cpni_detail }}")
# Section 5: 499-A
doc.add_heading("5. Form 499-A Status", level=1)
t5 = doc.add_table(rows=3, cols=2)
t5.style = "Table Grid"
for i, (label, placeholder) in enumerate([
("Filing Status", "{{ f499a_status }}"),
("Due Date", "{{ f499a_due_date }}"),
("Filer ID", "{{ f499a_filer_id }}"),
]):
t5.rows[i].cells[0].paragraphs[0].add_run(label).bold = True
t5.rows[i].cells[1].text = placeholder
doc.add_paragraph()
doc.add_paragraph("{{ f499a_detail }}")
# Section 6: 499-Q
doc.add_heading("6. Form 499-Q Status", level=1)
doc.add_paragraph("{{ f499q_detail }}")
# Section 7: Carrier Classification Summary
doc.add_heading("7. Carrier Classification Summary", level=1)
t7 = doc.add_table(rows=6, cols=2)
t7.style = "Table Grid"
for i, (label, placeholder) in enumerate([
("Carrier Category", "{{ carrier_category }}"),
("Infrastructure Type", "{{ infra_type }}"),
("Wholesale Provider", "{{ is_wholesale }}"),
("UCaaS Provider", "{{ ucaas_provider }}"),
("STIR/SHAKEN Status", "{{ classification_stir_shaken }}"),
("De Minimis", "{{ is_deminimis }}"),
]):
t7.rows[i].cells[0].paragraphs[0].add_run(label).bold = True
t7.rows[i].cells[1].text = placeholder
# Section 8: Recommended Actions
doc.add_heading("8. Recommended Actions", level=1)
doc.add_paragraph(
"The following actions are recommended to bring this entity into "
"full FCC compliance, listed by priority:"
)
doc.add_paragraph("{{ recommended_actions }}")
# Appendix
doc.add_page_break()
doc.add_heading("Appendix: Attached Documents", level=1)
doc.add_paragraph("{{ appendix_index }}")
# Disclaimer
doc.add_paragraph()
disc_para = doc.add_paragraph()
disc_run = disc_para.add_run(DISCLAIMER)
disc_run.font.size = Pt(8)
disc_run.font.italic = True
disc_run.font.color.rgb = LIGHT_GRAY
save_template(doc, "fcc_compliance_report_template")
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def main():
print(f"Generating DOCX templates in {OUTPUT_DIR}/\n")
generators = [
("Operating Agreement", create_operating_agreement),
("Privacy Policy", create_privacy_policy),
("Breach Response Plan", create_breach_response_plan),
("FLSA Audit Report", create_flsa_audit_report),
("Contractor Assessment", create_contractor_assessment),
("Handbook Review", create_handbook_review),
("CCPA Audit Report", create_ccpa_audit_report),
("TCPA Audit Report", create_tcpa_audit_report),
("Invoice", create_invoice),
("FCC Compliance Report", create_fcc_compliance_report),
]
for name, gen_func in generators:
try:
gen_func()
except Exception as e:
print(f" ERROR generating {name}: {e}")
raise
print(f"\nDone. Generated {len(generators)} templates.")
print("\nTo upload to MinIO:")
print(f" mc cp {OUTPUT_DIR}/*.docx minio/performancewest/templates/")
if __name__ == "__main__":
main()