- /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
150 lines
No EOL
4.4 KiB
Python
150 lines
No EOL
4.4 KiB
Python
"""
|
|
Add the JEI_orders collection for the /order tab "Saved orders" feature.
|
|
|
|
Stores a named snapshot of the OrderClient's lines so the user can save
|
|
drafts and reload them later. `lines` is a JSON column carrying the full
|
|
Line[] payload (code, description, qty, unit_price, ref invoice no/date).
|
|
|
|
Idempotent: if the collection exists already, the script reports EXISTS.
|
|
|
|
Run: python scripts/add_jei_orders_collection.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_post(path, body):
|
|
req = urllib.request.Request(
|
|
PB_URL + path,
|
|
data=json.dumps(body).encode("utf-8"),
|
|
headers=HEADERS,
|
|
method="POST",
|
|
)
|
|
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())
|
|
|
|
|
|
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 orders_schema():
|
|
return {
|
|
"name": "JEI_orders",
|
|
"type": "base",
|
|
"fields": [
|
|
{
|
|
"name": "name",
|
|
"type": "text",
|
|
"required": True,
|
|
"min": 1,
|
|
"max": 100,
|
|
"pattern": "",
|
|
},
|
|
{
|
|
# JSON column carrying the OrderClient lines snapshot.
|
|
# Schema is open: array of objects with at least
|
|
# { stockId, code, description, qty, unitPrice,
|
|
# refInvoiceNo, refInvoiceDate }.
|
|
"name": "lines",
|
|
"type": "json",
|
|
"required": True,
|
|
"maxSize": 200000,
|
|
},
|
|
{
|
|
# Free-text notes shown next to the saved order in the
|
|
# "Saved orders" panel. Optional.
|
|
"name": "notes",
|
|
"type": "text",
|
|
"required": False,
|
|
"min": 0,
|
|
"max": 1000,
|
|
"pattern": "",
|
|
},
|
|
],
|
|
**SUPERUSER_RULES,
|
|
}
|
|
|
|
|
|
def main():
|
|
print(f"PB_URL: {PB_URL}")
|
|
|
|
listing = pb_get("/api/collections?perPage=200")
|
|
orders_id = None
|
|
for c in listing.get("items", []):
|
|
if c.get("name") == "JEI_orders":
|
|
orders_id = c.get("id")
|
|
break
|
|
|
|
if orders_id:
|
|
print(f"EXISTS: JEI_orders (id={orders_id})")
|
|
return
|
|
|
|
resp, err = pb_post("/api/collections", orders_schema())
|
|
if err is not None:
|
|
sys.exit(f"ERROR: failed to create JEI_orders: {err}")
|
|
orders_id = resp.get("id")
|
|
print(f"CREATED: JEI_orders (id={orders_id})")
|
|
|
|
# Wake-up round-trip (PB v0.39.8 quirk: a freshly created collection
|
|
# 403s on subsequent reads until at least one rule field is PATCHed).
|
|
_, err = pb_patch(f"/api/collections/{orders_id}", dict(SUPERUSER_RULES))
|
|
if err is not None:
|
|
sys.exit(f"ERROR: wake-up PATCH failed: {err}")
|
|
print(f"PATCHED: {orders_id} (wake-up round-trip)")
|
|
|
|
# Verify it's actually readable now
|
|
check = pb_get(f"/api/collections/{orders_id}/records?perPage=1")
|
|
print(f"VERIFIED: totalItems = {check.get('totalItems', '?')}")
|
|
|
|
print("DONE: JEI_orders schema ready.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |