73 lines
2.6 KiB
Python
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="Ошибка активации купона")
|