"""
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{docs}\n
\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()