import httpx from fastapi import APIRouter, Depends, Query from sqlalchemy import text from . import vault from .auth import require_token from .db import get_db # The MEGA admin — back-office cockpit, all admin-gated. Inspired by WowPlatter's wp-admin nav # (Dashboard / Inventory / Orders / Import / Sales / Reports), but on RecordGod's own data. router = APIRouter(prefix="/admin", tags=["admin"]) @router.get("/stats") async def stats(ident=Depends(require_token), db=Depends(get_db)): s = ident["store_id"] row = (await db.execute(text(""" SELECT (SELECT count(*) FROM inventory WHERE store_id=:s) AS items, (SELECT count(*) FROM inventory WHERE store_id=:s AND in_stock) AS in_stock, (SELECT count(*) FROM inventory WHERE store_id=:s AND kind='vinyl') AS vinyl, (SELECT count(*) FROM inventory WHERE store_id=:s AND kind<>'vinyl') AS other_goods, (SELECT coalesce(sum(price),0)::float FROM inventory WHERE store_id=:s AND in_stock) AS stock_value, (SELECT count(*) FROM inventory WHERE staged) AS staged, (SELECT count(*) FROM crate) AS crates, (SELECT count(*) FROM sales) AS sales, (SELECT coalesce(sum(total),0)::float FROM sales) AS sales_total """), {"s": s})).mappings().first() return {"ok": True, **dict(row)} @router.get("/inventory") async def inventory(q: str = Query(""), kind: str = Query(""), page: int = Query(1, ge=1), ident=Depends(require_token), db=Depends(get_db)): per = 50 where = ["i.store_id = :s"] params = {"s": ident["store_id"], "per": per, "off": (page - 1) * per} if q: where.append("(i.sku ILIKE :q OR coalesce(i.title,dc.title) ILIKE :q OR dc.artist ILIKE :q)") params["q"] = f"%{q}%" if kind: where.append("i.kind = :k") params["k"] = kind w = " AND ".join(where) items = [dict(r) for r in (await db.execute(text(f""" SELECT i.sku, i.kind, i.release_id, coalesce(i.title, dc.title) AS title, dc.artist, i.price::float AS price, i.condition, i.in_stock, i.crate_id, c.label_text AS crate, dc.thumb, i.target_price::float AS target FROM inventory i LEFT JOIN disc_cache dc ON dc.release_id = i.release_id LEFT JOIN crate c ON c.id = i.crate_id WHERE {w} ORDER BY i.updated_at DESC NULLS LAST LIMIT :per OFFSET :off """), params)).mappings()] cparams = {k: v for k, v in params.items() if k not in ("per", "off")} total = (await db.execute(text( f"SELECT count(*) FROM inventory i LEFT JOIN disc_cache dc ON dc.release_id=i.release_id WHERE {w}" ), cparams)).scalar() return {"ok": True, "items": items, "page": page, "per": per, "total": total} @router.get("/orders") async def orders(ident=Depends(require_token), db=Depends(get_db)): base = await vault.get_secret(db, "woo_base_url") ck = await vault.get_secret(db, "woo_consumer_key") cs = await vault.get_secret(db, "woo_consumer_secret") if not (base and ck and cs): return {"ok": False, "reason": "WooCommerce not connected — add keys in Connections"} try: async with httpx.AsyncClient(timeout=20, follow_redirects=True) as c: r = await c.get(base.rstrip("/") + "/wp-json/wc/v3/orders", params={"per_page": 20, "orderby": "date", "order": "desc"}, auth=(ck, cs)) except Exception as e: return {"ok": False, "reason": f"connection error: {e}"} if r.status_code != 200: return {"ok": False, "reason": f"Woo API HTTP {r.status_code}"} out = [] for o in r.json(): b = o.get("billing", {}) name = (b.get("first_name", "") + " " + b.get("last_name", "")).strip() or b.get("email", "") out.append({"id": o["id"], "number": o.get("number"), "status": o.get("status"), "total": o.get("total"), "currency": o.get("currency"), "date": (o.get("date_created") or "")[:10], "customer": name, "items": len(o.get("line_items", []))}) return {"ok": True, "orders": out}