#!/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))