MEGAINFRA-WEBAPP/scripts/pb-add-dn-note-dismissed.py
DEls 2c5cde6bce feat(dn-batches): dismiss a single duplicate note, and stop erasing promoted counts
Duplication happens per NOTE, not per batch. The same stack of Vula
invoices was scanned three times in overlapping groupings — 13, 16 and 14
pages with three different file hashes, so upload-time hash dedup could
not see it. Each of those batches mixes notes that promoted, notes
duplicating another batch, and invoices unique to it: vdn074468 alone
carries four that exist nowhere else.

So no batch-level action is correct. Dismissing one wholesale either
discards unique invoices or zeroes a counter for notes already on the
ledger. Adds POST /api/dn-batches/[id]/notes/[noteId]/dismiss, which
stands one note down, refuses to touch a promoted one, and parks the
batch only once nothing is outstanding.

Also fixes the batch dismiss route, which wrote notes_promoted: 0
unconditionally. A batch that had promoted 8 of 13 notes would report
nothing while 8 delivery notes sat in the figures people pay from — the
same board-versus-ledger disagreement already fixed in run.ts. It now
counts what actually reached the ledger and says so in the reason.

929 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 00:44:57 +02:00

54 lines
1.7 KiB
Python

#!/usr/bin/env python3
"""
Adds "dismissed" to DN_BATCH_NOTES.status.
Duplication happens per note, not per batch. The same stack of Vula
invoices was scanned three times in overlapping groupings (13, 16 and 14
pages, three different file hashes), so every one of those batches holds
a mix of promoted notes, duplicates of another batch, and invoices unique
to it. Dismissing a whole batch therefore either discards unique
invoices or zeroes a counter for notes already on the ledger.
"dismissed" lets a single duplicate note stand down, which is the only
safe granularity.
Idempotent.
"""
import sys
from pb_env import PB, http, superuser_token
NEW_VALUE = "dismissed"
def main():
token = superuser_token()
print(f"\n→ dn_batch_notes on {PB}")
code, coll = http("GET", "/api/collections/dn_batch_notes", token=token)
if code != 200:
sys.exit(f"GET failed: {code} {coll}")
# Read the live field list and modify in place. PocketBase replaces
# the whole array on PATCH, so never build it from anything but a
# fresh read.
fields = list(coll.get("fields", []))
status = next((f for f in fields if f.get("name") == "status"), None)
if not status:
sys.exit("no status field on dn_batch_notes")
values = list(status.get("values") or [])
if NEW_VALUE in values:
print(f" • status already allows '{NEW_VALUE}'")
return
status["values"] = values + [NEW_VALUE]
code, resp = http("PATCH", f"/api/collections/{coll['id']}", {"fields": fields}, token)
if code != 200:
sys.exit(f"PATCH failed: {code} {resp}")
print(f" ✓ status values now {status['values']} (kept {len(fields)} fields)")
if __name__ == "__main__":
main()
print("\nDone.")