JEI_Import_Documents-App/scripts/export_lists.py

94 lines
3.5 KiB
Python
Raw Normal View History

"""Export two GBP lists: per-stock-code summary + per-line items."""
import os, json, urllib.request
from pathlib import Path
from collections import defaultdict
env = Path(__file__).resolve().parent.parent / ".env.local"
PB_TOKEN = None
for line in open(env):
if line.startswith("PB_TOKEN="):
PB_TOKEN = line.strip().split("=", 1)[1]
break
H = {"Authorization": PB_TOKEN}
# Load stock codes
sc = json.loads(urllib.request.urlopen(urllib.request.Request(
"https://pb.agent.apphub.co.za/api/collections/JEI_stock_codes/records?perPage=500&sort=code",
headers=H)).read())
codes = {c["id"]: c for c in sc["items"]}
# Load invoices
inv = json.loads(urllib.request.urlopen(urllib.request.Request(
"https://pb.agent.apphub.co.za/api/collections/JEI_invoices/records?perPage=500&sort=-invoice_date",
headers=H)).read())
invs = {i["id"]: i for i in inv["items"]}
# Load lines
lines = json.loads(urllib.request.urlopen(urllib.request.Request(
"https://pb.agent.apphub.co.za/api/collections/JEI_invoice_lines/records?perPage=5000&sort=invoice",
headers=H)).read())
# --- LIST 1: per-stock-code aggregated ---
agg = defaultdict(lambda: {"qty": 0.0, "value": 0.0, "prices": []})
for l in lines["items"]:
sc_id = l["stock_code"]
if sc_id not in codes:
continue
agg[sc_id]["qty"] += l["quantity"]
agg[sc_id]["value"] += l["net_amount"]
if l["unit_price"]:
agg[sc_id]["prices"].append(l["unit_price"])
# --- LIST 2: per-line items, sorted by invoice then line_no ---
inv_lines = []
for l in lines["items"]:
sc_id = l["stock_code"]
if sc_id not in codes:
continue
inv_id = l["invoice"]
inv_obj = invs.get(inv_id, {})
inv_lines.append({
"invoice_date": inv_obj.get("invoice_date", "")[:10],
"invoice_no": inv_obj.get("invoice_no", ""),
"line_no": l["line_no"],
"stock_code": codes[sc_id]["code"],
"description": codes[sc_id]["description_goods"],
"qty": l["quantity"],
"unit": l["unit_price"],
"net": l["net_amount"],
})
# Output
print("=" * 130)
print("LIST 1 — PER-STOCK-CODE SUMMARY (aggregated across all invoices)")
print("=" * 130)
print(f"{'Stock code':<22} {'Description':<55} {'Qty':>8} {'Avg £':>9} {'Min £':>9} {'Max £':>9} {'Total £':>11}")
print("-" * 130)
total_qty = 0
total_val = 0
for sc_id in sorted(agg.keys(), key=lambda i: codes[i]["code"]):
c = codes[sc_id]
s = agg[sc_id]
avg = (sum(s["prices"]) / len(s["prices"])) if s["prices"] else 0
mn = min(s["prices"]) if s["prices"] else 0
mx = max(s["prices"]) if s["prices"] else 0
total_qty += s["qty"]
total_val += s["value"]
desc = (c["description_goods"] or "")[:54]
print(f"{c['code']:<22} {desc:<55} {s['qty']:>8.1f} {avg:>9.2f} {mn:>9.2f} {mx:>9.2f} {s['value']:>11.2f}")
print("-" * 130)
print(f"{'TOTAL':<22} {'':<55} {total_qty:>8.1f} {'':>9} {'':>9} {'':>9} {total_val:>11.2f}")
print()
print("=" * 130)
print("LIST 2 — PER-LINE ITEMS (every invoice line, sorted by invoice date then line number)")
print("=" * 130)
print(f"{'Date':<12} {'Invoice':<10} {'#':>4} {'Stock code':<18} {'Description':<45} {'Qty':>6} {'Unit £':>9} {'Net £':>10}")
print("-" * 130)
inv_lines.sort(key=lambda x: (x["invoice_date"], x["invoice_no"], x["line_no"]))
for r in inv_lines:
desc = (r["description"] or "")[:44]
print(f"{r['invoice_date']:<12} {r['invoice_no']:<10} {r['line_no']:>4} {r['stock_code']:<18} {desc:<45} {r['qty']:>6.1f} {r['unit']:>9.2f} {r['net']:>10.2f}")
print("-" * 130)
print(f" Total lines: {len(inv_lines)}")