72 lines
2.7 KiB
Python
72 lines
2.7 KiB
Python
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)
|