import csv import io from datetime import date from typing import Annotated from fastapi import APIRouter, Depends, Query from fastapi.responses import StreamingResponse import asyncpg from app.core.pagination import pagination_params from app.core.responses import ok, paginated from app.dependencies import get_db, require_admin from app.models.orders import UpdateOrderStatus, RefundRequest from app.services import order_service router = APIRouter(prefix="/orders", tags=["Admin — Orders"]) @router.get("") async def list_orders( pagination: Annotated[tuple, Depends(pagination_params)], status: str | None = Query(None), from_date: date | None = Query(None), to_date: date | None = Query(None), db: asyncpg.Connection = Depends(get_db), _: dict = Depends(require_admin), ): page, per_page, offset = pagination orders, total = await order_service.list_orders(db, page, per_page, offset, status=status) return paginated(orders, total, page, per_page) @router.get("/export") async def export_orders( status: str | None = Query(None), db: asyncpg.Connection = Depends(get_db), _: dict = Depends(require_admin), ): rows = await db.fetch( """ SELECT o.id, p.email, p.full_name, o.status, o.total_amount, o.created_at FROM orders o JOIN profiles p ON p.id = o.user_id ORDER BY o.created_at DESC """ ) output = io.StringIO() writer = csv.writer(output) writer.writerow(["ID", "Email", "Name", "Status", "Total", "Date"]) for r in rows: writer.writerow([r["id"], r["email"], r["full_name"], r["status"], r["total_amount"], r["created_at"]]) output.seek(0) return StreamingResponse( iter([output.getvalue()]), media_type="text/csv", headers={"Content-Disposition": "attachment; filename=orders.csv"}, ) @router.get("/{order_id}") async def get_order( order_id: str, db: asyncpg.Connection = Depends(get_db), _: dict = Depends(require_admin), ): order = await order_service.get_order(db, order_id) return ok(order) @router.patch("/{order_id}/status") async def update_status( order_id: str, body: UpdateOrderStatus, db: asyncpg.Connection = Depends(get_db), admin: dict = Depends(require_admin), ): order = await order_service.update_order_status(db, order_id, body.status, str(admin["id"])) return ok(order) @router.post("/{order_id}/refund") async def refund_order( order_id: str, body: RefundRequest, db: asyncpg.Connection = Depends(get_db), admin: dict = Depends(require_admin), ): order = await order_service.refund_order(db, order_id, str(admin["id"]), body.amount, body.reason) return ok(order)