94 lines
3.5 KiB
Python
94 lines
3.5 KiB
Python
|
|
"""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)}")
|