updated the report so that we will flag drawers that had errors and also crashed

This commit is contained in:
2026-07-20 19:44:34 -05:00
parent b270ca9186
commit 3b950cf886
4 changed files with 45 additions and 13 deletions

View File

@@ -122,7 +122,9 @@ Drawer ID(s): 08097 18430
python fccs_report.py
```
This runs the same document-level check as `fccs_verify.py` but writes a self-contained, print-friendly HTML file (`report_html`, default `C:\Migration\progress_report.html`) that lists **only** the drawers with missing documents, each with the client name and the specific documents still outstanding. Fully-migrated drawers are omitted (a headline shows how many are done). Drawers with no manifest or in `crashed.txt` are excluded since they reflect internal tooling state, not client-facing progress. Open it in any browser and print to PDF to send.
This runs the same document-level check as `fccs_verify.py` but writes a self-contained, print-friendly HTML file (`report_html`, default `C:\Migration\progress_report.html`) that lists **only** the drawers with missing documents, each with the client name and the specific documents still outstanding. Fully-migrated drawers and drawers with no manifest are omitted (a headline shows how many are done). Open it in any browser and print to PDF to send.
Any outstanding drawer that also appears in `crashed.txt` (its export was aborted by an FCCS converter crash) is badged **CRASHED** and sorted to the top, and counted in the header. These are the genuine failures worth spot-checking first — as opposed to benign false positives, where a collapsed "container" document's children exported fine but the container's name lands in the filename's folder field rather than the document field, so it reads as missing.
## Config Reference

View File

@@ -6,10 +6,15 @@ 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.
Drawers that are fully exported or that have no manifest are left out — the
report shows outstanding work. A headline shows how many drawers are fully
migrated so overall progress is clear.
Any outstanding drawer that also appears in crashed.txt (an FCCS converter crash
aborted its export) is badged CRASHED and sorted to the top: those are genuine
failures worth attention, as opposed to benign name-match false positives (e.g.
a collapsed "container" document whose children exported fine but whose name
lands in the filename's folder field rather than the document field).
Output goes to `report_html` (default C:\\Migration\\progress_report.html).
@@ -24,7 +29,7 @@ import html
from datetime import datetime
from fccs_config import (
parse_args, load_config,
parse_args, load_config, load_lines,
evaluate_drawer, index_files_by_drawer, client_name_from_files,
)
@@ -61,6 +66,7 @@ PAGE_TEMPLATE = """<!doctype html>
letter-spacing: .03em; margin-top: .35rem; }}
.stat.good .num {{ color: #2e7d32; }}
.stat.flag .num {{ color: #c0392b; }}
.stat.crash .num {{ color: #b9770e; }}
.body {{ padding: 1.5rem 2.25rem 2.25rem; }}
.all-clear {{
text-align: center; padding: 2.5rem 1rem; color: #2e7d32; font-size: 1.1rem;
@@ -70,10 +76,17 @@ PAGE_TEMPLATE = """<!doctype html>
margin-bottom: 1rem;
}}
.drawer:last-child {{ margin-bottom: 0; }}
.drawer.crashed {{ border-left: 4px solid #c0392b; background: #fdf6f5; }}
.drawer h2 {{
margin: 0 0 .1rem; font-size: 1.05rem; font-weight: 620;
}}
.drawer .id {{ color: #486581; font-variant-numeric: tabular-nums; }}
.badge {{
display: inline-block; margin-left: .5rem; padding: .1rem .5rem;
font-size: .72rem; font-weight: 700; letter-spacing: .04em;
text-transform: uppercase; color: #fff; background: #c0392b;
border-radius: 4px; vertical-align: middle;
}}
.drawer .meta {{ color: #7b8794; font-size: .82rem; margin-bottom: .6rem; }}
ul.docs {{ margin: 0; padding: 0; list-style: none; }}
ul.docs li {{
@@ -105,6 +118,8 @@ PAGE_TEMPLATE = """<!doctype html>
<div class="lbl">Drawers migrated</div></div>
<div class="stat flag"><div class="num">{incomplete}</div>
<div class="lbl">Drawers outstanding</div></div>
<div class="stat crash"><div class="num">{crashed}</div>
<div class="lbl">Crashed in export</div></div>
<div class="stat"><div class="num">{total}</div>
<div class="lbl">Total drawers</div></div>
</div>
@@ -112,24 +127,29 @@ PAGE_TEMPLATE = """<!doctype html>
{content}
</div>
<footer>Generated {date} &middot; Lists documents not yet present in the
export. Drawers not shown are fully migrated.</footer>
export. Drawers not shown are fully migrated. A
<span class="badge">Crashed</span> badge marks drawers whose export was
interrupted by an error.</footer>
</div>
</body>
</html>
"""
def build_drawer_block(drawer_id, client, missing):
def build_drawer_block(drawer_id, client, missing, crashed=False):
"""Return the HTML for one outstanding drawer."""
head = f'<span class="id">{html.escape(drawer_id)}</span>'
if client:
head += f' &mdash; {html.escape(client)}'
if crashed:
head += ' <span class="badge">Crashed</span>'
n = len(missing)
docs = "\n".join(
f" <li>{html.escape(m)}</li>" for m in missing
)
cls = "drawer crashed" if crashed else "drawer"
return (
' <div class="drawer">\n'
f' <div class="{cls}">\n'
f' <h2>{head}</h2>\n'
f' <div class="meta">{n} document{"s" if n != 1 else ""} '
'outstanding</div>\n'
@@ -145,6 +165,7 @@ def main():
export_dir = cfg.get("paths", "export_dir")
manifest_dir = cfg.get("paths", "manifest_dir")
report_html = cfg.get("paths", "report_html")
crashed_set = set(load_lines(cfg.get("paths", "crashed_file")))
if not os.path.isdir(manifest_dir):
print(f"ERROR: manifest directory not found: {manifest_dir}")
@@ -166,22 +187,27 @@ def main():
files_by_drawer = index_files_by_drawer(export_dir)
complete = 0
outstanding = [] # (drawer_id, client, missing_list)
outstanding = [] # (drawer_id, client, missing_list, crashed)
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"]))
outstanding.append((drawer_id, client, r["missing"],
drawer_id in crashed_set))
else:
complete += 1
# Crashed drawers are the genuine failures — surface them first.
outstanding.sort(key=lambda o: (not o[3], o[0]))
crashed_ids = [d for d, _, _, cr in outstanding if cr]
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
build_drawer_block(d, c, m, cr) for d, c, m, cr in outstanding
)
else:
content = (' <div class="all-clear">All drawers are fully '
@@ -191,6 +217,7 @@ def main():
date=html.escape(date_str),
complete=complete,
incomplete=len(outstanding),
crashed=len(crashed_ids),
total=total,
content=content,
)
@@ -202,7 +229,10 @@ def main():
print(f" {complete}/{total} drawers fully migrated, "
f"{len(outstanding)} outstanding.")
if outstanding:
print(" Outstanding: " + ", ".join(d for d, _, _ in outstanding))
print(" Outstanding: " + ", ".join(d for d, _, _, _ in outstanding))
if crashed_ids:
print(f" Outstanding AND crashed ({len(crashed_ids)}) "
"— spot-check these first: " + ", ".join(crashed_ids))
if __name__ == "__main__":