#!/usr/bin/env python3 """Build the ABSLI policy-schedule / welcome-kit .docx template for app 385. Dependency-free: writes a minimal-but-valid WordprocessingML package by hand. Each {{placeholder}} is emitted as ONE contiguous run so docx-service's placeholder substitution resolves it cleanly (it also handles fragmented runs, but single runs are the safe path). Output: ai-employee-leadtopolicy/policy_schedule.docx Upload it via Studio > Templates (app 385); docx-service substitutes the {{vars}} mapped in the 44d generateDoc node. Placeholders (all sourced from companion tbl_wf_385_lead_to_policy at 44d): policy_number lead_name plan_name sum_assured premium_amount premium_frequency policy_term commencement_date maturity_date advisor_name issue_date """ import os import zipfile from xml.sax.saxutils import escape OUT = os.path.join(os.path.dirname(__file__), "..", "..", ".supacode", "repos", "sm2", "lead-to-policy", "ai-employee-leadtopolicy", "policy_schedule.docx") # When run from the aria-console scripts/ dir the relative hop above is brittle; # allow an explicit override. OUT = os.environ.get("POLICY_DOCX_OUT", OUT) NSW = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" # ---- run / paragraph helpers ------------------------------------------------- def run(text, *, bold=False, size=None, color=None): rpr = "" props = [] if bold: props.append("") if size: # half-points props.append(f'') if color: props.append(f'') if props: rpr = "" + "".join(props) + "" return (f'{rpr}{escape(text)}') def para(runs, *, align=None, space_after=120, shading=None): ppr_bits = [] if align: ppr_bits.append(f'') if shading: ppr_bits.append(f'') ppr_bits.append(f'') ppr = "" + "".join(ppr_bits) + "" body = runs if isinstance(runs, str) else "".join(runs) return f"{ppr}{body}" def cell(text_runs, *, w=4500, fill=None): shd = f'' if fill else "" tcpr = f'{shd}' return f"{tcpr}{para(text_runs, space_after=40)}" def kv_row(label, placeholder): left = cell([run(label, bold=True, size=20, color="475569")], w=3600, fill="F1F5F9") right = cell([run("{{" + placeholder + "}}", size=20, color="0F172A")], w=5400) return f"{left}{right}" def table(rows): borders = ( "" '' '' '' '' '' '' "" ) tblpr = f'{borders}' grid = '' return f"{tblpr}{grid}{''.join(rows)}" # ---- document body ----------------------------------------------------------- body_parts = [ para([run("Aditya Birla Sun Life Insurance", bold=True, size=32, color="9A1F40")], align="center", space_after=40), para([run("Policy Schedule & Welcome Kit", bold=True, size=24, color="475569")], align="center", space_after=240), para([run("Dear ", size=22), run("{{lead_name}}", bold=True, size=22), run(",", size=22)]), para([run( "Welcome to the Aditya Birla Sun Life Insurance family. We are delighted to " "confirm that your policy has been issued. Please find your policy schedule " "below. Kindly retain this document for your records.", size=22)], space_after=240), para([run("Policy Schedule", bold=True, size=24, color="9A1F40")], space_after=120), table([ kv_row("Policy Number", "policy_number"), kv_row("Plan", "plan_name"), kv_row("Life Assured", "lead_name"), kv_row("Sum Assured (INR)", "sum_assured"), kv_row("Premium (INR)", "premium_amount"), kv_row("Premium Frequency", "premium_frequency"), kv_row("Policy Term (years)", "policy_term"), kv_row("Risk Commencement Date", "commencement_date"), kv_row("Maturity Date", "maturity_date"), kv_row("Date of Issue", "issue_date"), kv_row("Your Advisor", "advisor_name"), ]), para([run("", size=22)], space_after=200), para([run( "This is a computer-generated welcome document. The benefits, terms and " "conditions are governed by the policy contract. For any assistance, please " "contact your advisor named above or reach us at care.abslifeinsurance@adityabirlacapital.com.", size=18, color="64748B")], space_after=240), para([run("Warm regards,", size=22)], space_after=40), para([run("Team Aditya Birla Sun Life Insurance", bold=True, size=22)]), ] document_xml = ( '\n' f'' "" + "".join(body_parts) + '' '' "" ) CONTENT_TYPES = ( '\n' '' '' '' '' "" ) RELS = ( '\n' '' '' "" ) DOC_RELS = ( '\n' '' "" ) os.makedirs(os.path.dirname(OUT), exist_ok=True) with zipfile.ZipFile(OUT, "w", zipfile.ZIP_DEFLATED) as z: z.writestr("[Content_Types].xml", CONTENT_TYPES) z.writestr("_rels/.rels", RELS) z.writestr("word/document.xml", document_xml) z.writestr("word/_rels/document.xml.rels", DOC_RELS) print("wrote", os.path.abspath(OUT))