Files
group_xinghuo_jinrong/app/repository/share_lot_repository.py
T
GaoYiYuan_0626andWorkBuddy 3244922a55 基金转换 T-3:core_ro 新增 5 个只读方法 + share_lot_repository 读侧
- core_ro 新增 get_nav_as_of(D10) / get_redeem_fee_rules / list_share_lots(S1 确定性排序)
  / sum_remain_qty(仅 >0) / get_holding;不动 get_latest_nav 与 list_trades_range 白名单
- 新增 share_lot_repository:core_share_lot 读侧 FIFO 贪心选批 + 汇总,排序复用 core_ro 的 ORDER BY(D18 单一副本)
- 新增 tests/test_share_lot.py 15 用例;pytest 全量 624 passed / 3 skipped(基线 609,零回归)
- 同步开发计划 §5.1 执行记录与交接文档 §B 状态(v1.5 / T-3 ✅ / 基线 624)

Co-Authored-By: WorkBuddy <workbuddy@tencent.com>
2026-09-10 15:42:55 +08:00

65 lines
2.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""份额批次读侧仓储(jinrong_core · 仅 SELECT)· T-3。
core_share_lot 的读侧封装:FIFO 选批 + 可用份额汇总。写侧(扣减 / 补建新批)
归 `convert_core_repository`(D2),本文件不写。
D18(单一副本):FIFO 排序规则(confirmed_at ASC, lot_id ASC)的唯一出处是
`CoreReadOnlyRepository.list_share_lots` 的 ORDER BY —— 本类复用它取批次,
**不另写一份排序 SQL**,贪心分配只在 Python 端做,避免排序口径漂移。
"""
from __future__ import annotations
from decimal import Decimal
from typing import Any
from sqlalchemy.engine import Engine
from app.config.settings import settings
from app.repository.core_ro import CoreReadOnlyRepository
from app.utils.db import get_engine
class ShareLotRepository:
"""core_share_lot 读侧:FIFO 选批 + 汇总(D2:写侧在 convert_core_repository)。"""
def __init__(self, engine: Engine | None = None) -> None:
self._engine = engine or get_engine(settings.mysql_core_database, "ro")
# 复用 core_ro 的 ORDER BY(D18 单一副本),避免排序规则漂移
self._core = CoreReadOnlyRepository(engine=self._engine)
def select_for_convert(
self, customer_id: str, product_id: str, qty: Decimal
) -> list[dict[str, Any]]:
"""FIFO 选批:按 confirmed_at ASC, lot_id ASC 贪心覆盖 `qty`。
返回被选中的批次(dict:lot_id / qty 本次可用 / nav / confirmed_at)。
若可用份额不足 `qty`,返回全部可用批次(差额由调用方校验,读侧不抛业务异常)。
零请求量返回空列表。
"""
if qty <= 0:
return []
remaining = Decimal(qty)
selected: list[dict[str, Any]] = []
for lot in self._core.list_share_lots(customer_id, product_id):
if remaining <= 0:
break
available = Decimal(lot["remain_qty"])
if available <= 0:
continue
take = min(available, remaining)
selected.append(
{
"lot_id": lot["lot_id"],
"qty": take,
"nav": Decimal(lot["nav"]),
"confirmed_at": lot["confirmed_at"],
}
)
remaining -= take
return selected
def available_qty(self, customer_id: str, product_id: str) -> Decimal:
"""可用份额合计(委托 core_ro.sum_remain_qty,仅统计 remain_qty > 0)。"""
return self._core.sum_remain_qty(customer_id, product_id)