JEI_Import_Documents-App/scripts/add_exchange_rate_field.py
Mavis 5f73d2ea71 feat: Fedex import flow, orders + invoice APIs, payment bundles
- /fedex: batch create, document upload/replace/delete, save shipment, imported list
- /api/orders, /api/invoices, /api/pb-file, /api/pb/refresh-token, /api/stock-codes
- /api/payments/bundle: generate + download-all remittance bundles
- shared app/components/DocCell.tsx and app/lib/{invoice-docs,pb-fetch,pb-token}.ts
- recon: invoice reconciliation reports and PowerShell fix-plan scripts
- .gitignore: exclude one-off scripts/_* debugging artefacts, recon/pdfs+txts, data backups
2026-10-18 17:27:40 +02:00

117 lines
No EOL
3.6 KiB
Python

"""
Add the `exchange_rate` number field to JEI_payment_batches.
This rate is captured at payment time so the unit price can later be
recalculated in ZAR (e.g. goods cost / batch exchange rate = ZAR per £1).
Stored as a number, optional for legacy batches (default 0), required
for new batches via the create API.
Idempotent: if the field already exists, reports EXISTS.
Run: python scripts/add_exchange_rate_field.py
"""
import os
import sys
import json
import urllib.request
from urllib.error import HTTPError
PB_URL = os.environ.get("PB_URL", "https://pb.agent.apphub.co.za")
PB_TOKEN = os.environ.get("PB_TOKEN", "")
if not PB_TOKEN:
env_path = os.path.join(os.path.dirname(__file__), "..", ".env.local")
if os.path.exists(env_path):
with open(env_path, "r", encoding="utf-8") as fh:
for line in fh:
if line.startswith("PB_TOKEN="):
PB_TOKEN = line.strip().split("=", 1)[1]
break
if not PB_TOKEN:
sys.exit("ERROR: PB_TOKEN not set")
HEADERS = {"Authorization": PB_TOKEN, "Content-Type": "application/json"}
def pb_get(path):
req = urllib.request.Request(PB_URL + path, headers=HEADERS, method="GET")
with urllib.request.urlopen(req, timeout=30) as r:
return json.loads(r.read())
def pb_patch(path, body):
req = urllib.request.Request(
PB_URL + path,
data=json.dumps(body).encode("utf-8"),
headers=HEADERS,
method="PATCH",
)
try:
with urllib.request.urlopen(req, timeout=30) as r:
return json.loads(r.read()), None
except HTTPError as e:
return None, json.loads(e.read())
SUPERUSER_RULES = {
"listRule": "",
"viewRule": "",
"createRule": "",
"updateRule": "",
"deleteRule": "",
}
def main():
print(f"PB_URL: {PB_URL}")
# Find JEI_payment_batches
listing = pb_get("/api/collections?perPage=200")
batches_id = None
for c in listing.get("items", []):
if c.get("name") == "JEI_payment_batches":
batches_id = c.get("id")
break
if not batches_id:
sys.exit("ERROR: JEI_payment_batches collection not found")
print(f"FOUND: JEI_payment_batches (id={batches_id})")
batches = pb_get(f"/api/collections/{batches_id}")
field_names = {f.get("name") for f in batches.get("fields", [])}
if "exchange_rate" in field_names:
print("EXISTS: JEI_payment_batches.exchange_rate field")
return
new_field = {
"name": "exchange_rate",
# Number so we can do arithmetic on it later (ZAR-per-GBP calculations).
# noDecimal=False so users can enter rates like 23.4512.
"type": "number",
"required": False,
"min": 0,
"max": None,
"noDecimal": False,
}
patched_fields = list(batches.get("fields", [])) + [new_field]
clean_fields = [{k: v for k, v in f.items() if k != "options"} for f in patched_fields]
resp, err = pb_patch(f"/api/collections/{batches_id}", {"fields": clean_fields})
if err is not None:
sys.exit(f"ERROR: failed to add exchange_rate field: {err}")
print(f"ADDED: JEI_payment_batches.exchange_rate number field")
# Wake-up round-trip (PB v0.39.8 quirk)
_, err = pb_patch(f"/api/collections/{batches_id}", dict(SUPERUSER_RULES))
if err is not None:
sys.exit(f"ERROR: wake-up PATCH failed: {err}")
print(f"PATCHED: {batches_id} (wake-up round-trip)")
# Verify
check = pb_get(f"/api/collections/{batches_id}/records?perPage=1")
print(f"VERIFIED: totalItems = {check.get('totalItems', '?')}")
print("DONE: JEI_payment_batches.exchange_rate ready.")
if __name__ == "__main__":
main()