39 lines
1.5 KiB
Python
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)
|