Files
zszq-trs/UnitTestProject/Modules/SwapModule/TestableSwapEodPositionService.cs
T
张名锐 aa3548e77f feat(bond): 支持债券与股票基金公司行为现金流计算的差异化处理 - init2
- 修改 CalcPayment 方法添加 useBondPriceScale 参数区分债券和股票/基金的金额计算口径
- 债券利息按每100元面值票息通过BondPriceConverter转为入库金额,股票基金分红直接计算
- 在BondPaymentService中添加详细的参数说明文档注释
- 更新SwapDealService中分红计算逻辑,根据标的类型自动选择合适的金额转换方式
- 新增CorporateActionEventLifecycleTest单元测试验证公司行为事件生命周期管理
- 添加SplitCorporateActionTddTest测试验证拆合股功能
- 优化FundCorporateActionRollbackAndUnwindTest扩展到股票类型测试
- 更新前端OperationHistory页面表格列宽和显示格式支持更长的说明信息
2026-08-19 17:48:34 +08:00

139 lines
5.9 KiB
C#
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.
using YLErp.DBModels;
using YLErp.DBModels.Enums;
using YLErp.Model;
namespace YLErp.Modules.SwapModule
{
/// <summary>
/// SwapEodPositionService 的可测试化基类(纯内存,不连库)。
/// ============================================================================
/// 收敛各 ScenarioTest 中 Stub 子类的重复 override
/// - PersistEodSwapPosition:收集到列表,不写库
/// - SaveAllChangesno-op
/// - GetCurrencyRate:返回 1.0(本币)
/// - 统一构造函数(注入 OptUserInfo,标记 UnitTest 来源)
///
/// 暴露 PersistedPositions / SaveChangesCount / ClientCashCalls 等输出捕获属性,
/// 供断言使用。各测试子类按需再 override 业务 seamFindTrade/GetUnderlyingPrice 等)。
///
/// 设计原则:
/// - 只收敛 8/8 Stub 都重复的高频 override,不预设业务数据注入方式
/// ComposePage 用属性字典、SwapPositionCompose 用构造函数 List,差异留给子类)
/// - 不提供 Execute* 包装器(签名各异且大多只出现 1-2 次,留在各子类避免基类膨胀)
/// ============================================================================
/// </summary>
public class TestableSwapEodPositionService : SwapEodPositionService
{
/// <summary>捕获所有持久化的 eod 持仓(按调用顺序)</summary>
public List<eod_swap_position> PersistedPositions { get; } = new();
/// <summary>
/// 捕获所有持久化的互换流水事件(按调用顺序)。
/// 生产 PersistFlowEvent 写 DbContext.swap_flow_eventGetConsumedInterest 也读同一张表。
/// 测试不连库,这里把真实收盘产生的 swap_flow_event 收集起来,
/// 使 GetConsumedInterest 能像生产一样从"真实累积的流水"里算已结利息,
/// 而无需硬编码、无需连库。这是消除"return 0m"伪绿的关键。
/// </summary>
public List<swap_flow_event> FlowEvents { get; } = new();
/// <summary>SaveAllChanges 调用次数</summary>
public int SaveChangesCount { get; private set; }
/// <summary>AddClientCash 调用记录(金额, 操作)</summary>
public List<(double amount, string action)> ClientCashCalls { get; } = new();
/// <summary>SwapPositionCompose 使用的公司行为内存数据;默认空,避免测试访问数据库。</summary>
public List<ex_dividend_info> ExDividendInfos { get; } = new();
/// <summary>捕获公司行为生命周期事件,避免事件测试访问真实 swap_event 表。</summary>
public List<swap_event> CorporateActionEvents { get; } = new();
/// <summary>自增 id 模拟器(新增 eod 时分配 id</summary>
private int _nextId = 1;
protected TestableSwapEodPositionService(string testName)
: base(new OptUserInfo(0, testName ?? nameof(TestableSwapEodPositionService), OptUserFrom.UnitTest))
{
}
// ===== 高频 seam override8/8 Stub 都重复,收敛到基类)=====
protected override void PersistEodSwapPosition(eod_swap_position position)
{
if (position.id == 0) position.id = _nextId++;
PersistedPositions.Add(position);
}
/// <summary>
/// 捕获真实收盘产生的 swap_flow_event(生产写 DbContext.swap_flow_event)。
/// 与 PersistEodSwapPosition 同理,这里只收集不写库,供 GetConsumedInterest 真实计算。
/// </summary>
protected void PersistFlowEvent(swap_flow_event flowEvent)
{
if (flowEvent.id == 0) flowEvent.id = _nextId++;
FlowEvents.Add(flowEvent);
}
protected override void SaveAllChanges()
{
SaveChangesCount++;
}
protected override double GetCurrencyRate(string quoteCurrency, string settlementCurrency, DateTime valueDate, bool seekPreday, CurrencyRateType currencyRateType)
{
return 1.0; // 本币,汇率=1
}
protected override List<ex_dividend_info> FindExDividendInfos(DateTime settleDate)
{
return ExDividendInfos
.Where(x => x.ValidStatus
&& x.EffectiveDate.HasValue
&& x.EffectiveDate.Value.Date == settleDate.Date)
.ToList();
}
protected override List<ex_dividend_info> FindCorporateActionInfos(DateTime settleDate)
{
return ExDividendInfos
.Where(x => x.ValidStatus
&& (x.ExDividendDate?.Date == settleDate.Date
|| x.EffectiveDate?.Date == settleDate.Date))
.ToList();
}
protected override List<ex_dividend_info> FindRegistrationExDividendInfos(DateTime settleDate)
{
return ExDividendInfos
.Where(x => x.ValidStatus
&& x.ExDividendDate.HasValue
&& x.ExDividendDate.Value.Date == settleDate.Date)
.ToList();
}
protected override List<swap_event> FindCorporateActionEvents(int swapTradeId)
{
return CorporateActionEvents
.Where(x => x.SwapTradeId == swapTradeId && !x.Invalid
&& x.EventType == (int)SwapEventTypeEnum.公司行为)
.ToList();
}
protected override decimal GetFundCorporateActionClosePrice(
ex_dividend_info dividendInfo,
decimal fallbackPrice)
=> fallbackPrice;
protected override decimal GetDividendTaxRate()
{
return 0m;
}
protected override int AddClientCash(trade td, double amount, string action, DateTime valueDate)
{
ClientCashCalls.Add((amount, action));
return _nextId++;
}
}
}