From 43981e245b8540314364a90858ba30cb1ea94d7a Mon Sep 17 00:00:00 2001 From: tengyufan <1532636164@qq.com> Date: Thu, 30 Jul 2026 14:46:07 +0800 Subject: [PATCH] =?UTF-8?q?#EQD-6718=20=E5=9B=BD=E8=81=94=E6=B0=91?= =?UTF-8?q?=E7=94=9F-=E6=94=B6=E7=9B=8A=E4=BA=92=E6=8D=A2=E9=9A=90?= =?UTF-8?q?=E8=97=8F=E6=94=B6=E6=94=AF=E6=96=B9=E5=90=91=EF=BC=8C=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E6=88=91=E6=96=B9=E6=94=B6=E5=8F=96=E6=B5=AE=E5=8A=A8?= =?UTF-8?q?=E6=94=B6=E7=9B=8A=20fix:=E5=9B=BD=E8=81=94=E6=B0=91=E7=94=9F?= =?UTF-8?q?=E6=94=B6=E7=9B=8A=E4=BA=92=E6=8D=A2=E9=9A=90=E8=97=8F=E6=94=B6?= =?UTF-8?q?=E6=94=AF=E6=96=B9=E5=90=91=EF=BC=8C=E9=BB=98=E8=AE=A4=E6=88=91?= =?UTF-8?q?=E6=96=B9=E6=94=B6=E5=8F=96=E6=B5=AE=E5=8A=A8=E6=94=B6=E7=9B=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增可配置开关 Erp.SwapFloatingIncomeReceiveOnlyMode,默认关闭,支持在普通模式与网厅适配模式之间切换 - 网厅适配模式下,新增及续做收益互换默认浮动端为我方收取,并隐藏新增、平仓、收益结算及查看页面的浮动端收支方向 - 普通模式保持原有展示和编辑逻辑,历史交易不修改原有浮动端收支方向 - 日终持仓风险_互换将浮动收支方向和标的多空合并为交易方向,并同步影响导出 - 交易方向映射收取+B为多头、收取+S为空头、支付+B为空头、支付+S为多头 - 新增交易方向映射专项前端单测 --- .../Configuration/Abstract/IErpConfig.cs | 8 ++- .../Configuration/ProjectSettings.cs | 8 ++- YLErpDAL/Modules/AppModule/AppUpgrader.cs | 1 + YLErpWeb/Views/SwapTrade2/SwapIncome.cshtml | 11 ++- YLErpWeb/Views/SwapTrade2/SwapUnwind.cshtml | 11 ++- YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml | 9 +-- YLErpWeb/Views/SwapTrade2/TradeView.cshtml | 71 +++++++++++++------ YLErpWeb/fe-tests/eodPositionRisks.test.js | 39 ++++++++++ .../Scripts/app/swaptrade/EodPositionRisks.js | 31 ++++---- .../Scripts/app/swaptrade/swapTradeEdit.js | 12 +++- 10 files changed, 154 insertions(+), 47 deletions(-) create mode 100644 YLErpWeb/fe-tests/eodPositionRisks.test.js diff --git a/Framework/YLErp.Core/Configuration/Abstract/IErpConfig.cs b/Framework/YLErp.Core/Configuration/Abstract/IErpConfig.cs index 8e00b1b4..5e597013 100644 --- a/Framework/YLErp.Core/Configuration/Abstract/IErpConfig.cs +++ b/Framework/YLErp.Core/Configuration/Abstract/IErpConfig.cs @@ -696,6 +696,12 @@ namespace YLErp.Configuration /// 确认书生成时是否自动用印 /// bool IsAutoSealAfterGeneratedBook { get; } + + /// + /// 收益互换浮动收益端默认为我方收取,并隐藏收支方向 + /// + bool SwapFloatingIncomeReceiveOnlyMode { get; } + /// /// 衡泰内证账号 /// @@ -725,4 +731,4 @@ namespace YLErp.Configuration /// string EodExecCallbackUrl { get; } } -} \ No newline at end of file +} diff --git a/Framework/YLErp.Core/Configuration/ProjectSettings.cs b/Framework/YLErp.Core/Configuration/ProjectSettings.cs index f88f6d9c..7b4fe8ca 100644 --- a/Framework/YLErp.Core/Configuration/ProjectSettings.cs +++ b/Framework/YLErp.Core/Configuration/ProjectSettings.cs @@ -811,6 +811,12 @@ namespace YLErp /// 确认书生成时是否自动用印 /// public bool IsAutoSealAfterGeneratedBook { get; set; } = false; + + /// + /// 收益互换浮动收益端默认为我方收取,并隐藏收支方向 + /// + public bool SwapFloatingIncomeReceiveOnlyMode { get; set; } = false; + /// /// 衡泰内证账号 /// @@ -842,4 +848,4 @@ namespace YLErp public string EodExecCallbackUrl { get; set; } = string.Empty; } } -} \ No newline at end of file +} diff --git a/YLErpDAL/Modules/AppModule/AppUpgrader.cs b/YLErpDAL/Modules/AppModule/AppUpgrader.cs index 945744b1..583afcb1 100644 --- a/YLErpDAL/Modules/AppModule/AppUpgrader.cs +++ b/YLErpDAL/Modules/AppModule/AppUpgrader.cs @@ -306,6 +306,7 @@ namespace YLErp.Modules.AppModule //----------------------------------------------- configService.AddDataIfNotExists("ProjectConfig", "Erp.IsAutoSealAfterGeneratedBook", "false", "bool", "确认书生成时是否自动用印(IsAutoSealAndUploadFiles勾选时生效)"); configService.AddDataIfNotExists("ProjectConfig", "Erp.ReportFileBeginNumber", "0", "int", "报送文件开始编号"); + configService.AddDataIfNotExists("ProjectConfig", "Erp.SwapFloatingIncomeReceiveOnlyMode", "false", "bool", "收益互换浮动收益端默认为我方收取,并隐藏收支方向"); RemoveUnUsed(configService); } diff --git a/YLErpWeb/Views/SwapTrade2/SwapIncome.cshtml b/YLErpWeb/Views/SwapTrade2/SwapIncome.cshtml index 4d3d6a5a..0e702cde 100644 --- a/YLErpWeb/Views/SwapTrade2/SwapIncome.cshtml +++ b/YLErpWeb/Views/SwapTrade2/SwapIncome.cshtml @@ -4,6 +4,7 @@ Layout = "~/Views/Shared/_InfoLayout.cshtml"; bool isUseApproval = ViewBag.isUseApproval; bool isShowReCheckClose = ViewBag.IsShowReCheckClose; + bool hideFloatingIncomeDirection = PS.Config.ErpElement.SwapFloatingIncomeReceiveOnlyMode; } @section CSS{ @@ -140,7 +141,10 @@ - + @if (!hideFloatingIncomeDirection) + { + + } @@ -154,7 +158,10 @@ - + @if (!hideFloatingIncomeDirection) + { + + } diff --git a/YLErpWeb/Views/SwapTrade2/SwapUnwind.cshtml b/YLErpWeb/Views/SwapTrade2/SwapUnwind.cshtml index d7683a3b..184177a4 100644 --- a/YLErpWeb/Views/SwapTrade2/SwapUnwind.cshtml +++ b/YLErpWeb/Views/SwapTrade2/SwapUnwind.cshtml @@ -4,6 +4,7 @@ Layout = "~/Views/Shared/_InfoLayout.cshtml"; bool isUseApproval = ViewBag.isUseApproval; bool isShowReCheckClose = ViewBag.IsShowReCheckClose; + bool hideFloatingIncomeDirection = PS.Config.ErpElement.SwapFloatingIncomeReceiveOnlyMode; } @section CSS{ @@ -179,7 +180,10 @@
收支方向收支方向多空方向 标的代码 期初标的交割全价%浮动端平仓盈亏
{{floatPosition.PayDirection==1?"收取":"支付"}}{{floatPosition.PayDirection==1?"收取":"支付"}} {{floatPosition.PositionType==1?"多头":"空头"}}
- + @if (!hideFloatingIncomeDirection) + { + + } @@ -193,7 +197,10 @@ - + @if (!hideFloatingIncomeDirection) + { + + } diff --git a/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml b/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml index 0b92e12f..bf22e849 100644 --- a/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml +++ b/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml @@ -80,7 +80,8 @@ tradingPlaceMap = places, clearingAgencyMap = agencys, timeUnits = GlobalData.AllTimeUnits(), - otcFormatConfig = otcFormatConfig + otcFormatConfig = otcFormatConfig, + swapFloatingIncomeReceiveOnlyMode = PS.Config.ErpElement.SwapFloatingIncomeReceiveOnlyMode }; //pageObj.clearingAgencyMap.Remove("甲方"); //pageObj.clearingAgencyMap.Remove("已方"); @@ -444,7 +445,7 @@
收支方向收支方向多空方向 标的代码 期初标的交割全价%浮动端平仓盈亏
{{floatPosition.PayDirection==1?"收取":"支付"}}{{floatPosition.PayDirection==1?"收取":"支付"}} {{floatPosition.PositionType==1?"多头":"空头"}}
- + @@ -456,7 +457,7 @@ -
收支方向收支方向 多空方向 标的代码 期初标的交割全价%交易费用后付
+ diff --git a/YLErpWeb/Views/SwapTrade2/TradeView.cshtml b/YLErpWeb/Views/SwapTrade2/TradeView.cshtml index 5ba38ed5..cde7fed6 100644 --- a/YLErpWeb/Views/SwapTrade2/TradeView.cshtml +++ b/YLErpWeb/Views/SwapTrade2/TradeView.cshtml @@ -30,6 +30,7 @@ var positions = trade.swap_positions.Where(x=>x.PosiDirection>0&&x.IsInitial).ToList(); var realPositions = trade.swap_positions.Where(x => x.PosiDirection > 0 && !x.IsInitial).ToList(); var sr = trade.trade_extend.ExtendObj.SettlementRules; + bool hideFloatingIncomeDirection = PS.Config.ErpElement.SwapFloatingIncomeReceiveOnlyMode; string SwapPriceData(decimal? value) => value?.ToString(CultureInfo.InvariantCulture) ?? string.Empty; } @section CSS{ @@ -365,10 +366,13 @@
-
-
-
-
+ @if (singleTrade || !hideFloatingIncomeDirection) + { +
+
+
+
+ } @if (trade.swap_positions != null) { var paySwapPositions = trade.swap_positions.Where(x => !string.IsNullOrEmpty(x.UnderlyingCode) && x.IsInitial&&x.PosiStartDate==trade.StartDate).ToList(); @@ -378,7 +382,10 @@
- + @if (!hideFloatingIncomeDirection) + { + + } @@ -396,7 +403,10 @@ var bgclass = item.PosiDirection == (int)SwapDirectionEnum.收取 ? "swapget" : "swappay"; var multiplier = ConsGlobal.InstrumentType.IsBond(item.UnderlyingInstrumentType) ? 100 : 1; - + @if (!hideFloatingIncomeDirection) + { + + }
收支方向收支方向多空方向 标的代码 @spotPriceTitle
@((SwapDirectionEnum)item.PosiDirection)@((SwapDirectionEnum)item.PosiDirection)@(item.PositionType == (int)PositionTypeFlag.Long ? "多头" : "空头") @item.UnderlyingCode @@ -435,7 +445,7 @@ } - else + else if (!hideFloatingIncomeDirection) {
@@ -577,10 +587,13 @@
-
-
-
-
+ @if (singleTrade || realPositions.Any(x => !string.IsNullOrEmpty(x.UnderlyingCode)) || !hideFloatingIncomeDirection) + { +
+
+
+
+ } @if (trade.swap_positions != null) { var paySwapPositions = trade.swap_positions.Where(x => !string.IsNullOrEmpty(x.UnderlyingCode) && !x.IsInitial).ToList(); @@ -590,7 +603,10 @@
- + @if (!hideFloatingIncomeDirection) + { + + } @@ -609,9 +625,12 @@ var bgclass = item.PosiDirection == 1 ? "swapget" : "swappay"; var multiplier = ConsGlobal.InstrumentType.IsBond(item.UnderlyingInstrumentType) ? 100 : 1; - + @if (!hideFloatingIncomeDirection) + { + + } @@ -639,7 +658,7 @@
收支方向收支方向多空方向 标的代码 @spotPriceTitle
- @((SwapDirectionEnum)item.PosiDirection) - + @((SwapDirectionEnum)item.PosiDirection) + @(item.PositionType == (int)PositionTypeFlag.Long ? "多头" : "空头")
} - else + else if (!hideFloatingIncomeDirection) {
@@ -797,7 +816,10 @@
- + @if (!hideFloatingIncomeDirection) + { + + } @if (isBond) @@ -817,7 +839,10 @@ - + @if (!hideFloatingIncomeDirection) + { + + } @if (isBond) @@ -993,7 +1018,10 @@
收支方向收支方向多空方向 标的代码浮动端平仓盈亏
@((SwapDirectionEnum)closeFloat.PayDirection)@((SwapDirectionEnum)closeFloat.PayDirection)@(closeFloat.PositionType == (int)PositionTypeFlag.Long ? "多头" : "空头") @closeFloat.UnderlyingCode
- + @if (!hideFloatingIncomeDirection) + { + + } @if (isBond) @@ -1013,7 +1041,10 @@ - + @if (!hideFloatingIncomeDirection) + { + + } @if (isBond) diff --git a/YLErpWeb/fe-tests/eodPositionRisks.test.js b/YLErpWeb/fe-tests/eodPositionRisks.test.js new file mode 100644 index 00000000..908528da --- /dev/null +++ b/YLErpWeb/fe-tests/eodPositionRisks.test.js @@ -0,0 +1,39 @@ +const fs = require('fs'); +const path = require('path'); +const vm = require('vm'); + +function loadEodPositionRiskHelpers() { + const filePath = path.join(__dirname, '../wwwroot/Scripts/app/swaptrade/EodPositionRisks.js'); + const code = fs.readFileSync(filePath, 'utf8') + '\nmodule.exports = { TradeDirectionFormat };'; + const sandbox = { + module: { exports: {} }, + exports: {}, + $() { }, + main: { + numberFormat() { + return function () { }; + } + } + }; + + vm.runInNewContext(code, sandbox, { filename: filePath }); + return sandbox.module.exports; +} + +const { TradeDirectionFormat } = loadEodPositionRiskHelpers(); + +describe('互换日终持仓交易方向', () => { + test.each([ + [1, 1, '多头'], + [1, 2, '空头'], + [2, 1, '空头'], + [2, 2, '多头'] + ])('收支方向=%i,多空方向=%i时展示%s', (posiDirection, positionType, expected) => { + const row = { eodPosition: { PosiDirection: posiDirection, PositionType: positionType } }; + expect(TradeDirectionFormat(positionType, {}, row)).toBe(expected); + }); + + test('无有效浮动端方向时不展示交易方向', () => { + expect(TradeDirectionFormat(1, {}, { eodPosition: { PosiDirection: 0, PositionType: 1 } })).toBe(''); + }); +}); diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/EodPositionRisks.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/EodPositionRisks.js index e6780644..8d799ab1 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/EodPositionRisks.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/EodPositionRisks.js @@ -136,20 +136,14 @@ function colModelGridEodPosition() { align: 'center', sortIndex: i++, sortable: true - }, { - name: 'eodPosition.PosiDirection', - label: '[浮动]收支方向', - index: 'eodPosition.PosiDirection', - width: 90, - align: 'center', - formatter: DrictionFormat }, { name: 'eodPosition.PositionType', - label: '标的多空(B/S)', + label: '交易方向', index: 'eodPosition.PositionType', width: 90, align: 'center', - formatter: PositionTypeFormat + formatter: TradeDirectionFormat, + sortable: false }, { name: 'eodPosition.UnderlyingCode', label: '标的代码', @@ -825,14 +819,21 @@ function NullableStockEqvNotionalFormat(cellValue, options, rowObject) { function PosiStatusFormat(cellValue, options, rowObject) { return cellValue == 1 ? "已平" : "正常"; } -function PositionTypeFormat(cellValue, options, rowObject) { - if (cellValue == 1) { - return "B"; +function TradeDirectionFormat(cellValue, options, rowObject) { + var eodPosition = rowObject && rowObject.eodPosition; + if (!eodPosition) { + return ""; } - if (cellValue == 2) { - return "S"; + + var posiDirection = Number(eodPosition.PosiDirection); + var positionType = Number(eodPosition.PositionType); + if (posiDirection === 2) { + positionType = positionType === 1 ? 2 : positionType === 2 ? 1 : 0; + } else if (posiDirection !== 1) { + return ""; } - return ""; + + return positionType === 1 ? "多头" : positionType === 2 ? "空头" : ""; } function DrictionFormat(cellValue, options, rowObject) { if (cellValue == 1) { diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js index b43786aa..7f0e627c 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js @@ -310,7 +310,10 @@ const vue = new Vue({ changeStructureType() { this.trade.StockEqvNotional = 0; let direction = this.trade.trade_extend.ExtendObj.Direction; - if (direction !== 1 && direction !== 2) { + if (page.swapFloatingIncomeReceiveOnlyMode) { + direction = 1; + this.trade.trade_extend.ExtendObj.Direction = direction; + } else if (direction !== 1 && direction !== 2) { direction = 2; this.trade.trade_extend.ExtendObj.Direction = direction; } @@ -1626,7 +1629,12 @@ const vue = new Vue({ thisObj.syncPosiFeeModeByItem(thisObj.paySwapList[0]); } } - + + if (page.isAdd && page.swapFloatingIncomeReceiveOnlyMode) { + thisObj.trade.trade_extend.ExtendObj.Direction = 1; + thisObj.paySwapList.forEach(x => x.PosiDirection = 1); + } + if (thisObj.paySwapList.length == 0) { thisObj.trade.trade_extend.ExtendObj.Direction = thisObj.trade.trade_extend.ExtendObj.Direction == 0 ? 2 : thisObj.trade.trade_extend.ExtendObj.Direction; var direction = thisObj.trade.trade_extend.ExtendObj.Direction;
收支方向收支方向多空方向 标的代码浮动端平仓盈亏
@((SwapDirectionEnum)closeFloat.PayDirection)@((SwapDirectionEnum)closeFloat.PayDirection)@(closeFloat.PositionType == (int)PositionTypeFlag.Long ? "多头" : "空头") @closeFloat.UnderlyingCode