ssulbox/backend/app/credit_service.py

39 lines
1.5 KiB
Python

# -*- coding: utf-8 -*-
"""크레딧 충전/차감 (원장 기록). castad credit_service 패턴 축약."""
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from .models import CreditTransaction, User
class InsufficientCreditError(Exception):
pass
async def _record(session, user_uuid, amount, balance_after, type_, reason):
tx = CreditTransaction(
user_uuid=user_uuid, amount=amount, balance_after=balance_after, type=type_, reason=reason,
)
session.add(tx)
return tx
async def charge(session: AsyncSession, user_uuid: str, amount: int, type_: str = "charge", reason: str | None = None):
user = (await session.execute(select(User).where(User.user_uuid == user_uuid).with_for_update())).scalar_one_or_none()
if user is None:
raise ValueError("user not found")
user.credits += amount
await session.flush()
return await _record(session, user_uuid, amount, user.credits, type_, reason)
async def deduct(session: AsyncSession, user_uuid: str, amount: int, type_: str = "consume", reason: str | None = None):
user = (await session.execute(select(User).where(User.user_uuid == user_uuid).with_for_update())).scalar_one_or_none()
if user is None:
raise ValueError("user not found")
if user.credits < amount:
raise InsufficientCreditError()
user.credits -= amount
await session.flush()
return await _record(session, user_uuid, -amount, user.credits, type_, reason)