193 lines
5.9 KiB
Python
193 lines
5.9 KiB
Python
import json
|
|
import re
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
OLD_APP = Path("/mnt/storage/sftp/mcelwain/repository/word-doc-generator")
|
|
DRAFT_PROFILE = Path("diagnostics/legacy_word_doc_generator_profile_draft.json")
|
|
OUT_PROFILE = Path("tools/doc_generator/content/document_types/legal_profile.json")
|
|
TEMPLATES_OUT = Path("tools/doc_generator/content/templates/legacy")
|
|
|
|
OLD_PUBLIC = OLD_APP / "public"
|
|
|
|
|
|
def run_node_list_extractor():
|
|
js = f"""
|
|
import {{ pathToFileURL }} from 'url';
|
|
|
|
const files = [
|
|
'casePlaintiffInfo.js',
|
|
'opposingCounselInfo.js',
|
|
'judgeInfo.js',
|
|
'caseFilingAttorneyInfo.js',
|
|
'filingAttorneyInfo.js',
|
|
'debtCollectorInfo.js'
|
|
];
|
|
|
|
const base = {json.dumps(str(OLD_PUBLIC))};
|
|
const result = {{}};
|
|
|
|
for (const file of files) {{
|
|
try {{
|
|
const mod = await import(pathToFileURL(`${{base}}/${{file}}`).href);
|
|
for (const [exportName, value] of Object.entries(mod)) {{
|
|
if (value && typeof value === 'object' && !Array.isArray(value)) {{
|
|
result[exportName] = Object.keys(value).sort();
|
|
}}
|
|
}}
|
|
}} catch (err) {{
|
|
// Some optional info files may not exist.
|
|
}}
|
|
}}
|
|
|
|
console.log(JSON.stringify(result));
|
|
"""
|
|
try:
|
|
completed = subprocess.run(
|
|
["node", "--input-type=module", "-e", js],
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
return json.loads(completed.stdout)
|
|
except Exception:
|
|
return {}
|
|
|
|
|
|
def nice_label(name):
|
|
label = re.sub(r"([a-z])([A-Z])", r"\1 \2", name)
|
|
label = label.replace("_", " ").replace("-", " ")
|
|
label = re.sub(r"\bSsn\b", "SSN", label.title())
|
|
label = label.replace("Dob", "DOB")
|
|
return label
|
|
|
|
|
|
def apply_legal_field_metadata(field):
|
|
name = field["name"]
|
|
lower = name.lower()
|
|
|
|
# Normalize generated labels.
|
|
field["label"] = nice_label(name)
|
|
|
|
# Autocomplete fields.
|
|
if name == "casePlaintiff":
|
|
field["type"] = "autocomplete"
|
|
field["list"] = "plaintiffs"
|
|
elif name == "caseOpposingCounsel":
|
|
field["type"] = "autocomplete"
|
|
field["list"] = "opposingCounsel"
|
|
elif name == "caseDivisionJudge":
|
|
field["type"] = "autocomplete"
|
|
field["list"] = "judges"
|
|
elif name == "caseFilingAttorney":
|
|
field["type"] = "autocomplete"
|
|
field["list"] = "filingAttorneys"
|
|
elif re.fullmatch(r"debtCollector\d+Name", name):
|
|
field["type"] = "autocomplete"
|
|
field["list"] = "debtCollectors"
|
|
elif lower.endswith("state") or name in {"caseState", "homeState", "client2homeState"}:
|
|
field["type"] = "autocomplete"
|
|
field["list"] = "states"
|
|
elif name == "caseDesignation":
|
|
field["type"] = "autocomplete"
|
|
field["list"] = "caseDesignations"
|
|
|
|
# Long text fields.
|
|
if name in {"notes", "caseAppearanceInfo", "paymentOptions", "paymentOptions1", "paymentOptions2", "paymentOptions3", "paymentOptions4", "paymentOptions5"}:
|
|
field["type"] = "textarea"
|
|
|
|
return field
|
|
|
|
|
|
def walk_sections(sections):
|
|
for section in sections:
|
|
section["collapsible"] = section.get("heading") not in {
|
|
"Client Information",
|
|
"Case Information",
|
|
}
|
|
section["defaultOpen"] = section.get("heading") in {
|
|
"Client Information",
|
|
"Case Information",
|
|
}
|
|
|
|
section["fields"] = [
|
|
apply_legal_field_metadata(field)
|
|
for field in section.get("fields", [])
|
|
]
|
|
|
|
for subsection in section.get("subsections", []):
|
|
walk_sections([subsection])
|
|
|
|
|
|
def discover_templates():
|
|
templates = []
|
|
|
|
for path in sorted(TEMPLATES_OUT.rglob("*.docx")):
|
|
rel = path.relative_to(Path("tools/doc_generator/content/templates")).as_posix()
|
|
template_id = re.sub(r"[^a-zA-Z0-9]+", "_", path.stem).strip("_").lower()
|
|
|
|
label = path.relative_to(TEMPLATES_OUT).as_posix()
|
|
label = label.replace(".docx", "")
|
|
label = label.replace("/", " / ")
|
|
label = label.replace("_", " ")
|
|
|
|
templates.append({
|
|
"id": template_id,
|
|
"label": label,
|
|
"template": rel,
|
|
"outputFilename": f"{template_id}_{{caseNumber}}_{{timestamp_YYYY-MM-DD_HH-mm-ss}}.docx"
|
|
})
|
|
|
|
return templates
|
|
|
|
|
|
def main():
|
|
if not DRAFT_PROFILE.exists():
|
|
raise SystemExit(f"Missing {DRAFT_PROFILE}. Run review-old-word-doc-generator.py first.")
|
|
|
|
draft = json.loads(DRAFT_PROFILE.read_text(encoding="utf-8"))
|
|
|
|
lists_raw = run_node_list_extractor()
|
|
|
|
lists = {
|
|
"plaintiffs": lists_raw.get("casePlaintiffInfo", []),
|
|
"opposingCounsel": lists_raw.get("caseOpposingCounselInfo", []) or lists_raw.get("opposingCounselInfo", []),
|
|
"judges": lists_raw.get("judgeInfo", []),
|
|
"filingAttorneys": lists_raw.get("caseFilingAttorneyInfo", []) or lists_raw.get("filingAttorneyInfo", []),
|
|
"debtCollectors": lists_raw.get("debtCollectorInfo", []),
|
|
"states": ["MO", "KS"],
|
|
"caseDesignations": [
|
|
"Associate Circuit",
|
|
"Circuit",
|
|
"Limited Actions",
|
|
"Small Claims"
|
|
]
|
|
}
|
|
|
|
sections = draft["sections"]
|
|
walk_sections(sections)
|
|
|
|
templates = discover_templates()
|
|
|
|
profile = {
|
|
"id": "legal_profile",
|
|
"name": "Legal Profile",
|
|
"description": "Consumer debt defense legal profile generated from the legacy word-doc-generator app.",
|
|
"template": templates[0]["template"] if templates else "legacy/Canned-Emails.docx",
|
|
"outputFilename": "legal_{caseNumber}_{timestamp_YYYY-MM-DD_HH-mm-ss}.docx",
|
|
"lists": lists,
|
|
"templates": templates,
|
|
"sections": sections
|
|
}
|
|
|
|
OUT_PROFILE.parent.mkdir(parents=True, exist_ok=True)
|
|
OUT_PROFILE.write_text(json.dumps(profile, indent=2), encoding="utf-8")
|
|
|
|
print(f"Wrote {OUT_PROFILE}")
|
|
print(f"Lists: {', '.join(f'{k}={len(v)}' for k, v in lists.items())}")
|
|
print(f"Templates: {len(templates)}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|