98 lines
3.6 KiB
Python
98 lines
3.6 KiB
Python
"""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
|