feat(margin): 添加预付金模板簿记账户范围控制功能
- 在 margin_template_v2 实体中新增 BookIds 字段存储适用簿记账户ID列表 - 实现簿记账户ID的规范化、解析和范围重叠判断逻辑 - 在客户端和默认模板编辑页面添加适用簿记账户选择控件 - 修改预付金模板解析逻辑以考虑簿记账户适用性 - 更新交易绑定模板验证以检查簿记账户范围匹配 - 优化模板冲突检测算法以支持簿记账户范围重叠验证 - 添加簿记账户ID存在性校验防止无效引用 - 实现前端动态筛选适用当前资产的模板选项
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Globalization;
|
||||
using YLErp.Enums;
|
||||
|
||||
namespace YLErp.DBModels
|
||||
@@ -17,6 +18,109 @@ namespace YLErp.DBModels
|
||||
[DisplayName("模板名称")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 适用簿记账户ID列表,逗号分隔;为空表示适用全部簿记账户。
|
||||
/// </summary>
|
||||
[DisplayName("适用簿记账户组")]
|
||||
[Column("book_id")]
|
||||
public string BookIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 将簿记账户ID列表规范化为去空格、去重的逗号分隔字符串。
|
||||
/// </summary>
|
||||
public static string NormalizeBookIds(string bookIds)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(bookIds))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ids = new List<int>();
|
||||
foreach (var rawId in bookIds.Split(new[] { ',' }, StringSplitOptions.None))
|
||||
{
|
||||
var token = rawId.Trim();
|
||||
if (token.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("适用簿记账户组包含空账户ID。", nameof(bookIds));
|
||||
}
|
||||
if (!int.TryParse(token, NumberStyles.None, CultureInfo.InvariantCulture, out var id) || id <= 0)
|
||||
{
|
||||
throw new ArgumentException("适用簿记账户组ID必须为正整数:" + token, nameof(bookIds));
|
||||
}
|
||||
if (!ids.Contains(id))
|
||||
{
|
||||
ids.Add(id);
|
||||
}
|
||||
}
|
||||
|
||||
return ids.Count == 0 ? null : string.Join(",", ids);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析簿记账户ID列表。结果使用完整token,避免"1"误命中"11"。
|
||||
/// </summary>
|
||||
public static HashSet<string> ParseBookIds(string bookIds)
|
||||
{
|
||||
var ids = new HashSet<string>(StringComparer.Ordinal);
|
||||
if (string.IsNullOrWhiteSpace(bookIds))
|
||||
{
|
||||
return ids;
|
||||
}
|
||||
|
||||
foreach (var rawId in bookIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var token = rawId.Trim();
|
||||
if (int.TryParse(token, NumberStyles.None, CultureInfo.InvariantCulture, out var id) && id > 0)
|
||||
{
|
||||
ids.Add(id.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断模板是否适用于指定簿记账户;空范围表示全部。
|
||||
/// </summary>
|
||||
public bool IsApplicableToBook(int? bookId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(BookIds))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return bookId.HasValue && ParseBookIds(BookIds).Contains(bookId.Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断两个簿记账户范围是否重叠;任一空范围均视为全部。
|
||||
/// </summary>
|
||||
public static bool AreBookScopesOverlapping(string firstBookIds, string secondBookIds)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(firstBookIds) || string.IsNullOrWhiteSpace(secondBookIds))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var first = ParseBookIds(firstBookIds);
|
||||
var second = ParseBookIds(secondBookIds);
|
||||
return first.Count > 0 && second.Count > 0 && first.Overlaps(second);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 收集与新模板簿记账户范围重叠的所有模板适用结构。
|
||||
/// </summary>
|
||||
public static IEnumerable<string> GetOverlappingTradeTypes(IEnumerable<margin_template_v2> candidates, string bookIds)
|
||||
{
|
||||
if (candidates == null)
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
return candidates
|
||||
.Where(x => x != null && AreBookScopesOverlapping(x.BookIds, bookIds))
|
||||
.SelectMany(x => (x.TradeTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单腿/多腿
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user