feat(margin): 添加预付金模板簿记账户范围控制功能

- 在 margin_template_v2 实体中新增 BookIds 字段存储适用簿记账户ID列表
- 实现簿记账户ID的规范化、解析和范围重叠判断逻辑
- 在客户端和默认模板编辑页面添加适用簿记账户选择控件
- 修改预付金模板解析逻辑以考虑簿记账户适用性
- 更新交易绑定模板验证以检查簿记账户范围匹配
- 优化模板冲突检测算法以支持簿记账户范围重叠验证
- 添加簿记账户ID存在性校验防止无效引用
- 实现前端动态筛选适用当前资产的模板选项
This commit is contained in:
张名锐
2026-08-27 19:38:10 +08:00
parent c843012cdc
commit 134e07c628
13 changed files with 415 additions and 100 deletions
+62 -19
View File
@@ -1,4 +1,4 @@
using BaseOUDAL;
using BaseOUDAL;
using ClosedXML.Report.Options;
using Confluent.Kafka;
using CsvHelper;
@@ -118,6 +118,12 @@ namespace YLErp.Modules.SwapModule
try
{
var isAddNew = req.id == 0;
var originalMarginTemplateName = isAddNew
? null
: DbContext.trade
.Where(x => x.id == req.id)
.Select(x => x.MarginTemplateName)
.FirstOrDefault();
dbTrade = isAddNew ? InnerSaveNewTrade(req, tradeNumberGenerated) : InnerSaveEditTrade(req, out var changeConfirmStatus);
if (req.SalesCommission != null)
{
@@ -139,7 +145,7 @@ namespace YLErp.Modules.SwapModule
}
}
//保证金模板V2迁移:按交易页选择的保证金模板(MarginTemplateName 存模板V2名称)维护交易模板绑定
SyncTradeMarginTemplate(dbTrade);
SyncTradeMarginTemplate(dbTrade, originalMarginTemplateName, isAddNew);
trans.Commit();
}
finally
@@ -151,35 +157,72 @@ namespace YLErp.Modules.SwapModule
}
/// <summary>
/// 保证金模板V2迁移:按交易上选择的保证金模板(MarginTemplateName 存预付金模板V2的名称)维护 trade_margin_template 绑定。
/// 未选择或名称匹配不到有效自定义模板时仅清除旧绑定,不新增(保持无预付金占用的现状)。
/// 未选择或存量交易原样保留的历史名称仅清除旧绑定,不新增(保持无预付金占用的现状)。
/// </summary>
private void SyncTradeMarginTemplate(trade dbTrade)
private void SyncTradeMarginTemplate(trade dbTrade, string originalMarginTemplateName, bool isNewTrade)
{
var olds = DbContext.trade_margin_template.Where(x => x.TradeId == dbTrade.id).ToList();
DbContext.trade_margin_template.RemoveRange(olds);
margin_template_v2 template = null;
if (!string.IsNullOrWhiteSpace(dbTrade.MarginTemplateName))
{
var allTemplatesByName = DbContext.margin_template_v2
.Where(x => x.Name == dbTrade.MarginTemplateName)
.ToList();
var hasV2TemplateWithName = allTemplatesByName.Any();
//匹配自定义+全局默认模板(重名时优先自定义),模板"适用结构"需包含 收益互换
var template = DbContext.margin_template_v2
.Where(x => x.Name == dbTrade.MarginTemplateName && !x.IsForClient && x.IsValid && x.TradeTypes.Contains("收益互换"))
var templatesByName = allTemplatesByName
.Where(x => !x.IsForClient && x.IsValid && (x.TradeTypes ?? string.Empty).Contains("收益互换"))
.OrderBy(x => x.IsDefault)
.FirstOrDefault();
if (template != null)
.ToList();
template = templatesByName.FirstOrDefault(x => x.IsApplicableToBook(dbTrade.AssetId));
if (template == null)
{
DbContext.trade_margin_template.Add(new trade_margin_template()
//存量交易未修改的非V2历史名称只保留在 trade.MarginTemplateName,不创建模板绑定。
if (!CanKeepLegacyMarginTemplateName(
isNewTrade,
originalMarginTemplateName,
dbTrade.MarginTemplateName,
hasV2TemplateWithName))
{
TradeId = dbTrade.id,
ValueDate = new DateTime(2000, 1, 1),
MarginTemplateId = template.id,
IsLatest = true,
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now
});
throw new ServiceException(templatesByName.Any()
? $"所选预付金模板不适用当前簿记账户:{dbTrade.MarginTemplateName}"
: $"所选预付金模板不存在或已失效:{dbTrade.MarginTemplateName}");
}
}
}
var olds = DbContext.trade_margin_template.Where(x => x.TradeId == dbTrade.id).ToList();
DbContext.trade_margin_template.RemoveRange(olds);
if (template != null)
{
DbContext.trade_margin_template.Add(new trade_margin_template()
{
TradeId = dbTrade.id,
ValueDate = new DateTime(2000, 1, 1),
MarginTemplateId = template.id,
IsLatest = true,
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now
});
}
DbContext.SaveChanges();
}
/// <summary>
/// 判断是否允许存量交易原样保留未迁移的历史保证金模板名称。
/// </summary>
internal static bool CanKeepLegacyMarginTemplateName(
bool isNewTrade,
string originalName,
string currentName,
bool currentNameIsV2Template)
{
return !isNewTrade
&& !currentNameIsV2Template
&& !string.IsNullOrWhiteSpace(originalName)
&& !string.IsNullOrWhiteSpace(currentName)
&& string.Equals(originalName, currentName, StringComparison.Ordinal);
}
/// <summary>
/// 单标的生成开仓事件
/// </summary>