Commit Graph
100 Commits
Author SHA1 Message Date
hjhan 4f46e2634f 修复收益互换多次部分平仓预付金返还:平仓比例/名义本金改以剩余持仓为基准
unwindSwapTrade.js:
- oriClosePercent 恒为 1(Definition B 下最多平 100% 剩余,修正全部平仓/按比例少返预付金 + 进页面 getInterestList 少算)
- CloseMethod==1(全部平仓)时修正 ClosePercent=1;CloseMethod==2(部分平仓/待复核)保留已提交比例,避免覆盖
- changeCloseQty/Percent/NotionalValue 三处换算改用 PosiNotionalValue(剩余本金),不再用原始 NotionalValue

swapCalc.js: 新增 calcCloseNotionalByRemaining / calcClosePercentByRemaining 纯函数(含除零保护)
swapCalc.test.js + _shim_run.js: 补充多次部分平仓换算单测(剩余vs原始对比、第3次全平、3次合计=原始、除零保护)
2026-07-16 10:03:21 +08:00
hjhan d69faaa8e8 fix(fast): 修复 numberInput 粘贴路径 percent 字段 ×100,并补 Jest 粘贴回归单测
- fastVue.base.js: __onInput 粘贴分支原把显示值当模型值传入 setValue 导致 percent 字段 ×100;
  改为先按 __change 同款口径(去千分位逗号 + 按 percent/append:'%'/append:'‱' 除法)解析为模型值再回显,
  使 DOM/显示/模型三者一致;键盘输入路径不变
- 重新生成 Statics/bundles/bundle.js:去每个输入文件头的 UTF-8 BOM(避免 bundle 中间出现 ZWN BSP 不可见字符),
  页面实际加载 bundle.js(改源文件必须重生成 bundle 才生效)
- 新增 numberInput.paste.test.js 覆盖 percent:true/append:%/append:‱/普通数字 4 类字段的 Ctrl+V 粘贴(Jest+jsdom,4 passed)
- fe-tests package.json 增加 jest-environment-jsdom、jquery 依赖
2026-07-15 12:58:08 +08:00
hjhan 94827eb6b6 fix(fast): 修复 numberInput 粘贴路径 percent 字段 ×100,并补 Jest 粘贴回归单测
- fastVue.base.js: __onInput 粘贴分支原把显示值当模型值传入 setValue 导致 percent 字段 ×100;
  改为先按 __change 同款口径(去千分位逗号 + 按 percent/append:'%'/append:'‱' 除法)解析为模型值再回显,
  使 DOM/显示/模型三者一致;键盘输入路径不变
- 重新生成 Statics/bundles/*.js:去每个输入文件头的 UTF-8 BOM(避免 bundle 中间出现 ZWN BSP 不可见字符),
  页面实际加载 bundle.js(改源文件必须重生成 bundle 才生效)
- 新增 numberInput.paste.test.js 覆盖 percent:true/append:%/append:‱/普通数字 4 类字段的 Ctrl+V 粘贴(Jest+jsdom,4 passed)
- fe-tests package.json 增加 jest-environment-jsdom、jquery 依赖
2026-07-15 11:29:14 +08:00
hjhan 05826fe7d5 debug(fast): 为 numberInput 粘贴路径加 F12 诊断日志并清理 bundle.js 中的 BOM
- fastVue.base.js: 在 __onInput 粘贴分支和 __change 加入 console.log,
  输出 raw/parsed/append/percent,便于在浏览器 F12 排查粘贴值实际走向
- 重新生成 bundle.js,并去掉每个输入文件头的 BOM,避免 bundle.js 中间出现 ZWN BSP 不可见字符
2026-07-15 11:08:25 +08:00
hjhan 2a5e338b50 fix(fast): 修复 numberInput 粘贴路径 percent 字段 ×100,并补 Jest 粘贴回归单测
- fastVue.base.js: __onInput 粘贴分支原把显示值当模型值传入 setValue 导致 percent 字段 ×100;
  改为按 __change 同款口径先解析为模型值再回显,键盘输入路径不变
- 重新生成 Statics/bundles/bundle.js(fastVue.base.js 被合并进此 bundle,页面实际加载该文件,
  改源文件不生效必须重生成 bundle)
- 新增 numberInput.paste.test.js 覆盖 percent:true/append:%/append:‱/普通数字 4 类字段的 Ctrl+V 粘贴
- fe-tests package.json 增加 jest-environment-jsdom、jquery 依赖
2026-07-15 11:08:25 +08:00
hjhan ea313dc1c6 fix(fast): 修复 numberInput 粘贴路径 percent 字段 ×100,并补 Jest 粘贴回归单测
- fastVue.base.js: __onInput 粘贴分支原把显示值当模型值传入 setValue 导致 percent 字段 ×100;
  改为按 __change 同款口径先解析为模型值再回显,键盘输入路径不变
- 新增 numberInput.paste.test.js 覆盖 percent:true/append:%/append:‱/普通数字 4 类字段的 Ctrl+V 粘贴
- fe-tests package.json 增加 jest-environment-jsdom、jquery 依赖
2026-07-15 10:18:26 +08:00
hjhan adc22a5b4c refactor(swap): 合并 CalcDailySimpleInterest 重置日/非重置日重复分支
两分支除"重置日重取浮动利率"外本金口径完全一致(都只缩放一次),
原非重置日分支是复制重置日逻辑时多写一行 tdDynomicPrincipal = flowEvent.InterestPrincipal
(已含 closePercent) 导致 closePercent^N 的指数 bug。合并为单分支,仅在
i % interestPeriod == 0 时重取利率,本金处理统一为 InterestPrincipal = 基数×closePercent。

行为保持:SwapModule 全量 196 通过/4 跳过,与重构前一致。
2026-07-14 17:23:33 +08:00
hjhan 7689436364 test(swap): 补 CalcDailySimpleInterest 全腿模式+日终路径覆盖,锁定无更大影响
用户要求确认 CalcDailySimpleInterest 所有调用方(含日终)覆盖完整性。
代码事实纠正:日终(settment=true)走 CalcEodInterest → CalcDailySimpleInterestByEod
(closePercent 硬编码 1m、且该函数从不改写 InterestPrincipal),根本不调用本函数;
本函数唯一真实调用链 = GetInterests(settment=false) → CalcUnwindInterest。
故'含日终'的正确命题是:日终不受此 bug 影响,应有用例锁定该不变量。

新增 CalcByMode 驱动各 InterestMode + 日终路径(rest_days=7, closePercent<1):
- 追加预付金(6)/多头存续(7)/空头存续(8)/合约名义本金规模(2):断言线性 closePrincipal
- 固定值(1):强制 newClosePercent=1,对平仓比例免疫,断言恒=Fix
- 日终 预付金(5)/标的期初全价(9):断言结果恒为线性 closePrincipal(证明 ByEod 正确变体不受影响)
SwapUnwindPrepayPrincipalBugTdd 现 19 绿;SwapModule 全量 196 通过/4 跳过,无回归。
2026-07-14 17:23:33 +08:00
hjhan 9bf3c4b9c6 test(swap): 补非预付金单利腿(标的期初全价)部分平仓回归,实证修复对所有单利腿通用
用户追问修复是否波及非预付金腿。CalcDailySimpleInterest 是所有单利腿
(InterestType=0)的盘中计息通用函数,预付金腿(mode5/6)只是使用者之一。
新增非预付金腿(标的期初全价=9,orginPv 走交易名义本金、不对齐 Fix)用例:
- 50%%→500,000、10%%→100,000、100%%→1,000,000(N=1,000,000)
- buggy 会给 N×closePercent^7,证明非预付金腿此前也中招、修复后统一线性缩放
- 100%% 用例锚定 closePercent=1 时修复前后恒等(零影响于日常计息/全平)
SwapUnwindPrepayPrincipalBugTdd 现 12 绿。
2026-07-14 16:45:27 +08:00
hjhan 83a55dab33 fix(swap): 修复平仓预付金应返还本金被 closePercent^N 指数级缩小
根因:CalcDailySimpleInterest 单利非重置日 else 分支曾把已×closePercent 的
InterestPrincipal 回填给计息基数 tdDynomicPrincipal,使下一个非重置日再乘一次,
累积成 InterestPrincipal = Fix × closePercent^N(N=计息天数),部分平仓时指数级缩小。
100% 因 1^N=1 不显现,故此前漏测。

修复:非重置日与重置日、日终 CalcDailySimpleInterestByEod 三者对齐——
显示本金 InterestPrincipal = 基数×closePercent(只缩放一次),计息基数不缩放。

TDD 铁证(GLMS-20260701-0006, interest_rest_days=7, Fix=9,180,000):
- 修复前 50%→71,718.75(=Fix×0.5^7)、10%→0.918(=Fix×0.1^7)
- 修复后 50%→4,590,000、10%→918,000、100%→9,180,000
新增 CalcUnwindMultiDay helper + 3 用例,SwapUnwindPrepayPrincipalBugTdd 共 9 绿,
SwapModule 全量 186 通过无回归。
2026-07-14 16:33:59 +08:00
hjhan b9462510de Merge branch 'merge/p132_74-risk-engine-into-1.4.2' into glms/feature/1.4.2 2026-07-14 15:14:27 +08:00
hjhan 0483cd8576 Merge remote-tracking branch 'origin/feature/p132_74-risk-engine' into spike/merge-p132_74-to-1.4.2 2026-07-14 14:48:11 +08:00
hjhan bfcfc74717 test: 平仓预付金bug回归测试贴合生产铁证(精确notional + 不计息断言)
- 客户截图级用例 notional 由反推的 306,191,860.22 更正为生产精确值
  306,191,860.26,使 2*Fix-Notional = -287,820,348.64 与生产 event15997 精确 0 误差。
- 生产该预付金腿三条 swap_flow_event 的 InterestAmount 全=0(债券类预付金腿不计息),
  仅 InterestPrincipal 中招;故客户级/Trade1813 用例改断言 InterestAmount==0、用 rate=0 贴合生产。
- 显式带息加固用例(rate=0.01,验证计息基数也基于保证金本金自身)保留,但注释标明为
  合成场景、非该笔生产的真实症状,避免与生产现象混淆。
- 固化生产双平仓记录佐证:同腿"盘中错(event15997)/EOD对(event15998)"两条平仓,
  恰好印证修复方向(盘中 orginPv 对齐 EOD=Fix)正确。
2026-07-14 14:46:42 +08:00
hjhan e1df4ded13 docs: FR007 ReferencePrice 小数口径注释(利息腿计算无需再 ÷100)
EodPriceQueryService.TryGetPrice 读取 eod_commodity_future_price.ReferencePrice
作为 FR007 浮动利率参与利息计算。说明该行 ReferencePrice 无论 bond-sync 自动
同步还是界面手工录入,写入时均已 ÷100 为小数口径,利息腿计算直接作为 floatRate
参与 principal*(fixedRate+floatRate)/annualDays,无需在计算侧再次 ÷100。
2026-07-14 11:33:15 +08:00
hjhan f7988e8fd3 fix: 修正预付金腿平仓计息基数 orginPv 维度错误导致应返还本金巨负
平仓(盘中)路径对预付金(保证金)腿将 orginPv 取为整笔交易名义本金,
使公式 dynomicPrincipal=TdInterestPrincipal+posiPrincipal-orginPv 把名义本金
(千万~亿级)当减项扣掉,导致"应返还本金"(InterestPrincipal)与计息基数变成巨负值。

修复:仅对初始预付金(5)/追加预付金(6)腿,将 orginPv 对齐为自身保证金本金
InterestPrincipalFix,与日终(EOD)路径 SwapEodPositionService 中预付金腿
orginPv=InterestPrincipalFix 的既有正确行为保持一致。债券本金腿(模式9)及其它
计息模式仍用交易名义本金,不受影响。

新增 SwapUnwindPrepayPrincipalBugTdd 回归测试(6 用例全绿),含客户截图级
0 误差复现、真实库 Trade1813 复现、多次部分平仓及计息基数断言。
2026-07-14 11:33:15 +08:00
hjhan 18ba0271ec refactor: eod 数据来源写库改用 EodPriceBase 常量
EodSyntheticPriceSaveService 三处 DataSource="系统"、SwapFlowService 一处 DataSource="人工",均改为引用既有 EodPriceBase.系统/人工 常量,消除 eod 数据来源列值散落字面量。仅统一“数据来源”语义,不动无关的系统操作员名(OptName/UserName 等)字面量。
2026-07-13 16:56:04 +08:00
hjhan 0fb8255b89 fix: 日终价格「系统」筛选修复债券来源口径不一致
债券分支在 DataSource=系统 时未过滤 update_user,导致后处理按 update_user 把手工改过的债券标成"人工"混入系统筛选结果。改为:系统仅命中 update_user==null(中债自动同步)、人工仅命中 update_user!=null,与显示口径一致。连库复现并验证:修复前系统筛选漏出3条人工债券,修复后0泄漏。
2026-07-13 16:00:49 +08:00
hjhan 0fda5fd1cc fix: 日终价格「数据来源」改为价格行自身语义(人工/系统两档)
移除中债估值细分与操作人姓名显示,按价格行自身 DataSource 列判定:期货/股票读 DataSource(otc-marketdata 同步写系统、手工写人工);债券 update_user 非空→人工、否则→系统。筛选仅人工/系统两选项,异常来源值返回空。ResolveBondDisplaySource 精简为单参纯函数。
2026-07-13 15:42:28 +08:00
hjhan 02624abf75 test: 日终价格回归测试(日期窗口纯单测 + 新增可见性DB集成测试)
- EodPriceService 提取 static ResolveValueDateWindow(reqStart,reqEnd),使日期窗口逻辑可脱离数据库单测

- EodPriceDtoTest 新增4个纯单测:未传日期回退±1年、起止都填今天→仅今天窗口、显式区间原样生效、结束日今天上界为明天;锁定'页面始终5条'根因

- EodPriceGoldenReplayTest 新增 Record_NewRecordVisibility([Ignore]手动跑):直接跑 SearchUnderlyingList,锁定(a)今天+已上市可查 (b)日期0001查不出 (c)未上市查不出

- 构建0错误;EodPriceDtoTest 19通过0失败
2026-07-13 13:37:18 +08:00
hjhan d978f7048d refactor: 日终价格联想逻辑抽成共享 eodUnderlyingSuggest.js 并修复下拉静默失效
- 三编辑页重复的 eodSuggest/eodRenderSuggest/eodHideSuggest/checkSubmitData/初始化 抽成 eodUnderlyingSuggest.js 一处引用,禁止逐页复制内联脚本

- 修复静默 bug:cshtml 缺 #eodSuggestBox 容器且 class 无 CSS 导致下拉从未渲染;改为 JS 动态创建盒子+样式内联

- 修复点选 ReferenceError:回调由对象字面量求值改为 window['lookup'+kind] 安全解析+typeof 校验
2026-07-13 13:30:35 +08:00
hjhan 045361dd9b feat: 日终价格新增标的代码支持输入联想(服务端模糊匹配+原生下拉,防填错)
- 新增 SuggestUnderlyingForEod(code,kind):按代码/名称 LIKE 匹配、Take(20)、强制 LaunchState==1 与类型,与列表查询/Lookup 三处口径一致

- 三个编辑页代码输入框加 oninput 防抖联想,原生 fixed 下拉展示候选,点选回填精确代码并复用失焦校验带出市场;期货额外回填 UnderlyingId

- 不依赖任何前端自动补全插件(jQuery UI 未打包),可支撑几十万标的数据量
2026-07-13 13:25:19 +08:00
hjhan 2ade7b46bb fix: 日终价格新增改回手动输入标的代码(删除全量下拉、解决null报错与市场带出)
- 删除 BuildUnderlyingOptions/UnderlyingOptionVm(几十万债券全量下拉导致卡死、选不动)

- 新增轻量 LookupUnderlyingForEod(code,kind):精确按代码查一条、强制 LaunchState=="1"(与列表查询对齐,杜绝幽灵记录)

- 三个编辑页新建时标的代码改为可输入框,onblur 用 main.post 带出市场;期货额外回填 UnderlyingId(按id join)

- 隐藏域按新建/编辑分渲染,修复 saveeod_*/on*Picked 读 null 报错

- 删除已废弃的 eodPriceAdd.cshtml
2026-07-13 13:15:08 +08:00
hjhan 8cade8ae53 fix: 修复日终价格新增后查不出(picker过滤LaunchState、新记录日期默认今天、列表新增改三选一)
- EodPriceController.BuildUnderlyingOptions 增加 LaunchState=="1" 过滤,与列表查询对齐,避免新增非激活标的被 inner join 永久过滤

- 三个编辑页新建分支将 valuation_date/ValueDate 默认设为今天,落在列表默认查询窗口内

- eodStockPriceEdit 补全 StockPicker 下拉(此前股票无picker,UnderlyingCode为空hidden导致查不出),删除上传无用的状态字段

- eodPriceList.js openEodPriceAdd 改为三选一(债券/期货/股票)打开各自编辑页空enid,替代已废弃的 EodPriceAdd 搜索页
2026-07-13 12:34:39 +08:00
hjhan 5cc24f787e fix: 修复日终价格新增页自动补全失效与查询开屏报错
EodPriceService.SearchUnderlyingList 三分支 Concat 投影成员不对称(债券缺 DataSource、期货/股票缺 UpdateUser),EF 翻译期抛 'DataSource' key not present 致 eodPriceQuery 开屏崩溃,补齐成员对称。eodPriceAdd.cshtml 原用 jQuery UI .autocomplete() 但 bundle 未打包该插件,调用即抛错、脚本中断、标的无法搜索;改为自带下拉补全(纯 jQuery+ajax,不依赖外部插件)。
2026-07-13 11:22:12 +08:00
hjhan 36d8909fe0 feat: 日终价格管理新增统一录入表单(按标的类型自动落表)
列表页新增"新增"按钮(结算管理-日终价格修改 权限),打开统一新增页;选标的后按 UnderlyingInstrumentType 自动显示对应字段组,保存时路由到正确的 Save 方法落到对应表;字段与上传 Excel 对齐,避免冗余字段。
2026-07-13 11:00:46 +08:00
hjhan 760ffd62e6 fix: 日终债券来源固定中债估值、人工改动显示操作人并补上传溯源
china_bond_valuation 来源恒为中债估值(聚源仅转发,无人手工维护),不再按 JSID 推断系统/人工;eod 两表仍用自带 DataSource(人工/系统)。债券被人工改动(update_user 非空)时,日终列表来源列显示操作人姓名,否则显示中债估值;操作人经已有 create_user/update_user 列溯源(零 DDL)。手工上传 xlsx 的债券分支补戳操作人,与表单编辑口径一致。配套单测 EodPriceDtoTest / EodPriceGoldenReplayTest + golden JSON。
2026-07-13 11:00:33 +08:00
hjhan 3f5e9a0be9 fix: 日终价格管理按真实标的类型显示并统一数据来源
1. 新增 RealInstrumentType 显示字段,从 underlying_manager 取真实类型,
   解决 eod_commodity_future_price 记录一律显示'商品期货'的问题
   (UnderlyingInstrumentType 继续作为查表路由键,前端/查看零改动)。
2. EodPriceBase 补'系统'常量,债券 DataSource 改为一次性三元判定,
   消除散落的 JSID 魔法字符串与重复 remap。
注:受'不增字段、不动库'约束,债券来源仍依赖 JSID 推断。
2026-07-10 19:41:19 +08:00
hjhan 0bef986e10 fix(valuation): 修复折叠分组后表头消失无法展开的问题
问题:折叠一个分组时,该组所有列被 hideCol 隐藏后,buildGroupHeaders
因 visibleColsInGroup 为空而 continue 跳过该分组,导致分组表头不渲染,
用户失去展开入口(表现为"收起后整组列和表头都不见了")。

修复:
- applyGroupHeaders:折叠时保留该组首列作为"展开锚点"(只隐藏 slice(1)),
  确保 setGroupHeaders 仍能为该分组渲染表头单元格
- buildGroupHeaders:折叠态下 numberOfColumns=1,表头显示 ▶ 可点击展开;
  被 setcolumnChooser 主动隐藏的分组仍跳过(不影响)
- 展开时恢复该组全部列

测试场景:
1. 互换估值Tab折叠任一分组 → 表头保留(▶),点击可展开恢复
2. 框架合约Tab同上
3. 全部折叠 → 每组各保留1列锚点,页面仍有列可操作
2026-07-08 09:08:08 +08:00
hjhan 5e27d6cef8 docs(valuation): 新增估值模块前端改造说明文档
记录:
- 改造范围、路径A决策依据、方案对比(否决otcdms-ui/free-jqGrid的理由)
- 分组配置映射表(需求字段 ↔ colModel.name ↔ 后端字段)
- 缺失字段清单(TODO,待后端确认):标的类型/期间付息分红/付息方式/合约估值两口径/保证金利息/期间分红/预付金系列/TRS估值
- 已知约束:冻结列冲突绕法、setcolumnChooser兼容、导出口径区分
- 测试要点、后续工作
2026-07-08 08:57:46 +08:00
hjhan a617ed6d93 feat(valuation): 互换估值Tab 接入分组折叠 + 簿记筛选 + 导出
对应需求《估值模块V1》模块二:每日估值报告 - 互换估值Tab

改动:
1. 新增 eodSwapValuationGroupConfig 分组配置(4组:基本信息/利率与规模/价格/收益)
   现有列顺序已天然满足分组连续性,无需重排,风险最低
2. gridComplete 在 setcolumnChooser 完成后初始化可折叠分组表头
   保留原有异常行标红(dataError)逻辑
3. 新增簿记账户筛选(需求3.1):cshtml 加 BookId 下拉,searchPositionDetials 传 BookId
   未选择时传空,后端返回该对手方下全部账户合约
4. 新增「导出互换估值」按钮(需求3.2+4.2),走通用 exportVisibleColumnsToExcel
   文件名:{对手方}_每日估值报告_互换估值_{估值日}.xls
   与现有 DownLoadReport(整份报告)独立,互不影响

缺失字段(TODO,待后端确认):期间分红、预付金系列(利率/利息/期初/追加)、TRS估值

测试要点:簿记筛选生效、分组表头显示、折叠交互、异常行标红不受影响、导出可用
2026-07-08 08:56:34 +08:00
hjhan d40b561a42 feat(valuation): 框架合约Tab 导出可见列Excel + 通用导出工具
对应需求《估值模块V1》4.2:导出当前筛选后可见列数据,格式与前端一致。

改动:
1. utils.js 新增通用导出工具 exportVisibleColumnsToExcel(jgrid, fileName)
   - 零依赖,基于 HTML table + ms-excel MIME
   - 只导出当前可见列(与折叠状态联动:收起的分组列不导出)
   - 与后端模板导出(SettlementReport/EodPositionRisksQueryService)口径独立,互不干扰
2. EodPositionRisks.cshtml 恢复导出按钮(原 exportTrade 被注释,现改为 exportVisibleColumns)
3. EodPositionRisks.js 新增 exportVisibleColumns(),文件名含Tab名+结算日期

测试要点:导出列=页面可见列、列名=表头名、数据=当前筛选数据、折叠的列不导出
2026-07-08 08:53:44 +08:00
hjhan 76af939332 feat(valuation): 框架合约Tab 接入可折叠分组表头 + 字段命名对齐
对应需求《估值模块V1》模块一:日终持仓风险_互换 - 框架合约Tab

改动:
1. colModelGridEodSwap 列按需求2.2分组重排(组内列连续,满足setGroupHeaders要求)
   - 互换类型移至基本信息组(原在末尾)
2. 字段命名对齐需求用词(纯label改动,不改name/index):
   - 合约利率端待实现收益 → 合约利息端待实现收益
   - 预付金字段 → 保证金(收取/支付 初始/维持保证金)
3. 新增 eodSwapGroupConfig 分组配置(7组:基本信息/名义本金/标的市值/浮动端/利息端/保证金/估值与实现收益)
4. gridComplete 在 setcolumnChooser 完成后初始化可折叠分组表头

缺失字段(TODO,待后端确认):
- 标的类型、期间付息/分红、付息方式、合约估值(两口径)

测试要点:框架合约Tab表头分组合并、点击折叠/展开、footer汇总行(DV)正常、列设置功能正常
2026-07-08 08:51:33 +08:00
hjhan 7928000dc6 feat(valuation): 新增通用可折叠分组表头工具 initCollapsibleGroupHeaders
jqGrid 4.5.4 原生 setGroupHeaders 只支持静态合并表头,不支持点击折叠。
本次在 utils.js 新增通用工具函数,为估值模块前端重构提供基础能力:

- initCollapsibleGroupHeaders(jgrid, groupConfig): 生成合并表头 + 点击折叠/展开
- refreshCollapsibleGroupHeaders(jgrid): 列重排/显隐后重建分组边界
- 复用本文件 setcolumnChooser2 已验证的 destroyGroupHeader → 显隐列 → setGroupHeaders 重建模式
- 默认全部展开,折叠态显示 ▶ 展开态显示 ▼
- 与 setcolumnChooser 通过事件委托协调,不依赖 free-jqGrid 商业版

不换库、零全站回归风险。后续提交接入业务页面。
2026-07-08 08:50:14 +08:00
hjhan b3c2fdfe38 test(fe): 补充守卫注释与架构闸门,防新增内联金额计算
- 生产接线处补注释,追溯到具体历史 bug (dcf649f2/20ea93d8/3c5f25a5/f873239a)

- swapCalc.js 注明哪些函数已接入生产、哪些是纯交叉校验规格

- 新增 guard_arch.js 架构闸门:扫描提交新增行,拦截 Vue 组件内联金额计算

- pre-commit hook 串行运行 单元测试 + 架构闸门
2026-07-07 13:26:32 +08:00
hjhan 7f64d48699 test(fe): 接入 SwapCalc 纯计算模块 + 前端精度回归测试
- incomeSwapTrade.js / swapTradeEdit.js 改为调用 SwapCalc.*(缩放/取整/全价推导)

- 新增 fe-tests 守卫:4 个历史 bug 回归 + 8 场景对齐 C# FrontendCalcReference 金标准 + otcformat.js 精度配置守卫

- 新增 .git/hooks/pre-commit 自动运行前端守卫(失败阻断提交)
2026-07-07 12:30:19 +08:00
hjhan 088df27011 fix(swap): 还原otcformat.js精度配置,修复期末全价只能录2位小数
f0ad4406(Revert ruisu合并进来的代码)在回滚RiskModule时,
误将otcformat.js从'压缩单行全precision=9'改成'多行precision=2',
导致StockEqvNotional/tradeSinglePrice/tradePrice/notional等字段
精度从9位降到2位,期末全价(TradingAmountAvg)等只能录2位小数。

还原到f0ad4406^的正确版本(全precision=9),恢复所有字段9位精度。

根因:前端运行时配置App_Data/Config/otcformat.js的precision限制,
与后端实体(EF默认decimal)和DB列(decimal(22,10))无关。

历史脉络:
- 3e650b8f(2026-05-28) 首次引入precision=2误伤
- 1932a2e7(2026-05-29) 首次还原回全9
- f0ad4406(2026-07-03) Revert ruisu时再次误伤(本次修复对象)
2026-07-06 09:55:01 +08:00
hjhan 86825cb2a1 test(swap): SwapPositionComposeScenarioTest(4场景)+CopyEodPosition/UpdateEodPosition/SaveCurrentEodInitalPosi走PersistEodSwapPosition seam
借鉴 testable 分支 SwapPositionComposeScenarioTest,基于当前分支 seam 重写4场景:
- SPC_001 首次归档(无前日eod):PosiQuantity=初始持仓
- SPC_002 Copy分支(有前日eod无事件):PosiGrossPrice原样复制
- SPC_003 Update分支(有平仓事件):PosiQuantity=1000-400=600, TdCloseQty=400
- SPC_004 未收盘抛异常(非交易首日无前日eod)

SwapEodPositionService 改动(零行为变更):
- CopyEodPosition/UpdateEodPosition/SaveCurrentEodInitalPosi 的 DbContext.eod_swap_position.Add
  改为调 PersistEodSwapPosition seam(3处),使测试可拦截持久化

利息腿场景(自动互换)因 CalcSwapInterests 参数适配复杂留后续。
SwapModule 177测试全绿(+4),无回归。
2026-07-03 18:37:46 +08:00
hjhan cbb5c88aa8 refactor(swap): SwapPositionCompose补5个seam+事务重构为ExecuteInTransaction
SwapEodPositionService 新增5个 protected virtual seam(SwapPositionCompose路径):
- FindActiveSwapTrades(DateTime, IEnumerable<int>): 查活跃互换交易
- FindAllSwapPositions(List<int>): 查所有持仓(含初始+实际)
- FindTradeExtends(List<int>): 批量查交易扩展
- FindEodSwapsByDate(DateTime): 查指定日期日终汇总
- FindFlowEvents(int, DateTime): 查交易指定日期的完成流水事件

SwapPositionCompose 方法体重构:
- 5处内联DbContext查询替换为seam调用
- 事务(BeginTransaction/Commit/Rollback)重构为ExecuteInTransaction lambda
- SaveChanges替换为SaveAllChanges seam
- 复用已有FindEodSwapPositions seam(替代内联eod_swap_position查询)

为零行为变更(seam生产实现=原代码,ExecuteInTransaction=原事务逻辑)。
SwapModule 173测试全绿,无回归。为SwapPositionComposeScenarioTest铺路。
2026-07-03 18:31:01 +08:00
hjhan 4fede8339a refactor(test): SwapDealSettlementTest拆分为SwapUnwind/SwapIncome+提取共享stub
按业务拆分原 SwapDealSettlementTest(8场景)为3个文件,提升可读性:
- TestableSwapDealService.cs: 共享stub(7个seam override)+工厂方法(CreateTrade/CreateUnwindData)
- SwapUnwindScenarioTest.cs: 平仓全流程6场景(UW_001~006: 全平/部分平/含预付金/含费价重算/审核/提交)
- SwapIncomeScenarioTest.cs: 结息2场景(SI_001~002: 正常结息/含预付金返息)

命名对齐 testable 分支风格(SwapUnwindScenarioTest),场景前缀改 UW_/SI_ 更直观。
删除 SwapDealSettlementTest.cs(内容已拆分迁移)。
SwapModule 173测试全绿,无回归。
2026-07-03 18:12:52 +08:00
hjhan 99958f9b43 test(swap): SwapDealSettlementTest补部分平仓+含预付金场景(借鉴testable)
借鉴 testable 分支 SwapUnwindScenarioTest.Scenario2,补当前分支缺失的2个场景:

SD_007 部分平仓:CloseMethod=部分平仓 → HasPartialUnWind=1,TradeStatus不变,
  StockEqvNotional/TradeAmount按比例扣减(原100万-50万=50万)
SD_008 含预付金平仓:SwapMarginAmount≠0 → 2条资金流水(平仓费+应付预付金)

SwapDealSettlementTest 现8场景,SwapModule 173测试全绿(+2),无回归。
2026-07-03 18:03:38 +08:00
hjhan 9da3a1ed91 refactor(swap): ClearSwapPositions改virtual(为重复收盘端到端测试铺路)
SwapTradeBaseService.ClearSwapPositions 从 public void 改为 public virtual,
使测试子类可 override 模拟清理逻辑(按ClientCashId关联删除出入金)。

为零行为变更(未被override时按原实现执行)。SwapModule 171测试全绿,无回归。

为后续 DuplicateSwapIncomeReproductionTest(重复收盘不累积出入金)端到端测试铺路。
当前分支已有 ClearSwapPositionsScenarioTest(CSW_001-004)覆盖清理单元逻辑,
端到端测试将补充'重复收盘场景'的集成验证。
2026-07-03 17:53:18 +08:00
hjhan cc8b862d04 fix: ETF交易确认书 债券名称置空 2026-07-03 11:28:07 +08:00
hjhan b6faa6fd1c fix: 国联民生确认书模板 0-> 0.00 2026-07-03 11:24:04 +08:00
hjhan 32bcf9beb9 refactor(swap): FindTrade seam上提基类消除三子类重复
SwapDealService/SwapEodPositionService/SwapFlowEventService 三处 FindTrade(int)
签名和实现完全一致(DbContext.trade.Find),上提到 SwapTradeBaseService 基类。

核对确认可安全上提的只有 FindTrade(三者逐字一致):
- FindTradeExtend 不可上提: SwapEodPositionService 用 FirstOrDefault,
  SwapFlowEventService 用 First(找不到抛异常),语义不同。
- FindPositions 不可上提: SwapEodPositionService 含 IsInitial 持仓,
  SwapFlowEventService 排除 IsInitial + AsNoTracking,语义不同。

测试 stub override FindTrade 跨基类层级正常工作,C# virtual 多态不受影响。
SwapModule 171测试全绿,无回归。
2026-07-03 09:52:57 +08:00
hjhan b501e21904 test(swap): 启用MergeCompose场景6/7+SwapFlowEventService录制钩子+RecordingSwapFlowEventService
1. MergeComposeScenarioTest 场景6/7 启用(去掉Ignore):
   此前失败是stale binary(未重新编译),重新build后8场景全部通过。
   - 场景6 单条merge无持仓→DealNoPosition创建交易
   - 场景7 两条merge无持仓→创建交易+平仓

2. SwapFlowEventService 补OnBefore/OnAfterMergePageEvent录制钩子(默认空实现):
   - OnBefore: DB查询完成、合成逻辑执行前触发,可捕获输入快照
   - OnAfter: PersistEvents后触发,捕获输出事件
   生产路径为空方法体,零行为影响。

3. 移植RecordingSwapFlowEventService(借鉴testable分支):
   override OnAfterMergePageEvent录制golden文件,备用录制工具。
   内联GoldenFileModel(简单POCO)。FullRecord_WithPreBookingPositions连库测试自动跳过。

SwapModule 171测试全绿,无回归。
2026-07-03 09:38:05 +08:00
hjhan f0ef37b599 test(swap): SwapFlowEventService seam改造+MergePageEventScenarioTest(6场景全绿)
借鉴 testable 分支,只取 seam(排除 PosiPnl/NetSettmentAmount 公式改动和 MergePageEvent 拆分),
填补当前分支对开平仓合成(MergePageEvent)零覆盖的空白。

SwapFlowEventService 新增11个 protected virtual seam:
- FindTrade/FindTradeExtend/FindPositions/FindAndInvalidateFutureEvents
- GetUnderlying/GetNextBusinessDay/ResolvePositionId
- PersistEvents(替代InitEvent内联Add+SaveChanges)/BeginTransaction/CommitTransaction/RollbackTransaction
MergePageEvent/InitEvent: private→protected virtual,内联DB调用替换为seam。
InitEvent 移除 DbContext.swap_flow_event.Add(转入PersistEvents,纯函数化)。
SwapTradeBaseService.UpdateDbOption: public void→public virtual(测试override用)。

新增测试(借鉴testable分支):
- TestableSwapFlowEventService.cs(集中式共享包装类)
- MergePageEventScenarioTest.cs(6场景全绿):
  Scenario1 单条无持仓开仓 / Scenario2 同向追加 / Scenario3 反向全平
  Scenario4 反向部分平+开 / Scenario5 一开一平 / Scenario6 复杂组合

**未借鉴**:SearchPositionFlowEvent的PosiPnl/NetSettmentAmount公式改动(行为变更)、
MergePageEvent拆分ProcessSingleFlow等(非必需重构)。
SwapModule 169测试全绿(+6),无回归。
2026-07-03 09:26:13 +08:00
hjhan 6e9bae94c5 test(swap): MergeRestModeCompose seam调用替换+移植MergeComposeScenarioTest(6/8场景)
借鉴 testable 分支,把 SwapTradeAutoService 的 MergeRestModeCompose/MergeRestModelItem/
DealNoPosition/DealHasPosition 内联DB调用替换为seam调用,生产行为不变。

替换的调用点:
- MergeRestModeCompose: FindActiveSwapTrades/FindTradeExtends/FindActivePositions/GetNextBusinessDayBefore/QueryFloatRates
- MergeRestModelItem: FindClient/GetEtradingRule/FindAssetUnit/FindUnderlying/GetSwapFloatRate/FindFlowEventsForCashCheck/FindValidTrades/SaveChanges
- DealNoPosition: CreateNewSwapTrade/AutoSwapUnwind
- DealHasPosition: AutoSwapUnwind

新增测试(借鉴testable分支):
- TestableSwapTradeAutoService.cs(集中式共享包装类)
- MergeComposeScenarioTest.cs(8场景):
  Scenario1-5/8 通过: 客户/权限/账户/标的校验链 + 空流水返回
  Scenario6/7 [Ignore]: 创建交易路径,DealNoPosition内部实现细节待对齐后启用

SwapModule 163测试全绿(+6),无回归。
2026-07-03 09:20:59 +08:00
hjhan 6b24e6e979 refactor(swap): SwapTradeAutoService补18个virtual seam(借鉴testable分支)
借鉴 origin/glms/feature/refactor-swap-event-testable 的可测性改造,
当前分支 SwapTradeAutoService 此前0个seam,纯新增#region可测试化区域,无冲突。

18个protected virtual seam(默认实现=原代码,行为不变):
- 日历: GetNextBusinessDay/GetNextBusinessDayBefore
- 计算: CalculateBondYtm
- 持久化: PersistMerge/SetModelOpt/SaveChanges
- 查询: FindActiveSwapTrades/FindTradeExtends/FindActivePositions/FindActivePositionsAll/
        QueryFloatRates/FindClient/FindAssetUnit/FindUnderlying/FindFlowEventsForCashCheck/FindValidTrades
- 协作服务: GetEtradingRule/GetSwapFloatRate/CreateNewSwapTrade/AutoSwapUnwind

为后续 MergeComposeScenarioTest(自动簿记流程测试)铺路。
SwapModule 157测试全绿,seam未被override时按生产实现执行,行为不变。
2026-07-03 09:08:12 +08:00
hjhan 178f1d7db8 docs(swap): 借鉴testable分支的Seam实践指南(团队规范沉淀)
从 origin/glms/feature/refactor-swap-event-testable 的 docs/seams-pattern-practice-guide.md 借鉴。
内容:Protected Virtual Seams 模式方法论、依赖类型提取策略表、可测试子类模式、
三层测试体系(合成+黄金+端到端)、命名约定、渐进节奏、6条经验教训。
与当前分支已采用的 seam 模式(SwapDealService/SwapEodPositionService)一致,作团队规范。
2026-07-03 09:05:37 +08:00
hjhan e4a92c93ee feat(swap): 后端只读校验告警-搬FrontendCalcReference+SwapIncome/SwapUnwind插校验
前端保持快速反馈(用户改输入立即算),后端不替代前端,仅做合理性兜底校验。

1. 搬FrontendCalcReference到YLErpDAL/Helpers(测试与生产共用同一份公式,避免分叉)
   - 从FrontendCalcCharacterizationTest提取,改public,8个FC测试搬迁后全绿验证一致

2. SwapDealService新增ValidateFrontendPnL只读校验:
   - 从unwindData.FlowEvents取浮动腿,PosiGrossPrice==0时跳过(避免误报)
   - 调FrontendCalcReference重算,与前端传值逐字段比对
   - 差异>0.01记Logger.Error(带输入快照便于排查)
   - 整体try/catch吞异常,校验自身错误绝不阻断交易
   - SwapUnwind/SwapIncome各插一处(FindTrade后、ExecuteInTransaction前)

不碰NLog配置(告警进Console,生产由运维采集)。SwapModule 157测试全绿。
2026-07-03 09:04:57 +08:00
hjhan 129e4bed0d test(swap): 补ApproveSwapTrade/ApplySwapTrade测试+3个seam(借鉴testable分支)
借鉴 origin/glms/feature/refactor-swap-event-testable 的 SwapUnwindScenarioTest 场景4/5,
补全当前分支缺失的平仓审批流程覆盖。

SwapDealService 新增3个 protected virtual seam:
- FindSwapEvent(查待审核事件)
- FindFlowEventsByEventId(查事件关联流水)
- CloseReCheckSetTrade(前置校验包装)
ApproveSwapTrade/ApplySwapTrade 重构为调seam,生产行为不变。

SwapDealSettlementTest 新增2个测试(SD_005/006,共6个):
- SD_005 ApproveSwapTrade 全平仓审核: 反序列化swap_event.EventData→资金流水→TradeStatus
- SD_006 ApplySwapTrade 提交审核: CloseReCheck前置校验+SwapRealizedPnL=SwapCloseAmount

融合策略: 保留当前分支SwapIncome资金流水断言独特价值(SD_001/002),
借鉴testable分支审批流程覆盖(SD_005/006),不二选一。
SwapModule 157测试全绿,无回归。
2026-07-03 08:30:36 +08:00
hjhan cf0d965ff8 test(swap): 前端计算逻辑特征化测试(8场景含用户可变输入)
用C#忠实重写前端JS公式作参考实现(FrontendCalcReference),冻结前端计算行为,
为后端校验/重算兜底提供金标准(注:前端保持快速反馈,不搬到后端)。

8个场景覆盖用户可变输入分支:
- FC_001-005 平仓页: 默认值/改标的价格/改平仓数量/改利息金额/非债券空头方向因子
- FC_006-008 结息页: 全量结算/改标的价格/含利息腿与预付金腿总额

参考实现内部用规范命名(EntryDirtyPrice/ExitDirtyFeePrice/floatRatio/longRatio),
践行《互换价格字段命名规范决策文档》,作命名规范活样板。
2026-07-03 08:22:55 +08:00
hjhan a207927f1b test(swap): SwapDealService抽7个virtual seam + 手动结算内存测试
攻克SwapIncome/SwapUnwind零单元测试覆盖的盲区(此前仅DBRecording,CI不跑)。

SwapDealService补7个protected virtual seam(参考已验证的SwapEodPositionService模式):
- FindTrade/AddClientCash/SaveSwapDeal(原private改protected virtual)
- SaveAllChanges/ExecuteInTransaction/CallSaveSwapTradeClientCash/TriggerRealtimeSwapPosition
生产实现行为不变,SwapIncome/SwapUnwind/ApproveSwapTrade重构为调seam。

新增SwapDealSettlementTest.cs(4个内存测试):
- SD_001 SwapIncome资金流水金额=-SwapRealizedPnL
- SD_002 含预付金返息双流水
- SD_003 SwapUnwind全平仓持仓归零+状态变更
- SD_004 DealFloatPosition含费价重算(后端唯二真做计算处)
红灯验证通过(改错金额符号测试立即失败)。
2026-07-03 08:22:43 +08:00
hjhan 782e1f6a7a refactor(swap): 债券价格÷100转换收敛到BondPriceConverter统一入口
消除9处价格转换字面量(*0.01m/*100),统一走BondPriceConverter.ToStorage/ToDisplay。
- 新增YLErpDAL/Helpers/BondPriceConverter.cs(含可空重载)
- 批次1(危险字面量): BondPaymentService/RealtimePnlCalc/RealTimeClientBanlanceService/SwapTradeAutoService
- 批次2-4(调用收敛): SwapFlowService/SwapFlowImportService/SwapEndConfirmService/EodPriceProvider/EodPriceQueryService
- RealtimePnlCalc:601/602价格×数量维度交织处加注释,不机械合并

不改bondPriceMultiple常量值,纯调用方式收敛。SwapModule 155测试全绿,行为不变。
2026-07-03 08:22:27 +08:00
hjhan ed80745bf2 字段命名建议 2026-07-02 18:09:27 +08:00
hjhan f88da59874 日期 事件 期望行为
D1=2026-01-06	无事件(Copy 分支)	TdPosiDividend=1天增量,PosiDividendSum=增量
D2=2026-01-07	部分平仓 30%(EventType=2, Quantity=300, DividendIn=按比例)	PosiQuantity→700,TdPosiDividend按(700)算,PosiDividendSum递推
D3=2026-01-08	无事件	增量按剩余700算
D4=2026-01-09	互换结算(EventType=3, DividendIn=部分待实现金额,不扣持仓)	PosiQuantity不变=700,TdCloseDividend=互换DividendIn,PosiDividendSum递推
D5=2026-01-10	无事件	继续按700累积
D6=2026-01-11	全平(EventType=2, Quantity=700, 全部待实现作DividendIn)	PosiQuantity→0,PosiDividendSum=0(else分支)
2026-07-02 12:59:16 +08:00
hjhan 0910969e3f fix(swap): PosiDividendSum精度差异修复(GLMS-20260105-0007)
问题:互换后PosiDividendSum=-89999.64(应为-90000),差0.36元。
根因:UpdateEodPosition cs:1635从头重算PosiDividendSum
  (Round(全程,2)-已实现),与CopyEodPosition逐天递增
  (每天Round(增量,2)累积)产生舍入误差累积。

修复:cs:1635改为递增模式
  PosiDividendSum = eod.PosiDividendSum + TdPosiDividend - TdCloseDividend
  与InterestIncomeSum的递增模式一致,避免从头重算的精度差异。

验证(golden录制/回放TDD):
- 真实数据录制GLMS-20260105-0007的eod快照+输入数据
- 回放重新调UpdateEodPosition:修复前=-89999.64(红灯),
  修复后=-90000(绿灯,精确匹配)
- 121个测试全通过,无回归
2026-07-02 10:47:23 +08:00
hjhan 0e045d89db test(swap): GLMS-20260105-0007分红精度差异golden红灯(复现0.36差异)
用真实测试库数据录制golden,回放复现0.36精度差异:
- 互换前 PosiDividendSum=-90400,互换支付-400
- 期望 PosiDividendSum=-90000,实际=-89999.64,差异0.36
- 回放断言失败(红灯坐实bug)

根因:UpdateEodPosition cs:1635从头重算PosiDividendSum
(Round(全程,2)-已实现),与CopyEodPosition逐天递增
(每天Round(增量,2)累积)产生舍入误差。

录制方法Record_FromRealDB标[Ignore],手动跑生成golden。
回放方法Replay_VerifyPrecisionDiff进CI,当前红灯(期望=-90000,实际=-89999.64)。
2026-07-02 10:28:23 +08:00
hjhan d11e332ff3 test(swap): golden录制/回放基础设施+DealInterests场景
引入golden回放框架,补充合成测试的精确值验证缺口。

新增GoldenReplayFramework.cs:
- GoldenScenarioModel: 通用golden数据模型(输入+期望输出)
- GoldenAssert: 精确字段对比(容许指定位数误差),逐字段验证

新增DealInterestsGoldenReplayTest.cs:
- Record_AllGoldenScenarios: 生成golden JSON(标Ignore,手动跑)
- Replay_AllGoldenFiles: 读golden重跑+精确对比(进CI)

2个golden场景:
- 互换结清后待实现归零: InterestIncomeSum=0.82191780822(精确到11位)
- 普通日归档递增(回放暂不支持自动重放,留后续)

golden文件持久化到Resources/GoldenFiles/DealInterestsGolden/

价值:重构时如果任何字段变了(哪怕第8位小数),回放立刻失败。
守恒测试验证大方向对,golden验证精确值对。

验证: 119+1(回放)=120全通过。
2026-07-02 09:37:18 +08:00
hjhan 64f0c82bbb test(swap): 多步生命周期守恒测试(数学不变量验证)
用数学守恒约束验证利息在多次操作后不丢失/不重复。
这类测试的价值:不管代码怎么改,只要守恒不成立就报错。

4个守恒场景:
- MS_001: 连续收盘10天,每天增量之和=10天总利息(防指数增长/丢失)
- MS_002: 半平50%+后续全平,两次利息都>0不为负(防consumedInterest扣过头)
- MS_003: 互换结清后再平仓只有增量(单利靠eod归零传递)
- MS_004: 多次互换(第5天+第10天)+最终平仓(第15天),
  累计consumed+平仓=全程复利利息(守恒不变量)

StubDealService支持构造注入consumedInterest和floatRate。
CalcEodInterest返回(当日增量,全程累计)元组,正确区分TdInterestAmount和InterestAmount。

验证: 115+4=119全通过。
2026-07-02 09:20:41 +08:00
hjhan fb0ab3e948 test(swap): ClearSwapPositions重收盘清理合成测试(78751f0a覆盖)
验证78751f0a的核心修复:重收盘清理自动互换资金记录时排除手动互换。

4个测试场景:
- CSW_001: 自动互换资金记录被正确选中删除
- CSW_002: 手动互换资金记录被排除(manualClientCashIds排除逻辑)
- CSW_003: 已在excludedClientCashIds中的记录不重复选中
- CSW_004: 预付金返息记录也参与清理(手动被排除)

Stub override 3个虚方法注入内存数据:
FindFlowEventsByEventIds/FindManualClientCashIds/FindClientCashRecords

至此4个最近修复全部有合成测试覆盖:
①复利consumedInterest() ②eod InterestIncomeSum()
③重收盘误删资金() ④分红重复计算()
验证: 111+4=115全通过。
2026-07-02 09:11:38 +08:00
hjhan 17005aa539 refactor(swap): ClearSwapPositions接缝-GetLegacyAutoSwapClientCashRecords可测化
SwapTradeBaseService加3个protected virtual虚方法:
- FindFlowEventsByEventIds: 查flow_event(原DbContext.swap_flow_event)
- FindManualClientCashIds: 查手动互换ClientCashId(原DbContext.swap_event)
- FindClientCashInCashOut: 查资金记录(原DbContext.ClientCashInCashOut)

GetLegacyAutoSwapClientCashRecords改为protected virtual,
内部3处DB查询替换为调虚方法。

这是78751f0a(重收盘误删资金修复)的核心逻辑:
GetLegacyAutoSwapClientCashRecords负责排除manualClientCashIds,
确保手动互换资金记录不被误删。

验证: 111个测试全通过。
2026-07-02 09:08:05 +08:00
hjhan eaa4ed735a test(swap): DealFloatPositions分红场景测试(盯市盈亏+分红+增值税)
扩展StubEodService override 3个外部依赖虚方法:
- GetUnderlyingPrice: 注入固定标的价格
- GetUnderlyingData: 注入标的缓存(增值税率)
- CalcBondPayment: 注入固定债券付息

新增3个分红场景测试:
- DF_005: CopyEodPosition盯市盈亏=(price-grossPrice)×qty×方向
- DF_006: 分红计算 TdPosiDividend=payment/(1+tax)×(1-tax)
- DF_007: 增值税调整(tax=6%): 100/1.06×0.94≈88.68

覆盖了cf2f8b6e分红重复计算修复所在的浮动腿归档链路。
验证: 108+3=111全通过。
2026-07-02 09:02:43 +08:00
hjhan 7c993f7bb2 refactor(swap): DealFloatPositions外部依赖虚方法接缝(分红场景准备)
加3个protected virtual虚方法:
- GetUnderlyingPrice: 标的市场价格(原UnderlyingCodePrice)
- GetUnderlyingData: 标的缓存数据(原DataCacheProvider)
- CalcBondPayment: 债券付息(原new BondPaymentService)

替换CopyEodPosition/UpdateEodPosition/SaveCurrentEodInitalPosi
内部的外部调用为调虚方法,生产代码行为不变。

这3个接缝使浮动腿归档的分红计算可测(TdPosiDividend/PosiDividendSum)。
验证: 108个测试全通过。
2026-07-02 08:57:55 +08:00
hjhan fee2203d6e test(swap): DealFloatPositions浮动腿归档合成测试(testable迁移)
新增4个浮动腿归档场景测试:
- DF_001: 空持仓返回空列表
- DF_002: 首日无eod走SaveCurrentEodInitalPosi分支
- DF_003: SaveCurrentEodInitalPosi纯计算字段验证(数量/均价/类型)
- DF_004: 有eod无平仓走CopyEodPosition分支(分支选择验证)

DealFloatPositions和子方法无直接DB调用(数据从参数传入),
但CopyEodPosition/UpdateEodPosition依赖外部数据源
(DataCacheProvider/UnderlyingCodePrice/BondPaymentService),
值验证需后续加接缝。当前覆盖分支选择+首日初始化值验证。

验证: 104+4=108全通过。
2026-07-02 08:49:50 +08:00
hjhan 4138a6ec36 refactor(swap): DealFloatPositions浮动腿归档方法可见性放开(testable迁移)
4个方法private→protected,不改变生产行为:
- DealFloatPositions(浮动腿归档主调度)
- CopyEodPosition(无平仓复制前日)
- UpdateEodPosition(有平仓更新)
- SaveCurrentEodInitalPosi(首日初始化)

这4个方法本身无直接DB调用(数据从参数传入),
但CopyEodPosition/UpdateEodPosition依赖外部数据源
(UnderlyingCodePrice/BondPaymentService/DataCacheProvider),
需后续加接缝才能完整测试。
SaveCurrentEodInitalPosi是纯计算可直接测。

验证: 104个测试全通过。
2026-07-02 08:47:30 +08:00
hjhan 7f0529bbed test(swap): ComposePage流水合成持仓合成测试(testable迁移)
新增4个ComposePage场景测试(参考testable分支ComposePageScenarioTest):
- CP_001: 空事件→不创建持仓
- CP_002: 单条开仓→创建1条持仓,均价=开仓价
- CP_003: 两条开仓(同标的)→加权均价
- CP_004: 开仓+平仓→平仓扣减数量+产生资金记录

改动(SwapEodPositionService.cs):
- SaveEodPosition改为protected virtual(可override绕过UpdateSwapPosition连库)
- SaveEodPosition内部DbContext.Add替换为PersistEodSwapPosition

StubEodPositionService override 12个虚方法:
FindTrade/FindTradeExtend/FindEodSwapPositions/FindSwapPositions/
FindEodSwap/AddSwapEvent/AddClientCash/SaveEodSwapRecord/
ClearSwapPositionsForCompose/PersistEodSwapPosition/SaveAllChanges/
GetCurrencyRate + SaveEodPosition

验证: 100+4=104全通过(T0/T1=89+DealInterests=7+ConsumedInterest=4+ComposePage=4)。
2026-07-02 08:39:39 +08:00
hjhan 886a4d3ab1 refactor(swap): ComposePage补充接缝-AddClientCash/SaveEodSwapRecord/ClearSwapPositionsForCompose
ComposePage内部还有3处DB依赖需要接缝:
- AddClientCashInCashOut(cs:804平仓资金记录) → AddClientCash虚方法
- SaveEodSwap(cs:862框架合约汇总) → SaveEodSwapRecord虚方法
- ClearSwapPositions(cs:729清理旧事件) → ClearSwapPositionsForCompose虚方法

测试时override这3个虚方法可避免连库。
验证: 100个测试全通过。
2026-07-02 08:34:49 +08:00
hjhan 014edaed45 refactor(swap): ComposePage接缝-7虚方法+DB调用替换(testable迁移)
ComposePage(流水合成持仓)是swap_flow_event→swap_position的核心转换,
每笔开仓/平仓/互换都经过这里(176行)。

新增7个protected virtual虚方法(Seams):
- FindTrade/FindTradeExtend/FindSwapPositions
- FindEodSwapPositions/FindEodSwap
- AddSwapEvent/ExecuteInTransaction

ComposePage内部DB调用替换为调虚方法:
- DbContext.trade.Find → FindTrade
- DbContext.trade_extend.FirstOrDefault → FindTradeExtend
- DbContext.eod_swap_position.Where → FindEodSwapPositions
- DbContext.swap_position.Where → FindSwapPositions
- DbContext.eod_swap.FirstOrDefault → FindEodSwap
- new SwapEventService.AddSwapEventDate → AddSwapEvent
- DbContext.SaveChanges → SaveAllChanges(已有)
- ComposePage可见性private→protected

生产代码行为不变(虚方法默认实现=原逻辑)。
验证: 100个测试全通过(T0/T1=89+DealInterests=7+ConsumedInterest=4)。
2026-07-02 08:28:13 +08:00
hjhan f501ee95a7 test(swap): 复利consumedInterest扣除合成测试(补c6adb3bb覆盖缺口)
c6adb3bb加的复利consumedInterest扣除此前无任何测试覆盖。
现在用4个合成测试完整验证:

改动(SwapDealService.cs):
- GetConsumedInterest加virtual关键字(测试可override注入内存值)

新增(ConsumedInterestScenarioTest.cs):
- StubSwapDealService override TryGetFloatRate+GetConsumedInterest
  (模仿T0/T1的StubSwapDealService模式)
- CI_001: 基线(consumedInterest=0)拿到全程复利利息
- CI_002: 注入consumedInterest后利息=基线-consumed(直接验证cs:793)
- CI_003: 守恒(consumed+利息=基线)×3组不同consumed值
- CI_004: 全部已结(consumed=基线)平仓≈0不为负(防双重扣减)

关键发现:测试必须传settment:false走盘中平仓路径(CalcUnwindInterest),
settment:true(默认)走收盘归档路径(CalcEodInterest)不传consumedInterest。

验证: 89(T0/T1)+7(DealInterests)+4(ConsumedInterest)=100全通过。
2026-07-01 18:40:48 +08:00
hjhan be88442c91 test(swap): 扩展DealInterests测试-多次互换守恒+预付金ratio翻转
新增2个测试场景:
- DI_SWAP_MULTI_001: 攒10天→互换结清→再攒5天→再互换结清
  守恒约束: RealizedInterest+InterestIncomeSum=全程利息(17天)
  验证多次互换结算后利息不丢失/不重复
- DI_MARGIN_001: 预付金腿(初始预付金,marginTypes)互换结清后
  RealizedInterest应为负(ratio翻转:收取→-1→支付方向)
  验证cs:789-793的marginTypes ratio翻转逻辑

验证: 89(T0/T1)+7(DealInterests)=96全通过,无回归。
2026-07-01 18:25:44 +08:00
hjhan 775d7a5881 test(swap): 阶段3 扩展DealInterests测试-普通日归档值+多日连续守恒
依赖阶段1c的CalcSwapInterests虚方法接缝,现在普通日分支(copy)
也可纯内存测试。

新增/改进的测试:
- DI_BRANCH_001: 改为真正的普通日归档值验证(InterestIncomeSum
  前日+1天新计=2天利息),不再是Inconclusive
- DI_MULTI_001: 连续5天收盘归档,验证InterestIncomeSum线性递增
  (每天+1天利息,5天后=5×DailyInterest)

StubEodPositionService扩展:
- override CalcSwapInterests(用真实SwapDealService算固定利率利息)
- ExecuteDealInterests public包装(替代反射调用)
- 删除旧的反射辅助方法

验证: 89(T0/T1)+5(DealInterests)=94全通过,无回归。
2026-07-01 18:21:51 +08:00
hjhan 638803c497 refactor(swap): 阶段1c CalcSwapInterests虚方法接缝(testable迁移)
加1个protected virtual虚方法:
- CalcSwapInterests: 计算利息腿利息明细(原new SwapDealService(this).GetInterests)
  参数与GetInterests完全一致,保证行为不变

将3个分支方法里的'new SwapDealService(this).GetInterests'替换为
调用CalcSwapInterests虚方法:
- SaveAutoEodInterestPosition(自动互换分支)
- SaveAutoEodWithCloseInterestPosition(平仓分支)
- SaveEodInterestPositionCopy(普通日分支)

测试子类override CalcSwapInterests,用StubSwapDealService
(已有89个测试验证)内存算利息,即可测全部4个分支。

验证: 93个测试全通过(T0/T1=89 + DealInterests=4),无回归。
2026-07-01 18:17:47 +08:00
hjhan deb831bf3e test(swap): 阶段2 DealInterests利息归档合成测试(testable迁移)
模仿GetInterestsUnitTest_T0风格,纯内存不连库:
- StubEodPositionService继承生产类,override PersistEodSwapPosition/
  SaveAllChanges/GetCurrencyRate替换DB调用
- 内存构造trade/position/eod/flowEvent数据
- 独立计算期望值(非循环论证)

4个测试场景:
- DI_SWAP_ZERO_001: 互换结清后InterestIncomeSum=当天新计(非攒的全程)
- DI_SWAP_ZERO_002: 已结清后再互换(只结算当天新计)InterestIncomeSum=0
- DI_BRANCH_001: 普通日走copy分支
- DI_BRANCH_002: 互换日走SaveEodInterestPosition分支

验证: 89(T0/T1)+4(DealInterests)=93全通过,无回归。
注意: fc90636a把公式改回pre+新计-实现(比我之前的pre-实现更好,
保留了当天新计利息),测试断言已据此调整。
2026-07-01 17:47:00 +08:00
hjhan dc3a6e9f77 refactor(swap): 阶段1b SwapEodPositionService加虚方法接缝(testable迁移)
加3个protected virtual虚方法(Seams接缝),不改变生产行为:
- PersistEodSwapPosition: 持久化eod持仓(原DbContext.Add+UpdateDbOption)
- SaveAllChanges: 保存变更(原DbContext.SaveChanges)
- GetCurrencyRate: 获取汇率(原new EodCurrencyRateService)

将4个利息归档分支方法里的直接DB调用替换为调虚方法:
- SaveEodInterestPosition(互换分支)
- SaveAutoEodInterestPosition(自动互换分支)
- SaveAutoEodWithCloseInterestPosition(平仓分支)
- SaveEodInterestPositionCopy(普通计息分支)

测试子类override这些虚方法即可在内存中运行收盘逻辑,
不连数据库。生产代码行为完全不变(虚方法默认实现=原逻辑)。

验证: GetInterestsUnitTest_T0/T1 89个测试全通过,无回归。
2026-07-01 17:21:56 +08:00
hjhan b548709371 Revert "fix(swap): 互换审核通过后到期日状态流转为已到期"
This reverts commit 83f44124c6.
2026-07-01 17:07:55 +08:00
hjhan 3e5a939689 refactor(swap): 阶段1a DealInterests利息归档方法可见性放开(testable迁移准备)
将5个利息腿归档相关方法从private改为protected,不改变生产行为:
- DealInterests(利息腿归档主调度)
- SaveEodInterestPosition(手动互换分支)
- SaveAutoEodInterestPosition(自动互换分支)
- SaveAutoEodWithCloseInterestPosition(平仓分支)
- SaveEodInterestPositionCopy(普通计息分支)

这是testable迁移第一步:先放开可见性让测试子类能调用,
后续阶段再加虚方法接缝(替换DB调用)和迁移合成测试。

参考: refactor-swap-event-testable分支 Seams模式改造
2026-07-01 16:47:26 +08:00
hjhan 47f95fcc45 fix(swap): 互换结清后eod待实现利息正确扣减(SaveEodInterestPosition)
SaveEodInterestPosition(cs:834)原公式:
  InterestIncomeSum = pre + TdInterestIncome - TdCloseInterest
其中 TdInterestIncome = TdCloseInterest(互换日全程利息),
两者抵消导致 InterestIncomeSum=pre不变。
互换结清后待实现没归零,后续平仓默认值偏大。

修复:只改InterestIncomeSum公式为 pre - TdCloseInterest
(前日待实现 - 当日实现 = 剩余待实现)。
TdInterestIncome保持原值不动(入库字段,影响报表)。

验证需重新收盘:修复改的是eod生成逻辑,已有eod不会自动变。
2026-07-01 13:58:24 +08:00
hjhan f7d23dc132 revert: 撤销单利consumedInterest扣除(双重扣减导致1天利息变0)
单利起点InterestProfitSum已含历史累计(eod快照),
再减consumedInterest会双重扣减。复利起点是0(从头算),
减consumedInterest正确。两者计算结构不同不能套用。

正确方向:让InterestProfitSum在互换结清后归零(eod层方案B),
而非在计算时减consumedInterest。待重新设计单利修复方案。

测试还原为红灯(Assert redCount>0),注释更新说明正确方向。
2026-07-01 13:38:24 +08:00
hjhan 83f44124c6 fix(swap): 互换审核通过后到期日状态流转为已到期
ApproveSwapTrade(cs:1558-1571)状态分支只判CloseMethod==全部平仓,
无ExerciseDate到期判断。互换CloseMethod默认0(Unknown)必走else→
TradeStatus退回确认成交→EodCheckMaturityTrade一直阻止收盘。
对比免审核路径SwapIncome(cs:1512)有正确的到期判断。
引入点083848fb(2025-05-28审核流程重构)。

改动(SwapDealService.cs cs:1579后):
在td.Notional=td.TradeAmount之后补到期判断(避免清零被覆盖):
if(eventType==互换 && ExerciseDate<=ValueDate)→已到期+清零Notional

副作用控制:
- 加eventType==互换条件→不影响平仓(eventType=2)审核
- 放cs:1579之后→Notional=0不被td.Notional=td.TradeAmount覆盖
- ExerciseDate<=ValueDate→非到期互换不进分支

验证: Step1坐实28/28互换事件走else分支, Step3验证3条到期互换→已到期
发现平仓部分平仓+到期也有类似问题(GL-20260420-0003),待业务确认处理方式
2026-07-01 13:02:43 +08:00
hjhan 1eb791381a fix(swap): 单利路径扣除历史已结利息consumedInterest
复利路径已由c6adb3bb修复(加consumedInterest扣除),单利路径
CalcDailySimpleInterest未同步。互换结清后再平仓默认值偏大。

改动(SwapDealService.cs 3处):
- cs:437 去掉InterestType==复利条件,单利也取GetConsumedInterest
- cs:707 单利调用传入consumedInterest参数
- cs:802/856 CalcDailySimpleInterest签名加consumedInterest+末尾扣除

验证(Step1_SimpleInterestRedTest): 1813单利样本
34203偏大量8271→0, 34204预付金偏大量58→0(修正测试口径漏乘ratio)
复利回归(1889): 6-30默认值仍6.44无退化
2026-07-01 13:02:15 +08:00
hjhan 3118c44365 互换三个bug的TDD红灯/绿灯测试
单利利息偏大(红灯): Step1_SimpleInterestRedTest 用1813坐实
单利路径(CalcDailySimpleInterest)未加consumedInterest扣除,
默认值偏大8271(历史已结利息未扣)。复利路径c6adb3bb已修。

审核状态卡死(红灯): SwapApproveStatusStuckTest 3个方法
坐实28/28互换事件CloseMethod=0走else分支(无ExerciseDate判断),
当前3笔交易实际卡死(到期+确认成交)。Step2分析副作用:Notional清零
需放cs:1577之后避免被td.Notional=td.TradeAmount覆盖。

重收盘误删(绿灯确认): Step1加修复后逻辑模拟,确认排除manualClientCashIds
后手动互换记录不再被命中(78751f0a已修)。
2026-07-01 12:22:57 +08:00
hjhan cd03fc53fb 互换两个独立bug分析文档+诊断测试
Bug①利息默认值偏大: 互换结清后eod的InterestProfitSum(待实现)没归零
(=RealizedInterest=77.26), 导致后续平仓默认值=77.26(本该0)+增量→偏大。
6-29收盘后三天对比坐实: 6-30默认83.70, 7-1默认90.14, 均含已实现的77.26。
根因 eod公式cs:829 对互换场景扣减失效(TdInterestIncome≈TdCloseInterest抵消)。

Bug②收益结算审核后状态卡死: ApproveSwapTrade(cs:1525)漏ExerciseDate判断,
到期互换审核后状态退回'确认成交'(CloseMethod默认0≠全部平仓1),
导致EodCheckMaturityTrade一直阻止收盘。引入点083848fb(2025-05-28)。

- 新增利息偏大分析文档(根因/修复方案A扣RealizedInterest/B eod归零)
- 新增审核状态卡死分析文档(根因/修复补ExerciseDate判断)
- 新增SwapPartialUnwindInterestDefaultTest(Step0探查/Step0b诊断/Step0d三天对比)
2026-07-01 09:57:25 +08:00
hjhan 6f9aa5fb45 互换重收盘误删手动互换资金记录: 分析文档+TDD红灯测试
问题:重新收盘后用户手动互换产生的资金记录(ClientCashInCashOut,
Action=系统操作-互换)被误删。根因 ClearSwapPositions:400 按 Action
字符串模糊删除,而该 Action 手动/自动共用,表无来源字段区分。
引入点 commit 44e89726(2026-05-14)。

- 新增决策文档(根因/引入时间/三种修复方案/自测方法)
- 新增 SwapReEodDeleteManualCashRecordTest 4个测试(探查/诊断/录制红灯/离线校验)
- 录制 golden 坐实 bug: trade 1903 手动互换资金记录 id=13032 会被误删
2026-07-01 08:35:58 +08:00
hjhan 5a731c4442 docs(swap): MarkClosePnl字段语义统一决策文档
修复ab70531f让MarkClosePnl不再含分红后,梳理出消费端3处PosiPnl公式
不一致(①不减分红/②③减分红,2024~2026分批引入),其中②③对新数据
会多减一份分红导致结算单/收益偏小。

给出3种改法权衡(修正公式/数据迁移/TotalClosePnl分离)+建议分阶段路径,
列出4个需团队决策的问题。含字段引用全景表便于实施定位。
2026-06-26 13:41:32 +08:00
hjhan ee1e8487d7 docs(swap): 排查SQL新增第2.5步-分红重复计算完整证明
4段查询还原证据链(含事件/价格/费用/付息明细):
段1事件拆解 MarkClosePnl=价差+费+分红;段2 EOD逐日盯市vs分红列;
段3累计对照;段4一句话结论。已连库实测:1875重复302400、1891重复-18.66。

修正段1列名: PosiNetPrice/PosiGrossPrice 在swap_flow_event是[NotMapped]
不入库,改用 TradingAmountNetAvg/TradingAmountNetFeeAvg。
2026-06-26 09:55:19 +08:00
hjhan 029475ce8d test(swap): 新增互换分红重复计算录制测试+排查SQL(TDD红灯)
分红被重复计入 RealizedPnl 两次的根因:互换/平仓事件的 MarkClosePnl
已含分红成分(DividendIn),导致分红既进 RealizedMtmPnL(盯市列) 又进
RealizedDividend(分红列)。本次提供数据证据与回归基线:

- SwapDividendGoldenRecordTest: 连库录制1875(纯分红型)/1891(混合型)
  5表快照→JSON golden,录制时逐事件拆解 MarkClosePnl=价差+费+分红,
  按 PositionId 汇总出重复计入的分红金额。Step2 离线校验已通过。
  诊断结论:1875 重复302400,1891 重复-18.66,均与 eod 分红列吻合。
- golden JSON 纳入源码树(全量复制规则),修复后可作回归基线。
- 排查SQL工具箱: 基于真实DDL核对全部列名(swap_flow_event.EventDate/
  bond_payment_info.paying_interest 等),含定位样本/导出/验证/守恒4步。
- appsettings.json 测试库 zszq→glms 前缀修正。

详见 项目文档/互换分红损益字段语义与重复计算分析.md(9e6af84e)。
2026-06-26 09:13:37 +08:00
hjhan 9e6af84e47 新增文档:互换分红损益字段语义与重复计算分析
分析互换分红/付息损益核算链路中的字段语义混乱与分红重复计算问题,
用真实交易数据佐证,供团队对齐字段语义、确定修复方案:

- 核心结论:MarkClosePnl含分红(价差+费+DividendIn),而DividendIn又
  单独存同一笔分红,导致汇总时分红算2次(确定,非2~3次)
- 字段三层分类:客观源头/一次计算/入库字段,理清哪些是录入哪些是计算
- totalInterest链路:payment_interest→求和→×0.01→增值税调整→DividendIn
- MarkClosePnl含分红的四场景对照(手动互换/平仓、自动互换/平仓)
- 真实数据佐证:6笔交易(含EventType=3/4)显示差值=0且价差=0
- 重复次数确定2次:两个层级各自独立计算,非叠加3次
- 演进过程(f9d8a256→2140a97f,用hash+日期)
- 修复方向A(治本:MarkClosePnl不含分红)/B(保守:改汇总公式)
- 附录A:验证SQL(重复检验/守恒检验)
- 附录B:精确文件:类:行号索引
- 附录C:calcFloatClosePnl两处不一致技术债(floatRatio/longRatio)
- 附录D:测试策略(记录golden source分支refactor-swap-event-testable)
2026-06-26 07:33:36 +08:00
hjhan 697c7babf2 新增文档:互换交易价格字段存储与显示规范
汇总互换价格显示Bug排查结论,供后续维护参考:
- 核心规则:债券类入库相对价(÷100)、展示×100;非债券类原样
- ÷100机制:由FastVue.parseNumber实现(percent:true时number/100)
- 关键字段映射:swap_position/swap_flow_event/eod_swap_position
  (标注TradingAmountNetAvg名像期末实装期初、PosiGrossPrice在
  event表为NotMapped等易混点)
- 互换事件生成路径:手动/自动互换-分红型/利息端
- 已修复Bug与教训(4个)
- 附录A:排查工具箱SQL(5个,期初持仓/事件入库值/分红数据源/
  中债估值/脏数据修复)
- 附录B:字段命名与数据流向速查表
2026-06-25 19:15:54 +08:00
hjhan 818619bc70 补充DV01计算工具的注释:明确输出单位为万元及入参单位
Dv01Helper.CalcDv01 与业界标准一致,但输出单位是万元而非元,且
PosiQuantity须为元面值单位。原注释未说明这些口径,易导致误读。
补充:
- 类注释:写明公式等价业界标准DV01(元)/10000,输出万元
- posiQuantity入参:标注须为元面值单位
- vobp入参:标注为每100元面值1bp的价格变动
- 返回值:标注单位为万元
- 券面总额计算行:标注交易数量单位为元面值

仅注释改动,不改逻辑。
2026-06-25 19:15:27 +08:00
hjhan 0ab6091962 修复分红型自动互换在互换Tab显示期初/期末价未×100及期初净价为0
DealDividends生成分红型自动互换事件时,漏赋了UnderlyingInstrumentType和
TradingAmountNetAvg两个字段,导致互换Tab(TradeView)显示异常:

1. UnderlyingInstrumentType缺失:TradeView第654行IsBond判断为false,
   multiplier=1,走了非债券分支(不×100),使期初/期末价显示为相对价(1.00)
   而非百分比(100%)。补赋eodPosi.UnderlyingInstrumentType后,
   与手动互换一致走债券分支(×100)。

2. TradingAmountNetAvg缺失:TradeView第993行显示期初净价取该字段,
   缺失导致显示0。补赋eodPosi.PosiNetNoFeePrice修复。

入库的TradingAmountAvg(相对价)本来就正确,仅显示层判断缺字段。
仅改动DealDividends,不影响平仓/手动互换/显示层逻辑。
2026-06-25 18:09:50 +08:00
hjhan 276c1c2961 修复互换收益结算期末价不可编辑及刷新图标缺失
ab09cbc9为支持自动互换期间付息,误将期末标的价格改为纯文本不可编辑,
并删除了changeUnderlyingPrice/refreshUnderlyingPrice方法。开发误解了需求:
自动互换默认填上次互换价是后端逻辑,手动互换时期末价应可编辑+刷新(与平仓页一致)。

对齐平仓页(SwapUnwind)恢复:
- incomeSwapTrade.js: 恢复changeUnderlyingPrice、refreshUnderlyingPrice方法
- SwapIncome.cshtml: 期末价列恢复vue-number-input输入框+刷新图标
- SwapDealService.cs/InitIncome: 补充注释说明TradingAmountNetAvg字段
  虽名为期末语义但此处装入期初净价,避免后续混淆
2026-06-25 14:41:55 +08:00
hjhan ca68178bf8 修复互换收益结算期初净价显示0的问题
期初净价列取TradingAmountNetAvg字段,后端InitIncome赋值为
position.PosiNetNoFeePrice(可空)。部分交易录入时未填该字段(值为0),
导致期初净价显示为0(如trade 1892/1859)。

改为:TradingAmountNetAvg为0时回退使用PosiNetPrice(期初净价,始终有值)。
仅前端兜底,不改动后端及平仓页。
2026-06-25 14:41:55 +08:00
hjhan 20ea93d89c 修复互换收益结算期末价被错误缩放及显示问题
a00fe3cc合并etf分支时,误把initDeal中TradingAmountAvg的×100缩放去掉,
导致期末标的价格停留在相对价态(1.02),提交时又被getPriceScale()÷100,
最终swap_flow_event.TradingAmountAvg入库为0.0102,且盈亏计算错误。

对齐平仓页(unwindSwapTrade.js)的正确实现:
- initDeal: TradingAmountAvg = initPosiNetPrice × multiplier 转为界面百分比态
- SwapIncome表格期末价列: 不再经过priceFormat(避免二次×100),直接显示界面态值
2026-06-25 14:04:54 +08:00
hjhan b4c8d0363d Merge branch 'glms/feature/1.4.2' of http://git.yiliantech.com/gitlab/otc-dev/zszq-trs into glms/feature/1.4.2 2026-04-29 16:55:20 +08:00
hjhan 735b7177ba feat(monitor): 添加神策数据诊断日志,排查 platform_type 和 uid 为未知的问题 2026-04-29 16:54:36 +08:00
hjhan 8f405091e1 fix(auth): V3Controller 补充缺失的菜单权限
收益凭证、凭证审批等 v3 路由菜单因 V3Controller 的 MyAuthorize 未包含对应权限,
导致需要依赖白名单券池等其他权限才能访问页面
2026-04-29 11:31:56 +08:00
hjhan 7cd937518f refactor(auth): 优化JWT令牌创建方法
- 移除CreateJwtToken2方法,统一使用CreateJwtToken方法
- 修改密钥处理方式,从ASCII字符串改为Base64解码
- 删除IssuedAt声明以简化令牌结构
- 更新所有相关调用点使用统一的令牌创建方法
2026-04-27 15:34:12 +08:00
hjhan 8745b76cac feat(auth): 401未授权时弹窗提示登录过期再跳转
AJAX请求返回401时弹出提示,用户点击确定或3秒后自动跳转登录页,
防止页面直接跳转让用户困惑
2026-04-27 14:14:54 +08:00
hjhan bac16132a8 fix(auth): Cookie认证AJAX请求返回401并增加诊断日志
OnRedirectToLogin/OnRedirectToAccessDenied中对AJAX请求返回401而非302,
并增加请求头诊断日志便于排查认证跳转问题
2026-04-27 13:25:50 +08:00