""" 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'' ) 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'') run_page = para.add_run() run_page._r.append(fld_char_begin) instr = parse_xml(f' PAGE ') run_page2 = para.add_run() run_page2._r.append(instr) fld_char_end = parse_xml(f'') 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'') run_np = para.add_run() run_np._r.append(fld_char_begin2) instr2 = parse_xml(f' NUMPAGES ') run_np2 = para.add_run() run_np2._r.append(instr2) fld_char_end2 = parse_xml(f'') 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()