fix(swap): 待结算分红收益(DividendPending)改用 EOD 全量口径,修复 e3c473ba 的硬0回归

e3c473ba 把前端 DividendPending 硬编码 0,对 GLMS-20260105-0004(PosiDividendSum 恰好=0)
测试通过、掩盖问题。但对 PosiDividendSum≠0 的部分平仓交易,硬0 会落库
(SwapFlowEventService:588 冲账取负写入 swap_flow_event.DividendPending)并在事件列表
"待结算分红收益"列显示错误的 0——是确定的回归。

口径论证(代码证据,非拍板):DividendPending(待结算存量) ↔ EOD PosiDividendSum(未实现),
字段名、递推公式(SwapEodPositionService:1825 已扣当日实现)、列标签(SwapflowList:561)、
旧前端意图(posiQty×totalInterest 想表达"平仓后剩余")四处同指全量口径。是存量非流量,
不按本次平仓比例分摊。

改动:
- SwapDealService.InitUnwind:GetPreEodDividendSum 返回值取一次,同时喂 DividendIn 与
  DividendPending(避免重复查库);GetPreEodDividendSum 注释补口径论证+历史教训(防后人改回硬0/分摊)
- 前端 unwindSwapTrade.js:删除 DividendPending=0 硬写,保持后端值不动
- 前端 incomeSwapTrade.js:DividendPending 保持 0(互换=全量结清,结清后待结算归0),
  注释说明与平仓页口径差异
- 测试补非0场景:GLMS-20260706-0004(PosiDividendSum=-150,000)验证返回非0真实值,
  直接针对"硬0被0掩盖"盲区,防止该回归复现

全量构建 0 错误,4 个分红测试全绿(含 0 场景、互换页、无EOD防御、非0场景)。
This commit is contained in:
hjhan
2026-08-07 09:28:18 +08:00
parent aaeb4bddf8
commit 1bf517188c
4 changed files with 94 additions and 11 deletions
@@ -154,5 +154,66 @@ namespace YLErp.Modules.SwapModule
}
finally { db?.Dispose(); }
}
// ============================================================================
// 非0场景验收(关键防回归)
// ----------------------------------------------------------------------------
// GLMS-20260105-0004 的 PosiDividendSum 恰好=03/2 已全额互换),无法暴露
// "DividendPending 硬编码 0" 的回归。本测试用一笔 PosiDividendSum≠0 的活交易
// GLMS-20260706-0004(标的 230004.IB,持仓 1亿,待实现分红 -150,000,多日稳定)
// 验证:GetPreEodDividendSum 返回非0的 -150,000 → 修复后 DividendIn/DividendPending
// 均应为此值(而非历史硬0回归)。
// 若本测试因硬0回归而失败(实际=0),即说明有人把 DividendPending 改回了硬0
// 或 GetPreEodDividendSum 传导链路被破坏。
// ============================================================================
/// <summary>
/// 非0场景:PosiDividendSum≠0 时,GetPreEodDividendSum 返回真实非0值,
/// 该值应同时成为 DividendIn 与 DividendPending(全量口径)。
/// 这是针对"硬0被0掩盖"盲区的核心防回归测试。
/// </summary>
[TestMethod]
[TestCategory("DBRecording")]
public void Green_NonZeroPosiDividendSum_Returns_RealValue_NotHardZero()
{
const string nonZeroTrade = "GLMS-20260706-0004"; // PosiDividendSum=-150,000,确认成交活交易
YLContext db;
try { db = DbContextFactory.GetYLDbContext(); }
catch (Exception ex) { Assert.Inconclusive($"无法连接测试库(CI/无DB环境正常跳过):{ex.Message}"); return; }
try
{
var td = db.trade.FirstOrDefault(t => t.TradeNumber == nonZeroTrade);
if (td == null) { Assert.Inconclusive($"测试库不存在交易 {nonZeroTrade}"); return; }
var floatLeg = db.swap_position
.Where(x => x.SwapTradeId == td.id && !x.Invalid && !x.IsInitial && x.UnderlyingCode != null && x.UnderlyingCode != "")
.FirstOrDefault();
Assert.IsNotNull(floatLeg, $"未找到 {nonZeroTrade} 的浮动腿持仓");
// 取该交易最近一次 EOD 的 PosiDividendSum 作为期望值(多日稳定 -150,000)
var lastEod = db.eod_swap_position
.Where(x => x.SwapTradeId == td.id && !x.Invalid && x.PositionId == floatLeg.PositionId && x.PosiQuantity > 0)
.OrderByDescending(x => x.ValueDate).FirstOrDefault();
Assert.IsNotNull(lastEod, $"未找到 {nonZeroTrade} 的有效 EOD");
Assert.AreNotEqual(0m, lastEod.PosiDividendSum, 0.01m,
$"前置:{nonZeroTrade} 的 PosiDividendSum 应≠0(本测试专为非0场景设计),实际={lastEod.PosiDividendSum}。" +
$"若该交易已互换/平仓致归0,请换另一笔 PosiDividendSum≠0 的活交易。");
// dealDate 取 lastEod 次日,确保 GetPreEodDividendSum 读到这笔非0 EOD
var dealDate = lastEod.ValueDate.AddDays(1);
var service = new RealDbSwapDealService();
decimal dividend = service.ExposeGetPreEodDividendSum(td.id, floatLeg.PositionId, dealDate);
// ---- 核心:返回值=真实非0的 PosiDividendSum,不是硬0 ----
Assert.AreEqual(lastEod.PosiDividendSum, dividend, 0.01m,
$"[非0场景·方案C验收] {nonZeroTrade} GetPreEodDividendSum 应返回 EOD PosiDividendSum={lastEod.PosiDividendSum}" +
$"实际={dividend}。该值将同时成为 DividendPending(待结算分红收益,全量口径)。" +
$"若实际=0,说明 DividendPending 硬0回归未修复,或传导链路被破坏(参见 SwapDealService.GetPreEodDividendSum 注释的口径论证)。");
Console.WriteLine($"[非0场景验证通过] {nonZeroTrade}: PosiDividendSum={dividend}(非0)→ DividendIn/DividendPending 均为此值,非硬0。");
}
finally { db?.Dispose(); }
}
}
}