""" Utility: Generate a client-facing progress report (HTML). Runs the same document-level completeness check as fccs_verify.py, but produces a clean, self-contained HTML file listing ONLY the drawers with outstanding items and, for each, the specific documents still missing from the export. It's meant as a "check-in progress" document you can send to the client. Drawers that are fully exported, that have no manifest, or that only appear in crashed.txt are intentionally left out — the report shows outstanding work, not internal tooling state. A headline shows how many drawers are fully migrated so the overall progress is clear. Output goes to `report_html` (default C:\\Migration\\progress_report.html). USAGE ----- python fccs_report.py """ import os import sys import html from datetime import datetime from fccs_config import ( parse_args, load_config, evaluate_drawer, index_files_by_drawer, client_name_from_files, ) PAGE_TEMPLATE = """ Migration Progress Report

Migration Progress Report

{date}
{complete}
Drawers migrated
{incomplete}
Drawers outstanding
{total}
Total drawers
{content}
""" def build_drawer_block(drawer_id, client, missing): """Return the HTML for one outstanding drawer.""" head = f'{html.escape(drawer_id)}' if client: head += f' — {html.escape(client)}' n = len(missing) docs = "\n".join( f"
  • {html.escape(m)}
  • " for m in missing ) return ( '
    \n' f'

    {head}

    \n' f'
    {n} document{"s" if n != 1 else ""} ' 'outstanding
    \n' f' \n' '
    ' ) def main(): args = parse_args() cfg = load_config(args.config) export_dir = cfg.get("paths", "export_dir") manifest_dir = cfg.get("paths", "manifest_dir") report_html = cfg.get("paths", "report_html") if not os.path.isdir(manifest_dir): print(f"ERROR: manifest directory not found: {manifest_dir}") print("Run fccs_export.py first to generate manifests.") sys.exit(1) if not os.path.isdir(export_dir): print(f"ERROR: export directory not found: {export_dir}") sys.exit(1) drawer_ids = sorted( os.path.splitext(f)[0] for f in os.listdir(manifest_dir) if f.endswith(".txt") ) if not drawer_ids: print("No manifest files found.") sys.exit(1) files_by_drawer = index_files_by_drawer(export_dir) complete = 0 outstanding = [] # (drawer_id, client, missing_list) for drawer_id in drawer_ids: files = files_by_drawer.get(drawer_id, []) r = evaluate_drawer(drawer_id, files, manifest_dir) if r["missing"]: client = client_name_from_files(files) outstanding.append((drawer_id, client, r["missing"])) else: complete += 1 total = len(drawer_ids) date_str = f"{datetime.now():%B %d, %Y}" if outstanding: content = "\n".join( build_drawer_block(d, c, m) for d, c, m in outstanding ) else: content = ('
    All drawers are fully ' "migrated — no outstanding documents.
    ") page = PAGE_TEMPLATE.format( date=html.escape(date_str), complete=complete, incomplete=len(outstanding), total=total, content=content, ) with open(report_html, "w", encoding="utf-8") as f: f.write(page) print(f"Progress report written to {report_html}") print(f" {complete}/{total} drawers fully migrated, " f"{len(outstanding)} outstanding.") if outstanding: print(" Outstanding: " + ", ".join(d for d, _, _ in outstanding)) if __name__ == "__main__": main()