refactor(swap-eod): L0 纯函数出仓——InterestEodScenario/ResolveInterestScenario/FindObservationInterval 移至独立 InterestEodScenarioDispatch(零行为变更)
- 上帝类减重 42 行;枚举与两个纯函数零实例状态、零 DB 依赖,符合 Accrual/ 既有纯函数迁移模式 - 测试不再继承 TestableSwapEodPositionService(原仅为够到 protected),plain 测试类 - SwapEodPositionService 两处调用点改为 InterestEodScenarioDispatch.FindObservationInterval 限定名 - 编译 0 错误;表驱动 8/8 通过
This commit is contained in:
@@ -4,15 +4,12 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
/// <summary>
|
||||
/// DealInterests 分派优先级(TEST-MATRIX §6 空洞补盖)。
|
||||
/// 纯函数 ResolveInterestScenario 的 8 组合表驱动单测,不连库、无 DB。
|
||||
/// 纯函数 InterestEodScenarioDispatch.ResolveInterestScenario 的 8 组合表驱动单测,不连库、无 DB。
|
||||
/// 守卫:手工互换压制观察日自动结息;观察日±平仓区分 autoSwap 真/假;纯平仓与普通日分流。
|
||||
/// 测试类直接继承 TestableSwapEodPositionService 以访问 protected 的枚举与方法。
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public class InterestEodScenarioDispatchTest : TestableSwapEodPositionService
|
||||
public class InterestEodScenarioDispatchTest
|
||||
{
|
||||
public InterestEodScenarioDispatchTest() : base(nameof(InterestEodScenarioDispatchTest)) { }
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow(false, false, false, InterestEodScenario.RollForward)] // 普通日
|
||||
[DataRow(false, false, true, InterestEodScenario.CloseOnly)] // 纯平仓(非观察日)
|
||||
@@ -25,7 +22,7 @@ namespace YLErp.Modules.SwapModule
|
||||
public void ResolveInterestScenario_CoversAllEightCombinations(
|
||||
bool hasInterval, bool hasSwap, bool hasClose, InterestEodScenario expected)
|
||||
{
|
||||
var actual = ResolveInterestScenario(hasInterval, hasSwap, hasClose);
|
||||
var actual = InterestEodScenarioDispatch.ResolveInterestScenario(hasInterval, hasSwap, hasClose);
|
||||
Assert.AreEqual(expected, actual,
|
||||
$"hasInterval={hasInterval}, hasSwap={hasSwap}, hasClose={hasClose}");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using YLErp.Models;
|
||||
|
||||
namespace YLErp.Modules.SwapModule;
|
||||
|
||||
/// <summary>
|
||||
/// 利息腿 EOD 归档场景分派规格(纯函数集;表驱动单测见 InterestEodScenarioDispatchTest)。
|
||||
/// 优先级链(承重业务语义,不能乱序):
|
||||
/// ① hasSwap(手工互换) → 按事件流水重新生成,压制观察日自动结息
|
||||
/// ② observationInterval(观察日) 存在 → 自动结息;同日有平仓 → autoSwap=true
|
||||
/// ③ hasClose(纯平仓, 非观察日) → autoSwap=false
|
||||
/// ④ 普通日 → 复制上一日终并计提当日新增
|
||||
/// 注意:hasSwap/hasClose 是交易级标志(整笔合约当天有无事件),
|
||||
/// observationInterval 是腿级(本条利息腿当天是否观察日)——粒度不同,分派依赖此区分。
|
||||
/// 生产分派点:SwapEodPositionService.DealInterests(分派结构接线前为影子规格,见其分派处注释)。
|
||||
/// </summary>
|
||||
public enum InterestEodScenario
|
||||
{
|
||||
ManualSwap, // ① 手工互换:压制观察日自动结息
|
||||
AutoSettleWithClose, // ② 观察日 + 当日平仓 (autoSwap=true)
|
||||
AutoSettle, // ② 观察日 + 当日无平仓
|
||||
CloseOnly, // ③ 非观察日 + 当日平仓 (autoSwap=false)
|
||||
RollForward, // ④ 普通日滚动
|
||||
}
|
||||
|
||||
public static class InterestEodScenarioDispatch
|
||||
{
|
||||
/// <summary>三分量布尔 → 场景(8 组合表驱动见 InterestEodScenarioDispatchTest)。</summary>
|
||||
public static InterestEodScenario ResolveInterestScenario(bool hasInterval, bool hasSwap, bool hasClose)
|
||||
{
|
||||
if (hasSwap)
|
||||
return InterestEodScenario.ManualSwap;
|
||||
if (hasInterval)
|
||||
return hasClose ? InterestEodScenario.AutoSettleWithClose : InterestEodScenario.AutoSettle;
|
||||
if (hasClose)
|
||||
return InterestEodScenario.CloseOnly;
|
||||
return InterestEodScenario.RollForward;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找利息腿在指定结算日的观察日信息(SwapIntervalList 中 Date==settleDate 且 Settlement==1 的记录)。
|
||||
/// 观察日即自动结息触发日;返回 null 表示当日非观察日。分派见 ResolveInterestScenario。
|
||||
/// </summary>
|
||||
public static IntervalModel FindObservationInterval(swap_position interest, DateTime settleDate)
|
||||
{
|
||||
return interest.SwapIntervalList.FirstOrDefault(x => x.Date == settleDate && x.Settlement == 1);
|
||||
}
|
||||
}
|
||||
@@ -375,7 +375,7 @@ namespace YLErp.Modules.SwapModule
|
||||
IntervalModel observationInterval = null;
|
||||
foreach (var interest in interestList)
|
||||
{
|
||||
observationInterval = FindObservationInterval(interest, settleDate);
|
||||
observationInterval = InterestEodScenarioDispatch.FindObservationInterval(interest, settleDate);
|
||||
if (observationInterval != null)
|
||||
break;
|
||||
}
|
||||
@@ -490,7 +490,7 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
var eodPosition = eodPositions.FirstOrDefault(x => x.PositionId == interest.id);//上一日日终利息信息 可能不存在
|
||||
var tdEodPosition = todyEodPositions.FirstOrDefault(x => x.PositionId == interest.id);//当前结算日日终利息信息
|
||||
var observationInterval = FindObservationInterval(interest, settleDate);//自动互换观察日信息
|
||||
var observationInterval = InterestEodScenarioDispatch.FindObservationInterval(interest, settleDate);//自动互换观察日信息
|
||||
List<swap_flow_event> dealInterests = new List<swap_flow_event>();
|
||||
dealInterests.AddRange(flowEvents);
|
||||
var dealInterest = dealInterests.FirstOrDefault(n => n.PositionId == interest.id);//当日是否做过互换或平仓
|
||||
@@ -533,45 +533,6 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 利息腿 EOD 归档场景分派(纯函数;表驱动单测见 InterestEodScenarioDispatchTest)。
|
||||
/// 优先级链(承重业务语义,不能乱序):
|
||||
/// ① hasSwap(手工互换) → 按事件流水重新生成,压制观察日自动结息
|
||||
/// ② observationInterval(观察日) 存在 → 自动结息;同日有平仓 → autoSwap=true
|
||||
/// ③ hasClose(纯平仓, 非观察日) → autoSwap=false
|
||||
/// ④ 普通日 → 复制上一日终并计提当日新增
|
||||
/// 注意:hasSwap/hasClose 是交易级标志(整笔合约当天有无事件),
|
||||
/// observationInterval 是腿级(本条利息腿当天是否观察日)——粒度不同,分派依赖此区分。
|
||||
/// </summary>
|
||||
public enum InterestEodScenario
|
||||
{
|
||||
ManualSwap, // ① 手工互换:压制观察日自动结息
|
||||
AutoSettleWithClose, // ② 观察日 + 当日平仓 (autoSwap=true)
|
||||
AutoSettle, // ② 观察日 + 当日无平仓
|
||||
CloseOnly, // ③ 非观察日 + 当日平仓 (autoSwap=false)
|
||||
RollForward, // ④ 普通日滚动
|
||||
}
|
||||
|
||||
protected static InterestEodScenario ResolveInterestScenario(bool hasInterval, bool hasSwap, bool hasClose)
|
||||
{
|
||||
if (hasSwap)
|
||||
return InterestEodScenario.ManualSwap;
|
||||
if (hasInterval)
|
||||
return hasClose ? InterestEodScenario.AutoSettleWithClose : InterestEodScenario.AutoSettle;
|
||||
if (hasClose)
|
||||
return InterestEodScenario.CloseOnly;
|
||||
return InterestEodScenario.RollForward;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找利息腿在指定结算日的观察日信息(SwapIntervalList 中 Date==settleDate 且 Settlement==1 的记录)。
|
||||
/// 观察日即自动结息触发日;返回 null 表示当日非观察日。分派见 ResolveInterestScenario。
|
||||
/// </summary>
|
||||
protected static IntervalModel FindObservationInterval(swap_position interest, DateTime settleDate)
|
||||
{
|
||||
return interest.SwapIntervalList.FirstOrDefault(x => x.Date == settleDate && x.Settlement == 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理浮动腿归档
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user