Spaces:
Sleeping
Sleeping
| """ | |
| Admin-facing order endpoints. | |
| Matches the admin frontend (Orders.jsx): | |
| POST /api/order/list -> {success, orders: [...]} | |
| POST /api/order/status -> {orderId, status} -> {success, message} | |
| Reuses the same `orders` table that /api/orders writes to. Just remaps the | |
| field names so the admin UI can render its existing layout untouched. | |
| """ | |
| import asyncpg | |
| from fastapi import APIRouter, Body, Depends, HTTPException | |
| from app.db.asyncpg_pool import get_asyncpg_conn | |
| from app.audit import audit | |
| router = APIRouter() | |
| def _row_to_admin_order(row) -> dict: | |
| """Map the orders table row to the shape Orders.jsx expects.""" | |
| delivery = row["delivery_info"] or {} | |
| if isinstance(delivery, str): | |
| import json as _json | |
| delivery = _json.loads(delivery or "{}") | |
| items = row["items"] or [] | |
| if isinstance(items, str): | |
| import json as _json | |
| items = _json.loads(items or "[]") | |
| return { | |
| "_id": row["order_id"], | |
| "userId": row["user_id"], | |
| "items": items, | |
| "address": delivery, | |
| "amount": float(row["total"]), | |
| "total": float(row["total"]), | |
| "paymentMethod": row["payment_method"], | |
| "status": row["status"], | |
| "date": row["created_at"].isoformat() if row["created_at"] else None, | |
| "payment": True, # legacy field some admin UIs read | |
| } | |
| async def list_admin_orders(conn: asyncpg.Connection = Depends(get_asyncpg_conn)): | |
| rows = await conn.fetch("SELECT * FROM orders ORDER BY created_at DESC") | |
| return {"success": True, "orders": [_row_to_admin_order(r) for r in rows]} | |
| async def update_admin_order_status( | |
| body: dict = Body(...), | |
| conn: asyncpg.Connection = Depends(get_asyncpg_conn), | |
| ): | |
| order_id = body.get("orderId") | |
| new_status = body.get("status") | |
| if not order_id or not new_status: | |
| return {"success": False, "message": "Missing 'orderId' or 'status'"} | |
| # Frontend uses "Packing" but our enum was "Processing" — keep both valid. | |
| allowed = { | |
| "Order Placed", "Packing", "Processing", "Shipped", | |
| "Out for Delivery", "Delivered", | |
| } | |
| if new_status not in allowed: | |
| return {"success": False, "message": f"Invalid status '{new_status}'"} | |
| existing = await conn.fetchval( | |
| "SELECT id FROM orders WHERE order_id = $1", order_id | |
| ) | |
| if not existing: | |
| return {"success": False, "message": "Order not found"} | |
| await conn.execute( | |
| "UPDATE orders SET status = $1 WHERE order_id = $2", | |
| new_status, order_id, | |
| ) | |
| await audit(conn, None, "order.status", order_id, {"status": new_status}) | |
| return {"success": True, "message": "Status updated"} | |