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>
55 lines
2.2 KiB
Python
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.")
|