""" Create the 3 JEI_fedex_* collections in PocketBase. Collections: JEI_fedex_import_batches - one per import batch (date, vat, duties, status) JEI_fedex_shipments - links invoice <-> batch with waybill_no + fedex_ref_no JEI_fedex_batch_documents - documents (Waybill/SAD500/SAD507/BillOfEntry) per batch Idempotent: skips a collection if it already exists. Run: python scripts/create_fedex_collections.py """ import os, sys, json, urllib.request from urllib.error import HTTPError PB_URL = os.environ.get("PB_URL", "https://pb.agent.apphub.co.za") PB_TOKEN = None env_path = os.path.join(os.path.dirname(__file__), "..", ".env.local") if os.path.exists(env_path): for line in open(env_path): if line.startswith("PB_TOKEN="): PB_TOKEN = line.strip().split("=", 1)[1] if not PB_TOKEN: sys.exit("PB_TOKEN missing") H = {"Authorization": PB_TOKEN, "Content-Type": "application/json"} SUPERUSER_RULES = {"listRule": "", "viewRule": "", "createRule": "", "updateRule": "", "deleteRule": ""} def pb_get(path): r = urllib.request.Request(PB_URL + path, headers=H, method="GET") with urllib.request.urlopen(r, timeout=30) as resp: return json.loads(resp.read()) def pb_post(path, body): data = json.dumps(body).encode("utf-8") r = urllib.request.Request(PB_URL + path, data=data, headers=H, method="POST") try: with urllib.request.urlopen(r, timeout=30) as resp: return json.loads(resp.read()), None except HTTPError as e: return None, json.loads(e.read()) def find_col(name): items = pb_get("/api/collections?perPage=200")["items"] return next((c for c in items if c["name"] == name), None) def ensure(name, factory): existing = find_col(name) if existing: print(f"EXISTS: {name}") return existing result, err = pb_post("/api/collections", factory()) if err: sys.exit(f"ERROR creating {name}: {err}") print(f"CREATED: {name} (id={result['id']})") return result def batches_schema(): # NOTE: PB v0.39.8 quirk — select options go at field root, NOT in `options` return { "name": "JEI_fedex_import_batches", "type": "base", "fields": [ {"name": "import_date", "type": "date", "required": True, "options": {"min": "", "max": ""}}, {"name": "vat_paid", "type": "number", "required": False, "options": {"min": 0, "max": None, "noDecimal": False}}, {"name": "duties_paid", "type": "number", "required": False, "options": {"min": 0, "max": None, "noDecimal": False}}, {"name": "status", "type": "select", "required": True, "maxSelect": 1, "values": ["pending", "imported", "cancelled"]}, {"name": "notes", "type": "text", "required": False, "options": {"min": 0, "max": 2000, "pattern": ""}}, ], **SUPERUSER_RULES, } def shipments_schema(invoices_id, batches_id): # PB v0.39.8 quirk: relation fields need collectionId/cascadeDelete at root, # not inside options return { "name": "JEI_fedex_shipments", "type": "base", "fields": [ {"name": "invoice", "type": "relation", "required": True, "collectionId": invoices_id, "cascadeDelete": False, "minSelect": 1, "maxSelect": 1}, {"name": "batch", "type": "relation", "required": True, "collectionId": batches_id, "cascadeDelete": True, "minSelect": 1, "maxSelect": 1}, {"name": "waybill_no", "type": "text", "required": False, "options": {"min": 0, "max": 100, "pattern": ""}}, {"name": "fedex_ref_no", "type": "text", "required": False, "options": {"min": 0, "max": 100, "pattern": ""}}, {"name": "notes", "type": "text", "required": False, "options": {"min": 0, "max": 1000, "pattern": ""}}, ], **SUPERUSER_RULES, } def documents_schema(batches_id): return { "name": "JEI_fedex_batch_documents", "type": "base", "fields": [ {"name": "batch", "type": "relation", "required": True, "collectionId": batches_id, "cascadeDelete": True, "minSelect": 1, "maxSelect": 1}, {"name": "doc_type", "type": "select", "required": True, "maxSelect": 1, "values": ["waybill", "sad500", "sad507", "bill_of_entry"]}, {"name": "file", "type": "file", "required": False, "options": {"maxSelect": 1, "maxSize": 0, "mimeTypes": ["application/pdf", "image/png", "image/jpeg"], "thumbs": []}}, {"name": "notes", "type": "text", "required": False, "options": {"min": 0, "max": 500, "pattern": ""}}, ], **SUPERUSER_RULES, } def main(): print(f"PB_URL: {PB_URL}") inv = find_col("JEI_invoices") if not inv: sys.exit("JEI_invoices not found - run scripts/create_collections.py first") b = ensure("JEI_fedex_import_batches", batches_schema) s = ensure("JEI_fedex_shipments", lambda: shipments_schema(inv["id"], b["id"])) d = ensure("JEI_fedex_batch_documents", lambda: documents_schema(b["id"])) print("DONE: 3 JEI_fedex_* collections ready.") if __name__ == "__main__": main()