Files
Solo_bot/api/v2/routes/coupons.py
T
2026-04-14 07:19:14 +00:00

73 lines
2.6 KiB
Python

from fastapi import Depends, HTTPException, Request
from sqlalchemy.ext.asyncio import AsyncSession
from api.depends import get_request_actor, get_session, verify_identity_token
from api.v2.base_crud import generate_crud_router
from api.v2.schemas import CouponBase, CouponResponse, CouponUpdate
from api.v2.schemas.web_public import CouponApplyRequest, CouponApplyResponse
from database import identities as idb
from database.models import Coupon
from services.coupons import apply_fixed_coupon
from services.errors import LimitExceededError, NotFoundError, ServiceError, ValidationError
router = generate_crud_router(
model=Coupon,
schema_response=CouponResponse,
schema_create=CouponBase,
schema_update=CouponUpdate,
identifier_field="code",
parameter_name="code",
enabled_methods=["get_all", "get_one", "create", "update", "delete"],
)
async def _resolve_coupon_user_id(session: AsyncSession, request: Request, identity) -> tuple[int, int | None]:
actor = get_request_actor(request)
billing_user_id = actor.billing_user_id if actor and actor.billing_user_id is not None else None
if billing_user_id is None:
billing_user_id = await idb.ensure_billing_user_for_identity(session, identity)
tg_id = actor.telegram_chat_id if actor else None
return int(billing_user_id), tg_id
def _service_error_to_http(e: ServiceError) -> HTTPException:
status_map = {
"not_found": 404,
"limit_exceeded": 409,
"validation_error": 400,
"forbidden": 403,
}
return HTTPException(status_code=status_map.get(e.code, 400), detail=e.message)
@router.post("/apply", response_model=CouponApplyResponse)
async def apply_coupon(
body: CouponApplyRequest,
request: Request,
session: AsyncSession = Depends(get_session),
identity=Depends(verify_identity_token),
):
user_id, tg_id = await _resolve_coupon_user_id(session, request, identity)
try:
result = await apply_fixed_coupon(
session=session,
user_id=user_id,
tg_id=tg_id,
code=str(body.code or ""),
)
await session.commit()
return CouponApplyResponse(
ok=True,
message="Купон успешно активирован",
coupon_code=result.coupon_code,
amount=result.amount,
balance=result.balance,
)
except ServiceError as e:
await session.rollback()
raise _service_error_to_http(e)
except Exception:
await session.rollback()
raise HTTPException(status_code=500, detail="Ошибка активации купона")