"""fin_holdings 持仓仓储:按客户(+状态)查持仓、申购加仓 upsert、赎回减仓。""" from __future__ import annotations from decimal import Decimal from sqlalchemy import case, select, update from sqlalchemy.dialects.mysql import insert as mysql_insert from model.fin_holdings import FinHoldings from repositories.base import BaseRepository class FinHoldingsRepo(BaseRepository): model = FinHoldings async def list_by_customer( self, customer_id: int, status: str | None = None ) -> list[FinHoldings]: """按客户 ID 查持仓,可按状态过滤(status=None 表示不过滤)。""" stmt = select(FinHoldings).where(FinHoldings.customer_id == customer_id) if status is not None: stmt = stmt.where(FinHoldings.status == status) stmt = stmt.order_by(FinHoldings.id) return list((await self.db.scalars(stmt)).all()) async def get_by_customer_product( self, customer_id: int, product_id: int ) -> FinHoldings | None: return await self.db.scalar( select(FinHoldings).where( FinHoldings.customer_id == customer_id, FinHoldings.product_id == product_id, ) ) async def upsert( self, customer_id: int, product_id: int, add_shares: Decimal, add_cost: Decimal ) -> None: """申购加仓:有则加份额/成本,无则新增(靠 uk_customer_product 唯一键)。不 commit。""" stmt = mysql_insert(FinHoldings).values( customer_id=customer_id, product_id=product_id, shares=add_shares, cost_amount=add_cost, ) stmt = stmt.on_duplicate_key_update( shares=FinHoldings.shares + add_shares, cost_amount=FinHoldings.cost_amount + add_cost, ) await self.db.execute(stmt) async def redeem( self, customer_id: int, product_id: int, redeem_shares: Decimal ) -> bool: """赎回减仓:shares -= redeem_shares,份额归 0 时状态置'已清仓'。 持仓份额不足(含无持仓、shares=0)时不动作,返回 False。 不 commit,由 service 层事务统一提交,保证「减仓 + 入账」原子性。 """ result = await self.db.execute( update(FinHoldings) .where( FinHoldings.customer_id == customer_id, FinHoldings.product_id == product_id, FinHoldings.shares >= redeem_shares, ) .values( shares=FinHoldings.shares - redeem_shares, status=case( (FinHoldings.shares - redeem_shares == 0, "已清仓"), else_=FinHoldings.status, ), ) ) return result.rowcount > 0