from fastapi import APIRouter, Header, HTTPException, Request from app.core.deps import CurrentUser, DbSession from app.core.rate_limit import enforce_rate_limit from app.schemas.orders import OrderCheckoutResponse, OrderCreate, OrderPublic, PaymentVerifyRequest from app.services.orders import cancel_pending_order, create_order, get_order_for_user from app.core.config import get_settings from app.services.payments.service import ( build_checkout_payload, mock_complete_pending_order, verify_checkout_and_confirm, ) router = APIRouter(prefix="/orders", tags=["orders"]) @router.post("", response_model=OrderCheckoutResponse, status_code=201) def post_order( body: OrderCreate, db: DbSession, user: CurrentUser, idempotency_key: str | None = Header(default=None, alias="Idempotency-Key"), ) -> OrderCheckoutResponse: order = create_order(db, user, body, idempotency_key=idempotency_key) payment = build_checkout_payload(order) return OrderCheckoutResponse( **OrderPublic.model_validate(order).model_dump(), payment=payment, ) @router.get("/{order_id}", response_model=OrderPublic) def get_order(order_id: int, db: DbSession, user: CurrentUser) -> OrderPublic: order = get_order_for_user(db, order_id, user.id) return OrderPublic.model_validate(order) @router.post("/{order_id}/payment/verify", response_model=OrderPublic) def verify_order_payment( order_id: int, body: PaymentVerifyRequest, request: Request, db: DbSession, user: CurrentUser, ) -> OrderPublic: enforce_rate_limit(request, scope="payment_verify", limit=30, window_seconds=60) order = get_order_for_user(db, order_id, user.id) order = verify_checkout_and_confirm( db, order=order, provider_order_id=body.provider_order_id, provider_payment_id=body.provider_payment_id, signature=body.signature, ) return OrderPublic.model_validate(order) @router.post("/{order_id}/cancel", response_model=OrderPublic) def cancel_order(order_id: int, db: DbSession, user: CurrentUser) -> OrderPublic: order = get_order_for_user(db, order_id, user.id) order = cancel_pending_order(db, order) return OrderPublic.model_validate(order) @router.post("/{order_id}/payment/mock-complete", response_model=OrderPublic) def dev_mock_complete_payment(order_id: int, db: DbSession, user: CurrentUser) -> OrderPublic: settings = get_settings() if settings.environment.lower() != "development" or settings.payment_provider.lower() != "mock": raise HTTPException(status_code=404, detail="Not found") order = get_order_for_user(db, order_id, user.id) order = mock_complete_pending_order(db, order) return OrderPublic.model_validate(order)