From 78751f0a57fe4da703e9a07e84c3c8a1541b8433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=90=8D=E9=94=90?= <1565842059@qq.com> Date: Wed, 1 Jul 2026 09:53:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(swap):=20=E5=AE=8C=E5=96=84=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E4=BA=92=E6=8D=A2=E8=B5=84=E9=87=91=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在SwapEodPositionService中添加clientCashIds列表追踪多笔资金记录 - 为UnwindData类新增ClientCashIds属性存储自动互换生成的资金记录ID集合 - 在SwapTradeBaseService中实现GetAutoSwapClientCashIds方法解析历史数据 - 添加GetLegacyAutoSwapClientCashRecords方法处理遗留资金记录删除逻辑 - 实现IsLegacyAutoSwapClientCashRecord方法精确匹配待删除资金记录 - 优化资金记录删除策略区分自动互换与手动操作产生的记录 --- Framework/YLErp.Core/DBModels/SwapEvent.cs | 5 + .../SwapModule/SwapEodPositionService.cs | 5 + .../SwapModule/SwapTradeBaseService.cs | 139 ++++++++++++++++-- 3 files changed, 135 insertions(+), 14 deletions(-) diff --git a/Framework/YLErp.Core/DBModels/SwapEvent.cs b/Framework/YLErp.Core/DBModels/SwapEvent.cs index 7baa00e5..ce7f1cc2 100644 --- a/Framework/YLErp.Core/DBModels/SwapEvent.cs +++ b/Framework/YLErp.Core/DBModels/SwapEvent.cs @@ -102,6 +102,7 @@ namespace YLErp.DBModels public UnwindData() { FlowEvents = new List(); + ClientCashIds = new List(); } public int SwapTradeId { get; set; } /// @@ -178,6 +179,10 @@ namespace YLErp.DBModels /// public decimal SwapDividendPnl { get; set; } /// + /// 自动互换生成的客户资金记录ID集合 + /// + public List ClientCashIds { get; set; } + /// /// 利息腿/浮动腿 集合,不序列化存储,只做查询 /// public List FlowEvents { get; set; } diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index fdd4136b..8c15c222 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -510,16 +510,19 @@ namespace YLErp.Modules.SwapModule var cashHappenDate = interval?.SettlementDate ?? unwindData.ValueDate; int clientCashId = 0; + var clientCashIds = new List(); // 利息腿:插入资金记录(使用系统操作_互换) if (unwindData.SwapCloseAmount != 0) { clientCashId = AddClientCashInCashOut(td, Convert.ToDouble(-unwindData.SwapCloseAmount), ClientCashInCashOut.系统操作_互换, cashHappenDate); + clientCashIds.Add(clientCashId); } // 预付金腿:单独插入一条资金记录(系统操作_预付金返息) if (unwindData.SwapMarginRebatePnl != 0) { clientCashId = AddClientCashInCashOut(td, Convert.ToDouble(-unwindData.SwapMarginRebatePnl), ClientCashInCashOut.系统操作_预付金返息, unwindData.ValueDate); + clientCashIds.Add(clientCashId); } unwindData.SwapCloseAmount = unwindData.SwapRealizedPnL;//需要算上预付金利息 和 分红; 只是不算预付金返还 // 分红:使用派息支付日偏移记录资金记录 @@ -529,8 +532,10 @@ namespace YLErp.Modules.SwapModule ? dividendEvents.First().PayDate.Value : unwindData.ValueDate; clientCashId = AddClientCashInCashOut(td, Convert.ToDouble(-unwindData.SwapDividendPnl), ClientCashInCashOut.系统操作_互换, dividendPayDate); + clientCashIds.Add(clientCashId); } + unwindData.ClientCashIds = clientCashIds; string data = JsonConvert.SerializeObject(unwindData); var swapEvent = new SwapEventService(this).AddSwapEventDate(unwindData.ValueDate, unwindData.SwapTradeId, (int)SwapEventTypeEnum.自动互换, data, clientCashId, true, "系统操作-自动互换");//将互换总额存入事件 if (flowEvents!=null) diff --git a/YLErpDAL/Modules/SwapModule/SwapTradeBaseService.cs b/YLErpDAL/Modules/SwapModule/SwapTradeBaseService.cs index 0fe0981a..80a4a0a4 100644 --- a/YLErpDAL/Modules/SwapModule/SwapTradeBaseService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapTradeBaseService.cs @@ -384,28 +384,40 @@ namespace YLErp.Modules.SwapModule DbContext.swap_flow_event.RemoveRange(swapFlowEvents); // 删除自动互换产生的资金记录(client_cash_in_out) - var swapEventIds = swapEvents.Select(s => s.id).ToList(); - if (swapEventIds.Any()) + var autoSwapEvents = swapEvents.ToList(); + if (autoSwapEvents.Any()) { // 通过 swap_event 的 ClientCashId 删除对应的资金记录(利息腿) - var clientCashIds = swapEvents.Where(s => s.ClientCashId > 0).Select(s => s.ClientCashId).ToList(); + var clientCashIds = autoSwapEvents + .Where(s => s.ClientCashId > 0) + .Select(s => s.ClientCashId) + .ToList(); + + var legacyAutoEvents = new List(); + foreach (var swapEvent in autoSwapEvents) + { + var eventCashIds = GetAutoSwapClientCashIds(swapEvent); + if (eventCashIds.Any()) + { + clientCashIds.AddRange(eventCashIds); + } + else + { + legacyAutoEvents.Add(swapEvent); + } + } + + clientCashIds = clientCashIds.Distinct().ToList(); if (clientCashIds.Any()) { var clientCashRecords = DbContext.ClientCashInCashOut.Where(x => clientCashIds.Contains(x.id)).ToList(); DbContext.ClientCashInCashOut.RemoveRange(clientCashRecords); } - - // 删除预付金腿的资金记录(通过交易ID、日期和Action类型查找,一次性查询避免MySQL连接重用问题) - var swapTradeIds = swapEvents.Select(s => s.SwapTradeId).Distinct().ToList(); - var actions = new List() { ClientCashInCashOut.系统操作_预付金返息, ClientCashInCashOut.系统操作_互换 }; - var premiumCashRecords = DbContext.ClientCashInCashOut - .Where(x => swapTradeIds.Contains(x.TradeId ?? 0) - && x.HappenDate>=valueDate - && actions.Contains(x.Action)) - .ToList(); - if (premiumCashRecords.Any()) + + var legacyCashRecords = GetLegacyAutoSwapClientCashRecords(legacyAutoEvents, clientCashIds); + if (legacyCashRecords.Any()) { - DbContext.ClientCashInCashOut.RemoveRange(premiumCashRecords); + DbContext.ClientCashInCashOut.RemoveRange(legacyCashRecords); } } } @@ -413,6 +425,105 @@ namespace YLErp.Modules.SwapModule DbContext.eod_swap.RemoveRange(eodSwaps); DbContext.SaveChanges(); } + + private List GetAutoSwapClientCashIds(swap_event swapEvent) + { + if (swapEvent == null || string.IsNullOrWhiteSpace(swapEvent.EventData)) + { + return new List(); + } + + try + { + var unwindData = JsonConvert.DeserializeObject(swapEvent.EventData); + return unwindData?.ClientCashIds?.Where(x => x > 0).Distinct().ToList() ?? new List(); + } + catch + { + return new List(); + } + } + + private List GetLegacyAutoSwapClientCashRecords(List swapEvents, List excludedClientCashIds) + { + if (swapEvents == null || !swapEvents.Any()) + { + return new List(); + } + + var eventIds = swapEvents.Select(x => x.id).ToList(); + var flowEvents = DbContext.swap_flow_event + .Where(x => x.EventId.HasValue && eventIds.Contains(x.EventId.Value)) + .ToList(); + var manualClientCashIds = DbContext.swap_event + .Where(x => x.SwapTradeId == swapEvents.First().SwapTradeId + && x.ClientCashId > 0 + && x.EventType != (int)SwapEventTypeEnum.自动互换) + .Select(x => x.ClientCashId) + .ToList(); + var records = new List(); + + foreach (var swapEvent in swapEvents) + { + UnwindData unwindData = null; + if (!string.IsNullOrWhiteSpace(swapEvent.EventData)) + { + try + { + unwindData = JsonConvert.DeserializeObject(swapEvent.EventData); + } + catch + { + } + } + + var eventFlowEvents = flowEvents.Where(x => x.EventId == swapEvent.id).ToList(); + var candidateDates = new HashSet { swapEvent.ValueDate.Date }; + if (unwindData?.PayDate != null) + { + candidateDates.Add(unwindData.PayDate.Value.Date); + } + eventFlowEvents.Where(x => x.PayDate.HasValue).ToList().ForEach(x => candidateDates.Add(x.PayDate.Value.Date)); + + var eventRecords = DbContext.ClientCashInCashOut + .Where(x => x.TradeId == swapEvent.SwapTradeId + && !excludedClientCashIds.Contains(x.id) + && !manualClientCashIds.Contains(x.id) + && (x.Action == ClientCashInCashOut.系统操作_预付金返息 || x.Action == ClientCashInCashOut.系统操作_互换)) + .ToList() + .Where(x => x.HappenDate.HasValue && candidateDates.Contains(x.HappenDate.Value.Date)) + .Where(x => IsLegacyAutoSwapClientCashRecord(x, unwindData)) + .ToList(); + + records.AddRange(eventRecords); + } + + return records.GroupBy(x => x.id).Select(x => x.First()).ToList(); + } + + private bool IsLegacyAutoSwapClientCashRecord(ClientCashInCashOut cashRecord, UnwindData unwindData) + { + if (unwindData == null) + { + return true; + } + + var amount = Convert.ToDecimal(cashRecord.Money ?? 0); + if (cashRecord.Action == ClientCashInCashOut.系统操作_预付金返息) + { + return unwindData.SwapMarginRebatePnl != 0 + && amount == -unwindData.SwapMarginRebatePnl; + } + + if (cashRecord.Action == ClientCashInCashOut.系统操作_互换) + { + return (unwindData.SwapCloseAmount != 0 && amount == -unwindData.SwapCloseAmount) + || (unwindData.SwapDividendPnl != 0 && amount == -unwindData.SwapDividendPnl) + || (unwindData.SwapRealizedPnL != 0 && amount == -unwindData.SwapRealizedPnL); + } + + return false; + } /// /// 获取上一交易日 ///