MEGAINFRA-WEBAPP/scripts/pb-add-dn-dates.py
DEls a41653ce87 fix(dn): date deliveries by the slip and orders by the PO's order date
The reader always read the slip date (and receiver, site name, customer
VAT, supplier registration), but dn_batch_notes never had those fields,
so they were dropped on save and every receipt was dated the moment it
was posted. The Financial dashboard dated orders by upload date, so 24
of 41 POs (R7.08M) sat in no month and deliveries piled up in the month
they were booked: 'R1.1M ordered, R2.4M delivered'.

- scripts/pb-add-dn-dates.py: adds the five header fields,
  delivery_notes.posted_at and purchase_orders.order_date (applied).
- scripts/dn-backfill-dates.py: filled 270 documents from the stored
  readings, moved 192 receipts to their slip date (booking time kept in
  posted_at) and read 36 PO order dates from the PDFs (applied; replaced
  values in docs/audits/2026-10-11-dates-backfill-backup.json).
- Posting refuses a slip without a delivery date instead of using today;
  receipts record posted_at. The review page shows the date and locks
  Post with a plain message when it is missing.
- PO intake reads 'PO Creation Date' from the PDF text (pdftotext).
- Dashboard tile and monthly chart date orders by order_date only; an
  order without one is undated, never put on its upload month.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:35:00 +02:00

55 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""
Adds the fields that carry real dates through receiving and ordering.
The reader has always read the slip's date, receiver, site name, customer
VAT and supplier registration, and the pipeline writes them to
dn_batch_notes, but the collection never had those fields, so PocketBase
dropped them on every save. Posting then fell back to "now" for
delivery_notes.date_received, which put every delivery in the month it was
posted instead of the month it arrived.
dn_batch_notes: date, received_by_name, site_name_raw, customer_vat_no,
supplier_registration_raw (text, as the reader gives them)
delivery_notes: posted_at (when the receipt was booked; date_received
becomes the slip's delivery date)
purchase_orders: order_date (the "PO Creation Date" printed on the PO;
the upload date says nothing about when it was ordered)
Idempotent. Run scripts/pb-backup-collection.py for each collection first.
"""
import sys
from pb_env import PB, http, superuser_token
TEXT = lambda name: {"name": name, "type": "text", "required": False}
WANTED = {
"dn_batch_notes": [TEXT("date"), TEXT("received_by_name"), TEXT("site_name_raw"), TEXT("customer_vat_no"), TEXT("supplier_registration_raw")],
"delivery_notes": [{"name": "posted_at", "type": "date", "required": False}],
"purchase_orders": [{"name": "order_date", "type": "date", "required": False}],
}
def main():
token = superuser_token()
print(f"\n→ {PB}")
for name, wanted in WANTED.items():
code, coll = http("GET", f"/api/collections/{name}", token=token)
if code != 200:
sys.exit(f"GET {name} failed: {code} {coll}")
fields = list(coll.get("fields", []))
have = {f.get("name") for f in fields}
add = [w for w in wanted if w["name"] not in have]
if not add:
print(f" • {name}: nothing to add")
continue
code, resp = http("PATCH", f"/api/collections/{coll['id']}", {"fields": fields + add}, token)
if code != 200:
sys.exit(f"PATCH {name} failed: {code} {resp}")
for a in add:
print(f" ✓ {name}: added {a['name']}")
if __name__ == "__main__":
main()
print("\nDone.")