"""fin_account 仓储:按客户 ID 取资金账户 + 余额加减(原子 UPDATE)。 注:本表主键为 customer_id(非 id),故不复用 BaseRepository.delete/count 中的 id 约定。 余额增减用原子 UPDATE(balance = balance ± delta)防并发丢更新,不依赖乐观锁重试。 """ from __future__ import annotations from decimal import Decimal from sqlalchemy import select, update from model.fin_account import FinAccount from repositories.base import BaseRepository class FinAccountRepo(BaseRepository): model = FinAccount async def get_by_customer_id(self, customer_id: int) -> FinAccount | None: return await self.db.scalar( select(FinAccount).where(FinAccount.customer_id == customer_id) ) async def create(self, customer_id: int, balance: Decimal) -> FinAccount: """开资金户(充值时账户不存在则自动开户入账)。""" account = FinAccount(customer_id=customer_id, balance=balance) self.db.add(account) await self.db.commit() await self.db.refresh(account) return account async def add_balance(self, customer_id: int, delta: Decimal) -> FinAccount: """入账:balance += delta,原子自增后回读最新余额。""" await self.db.execute( update(FinAccount) .where(FinAccount.customer_id == customer_id) .values( balance=FinAccount.balance + delta, version=FinAccount.version + 1, ) ) await self.db.commit() return await self.get_by_customer_id(customer_id) async def subtract_balance( self, customer_id: int, delta: Decimal ) -> FinAccount | None: """出账:balance -= delta,可用余额(balance - frozen_amount)不足时返回 None。""" result = await self.db.execute( update(FinAccount) .where( FinAccount.customer_id == customer_id, FinAccount.balance - FinAccount.frozen_amount >= delta, ) .values( balance=FinAccount.balance - delta, version=FinAccount.version + 1, ) ) await self.db.commit() if result.rowcount == 0: return None return await self.get_by_customer_id(customer_id) async def deduct_balance(self, customer_id: int, delta: Decimal) -> bool: """申购事务内扣款:balance -= delta(可用余额不足则不动)。 不 commit,由 service 层事务统一提交,保证「扣款 + 加仓」原子性。 可用余额(balance - frozen_amount)不足时返回 False。 """ result = await self.db.execute( update(FinAccount) .where( FinAccount.customer_id == customer_id, FinAccount.balance - FinAccount.frozen_amount >= delta, ) .values( balance=FinAccount.balance - delta, version=FinAccount.version + 1, ) ) return result.rowcount > 0 async def credit_balance(self, customer_id: int, delta: Decimal) -> bool: """赎回事务内入账:balance += delta。 不 commit,由 service 层事务统一提交,保证「减仓 + 入账」原子性。 """ result = await self.db.execute( update(FinAccount) .where(FinAccount.customer_id == customer_id) .values( balance=FinAccount.balance + delta, version=FinAccount.version + 1, ) ) return result.rowcount > 0