#EQD-5843 国联民生-交易确认书编号规则, 客户编号规则, 以及确认书相关的一些调整:除了上传确认书

This commit is contained in:
吴方海
2026-05-21 10:57:14 +08:00
parent e3b11e7f5b
commit 1ca9cace72
8 changed files with 205 additions and 8 deletions
@@ -1347,6 +1347,9 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
return Trade.TradeNumber;
}
/// <summary>
/// 生成国贸确认书编号
/// </summary>
private string GenerateGuolianContractNo()
{
if (_contractType != ContractTypeEnum.Trade)
@@ -1355,13 +1358,11 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
}
if (Trade.TradeType == "收益互换")
{
var posi = GetSwapPositions(Trade.id, true).FirstOrDefault(p => p.PositionType > 0);
var isLong = posi?.PositionType == (int)PositionTypeFlag.Short ? false : true;
return "GLMS-" + _client.Number + "-" + Trade.TradeNumber;
return GuolianContractNoGenerator.Generate(DbContext, (trade)Trade, _client.Code);
}
return Trade.TradeNumber;
return Trade.TradeNumber;
}
/// <summary>
/// 生成国贸确认书编号
/// </summary>
@@ -0,0 +1,174 @@
using YLErp.BLL;
using YLErp.DBModels;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Enums;
namespace YLErp.Modules.TradeModule.DocGenerateModule
{
/// <summary>
/// 国贸交易确认书编号生成器
/// 规则:
/// - 对客交易(OpponentRole为"甲方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{标的代码}-{当日第N笔对客交易(数字递增)},从001开始
/// - 非对客交易(OpponentRole为"乙方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{标的代码}-{当日第N笔非对客交易(字母递增)},从A开始
/// </summary>
public class GuolianContractNoGenerator
{
private static readonly object _syncLock = new object();
/// <summary>
/// 生成国贸交易确认书编号
/// </summary>
/// <param name="dbContext">数据库上下文</param>
/// <param name="trade">交易记录</param>
/// <param name="clientCode">客户代码</param>
/// <returns>确认书编号</returns>
public static string Generate(
YLContext dbContext,
trade trade,
string clientCode)
{
// 根据trade的OpponentRole判断是否为对客交易
var isClientTrade = trade.OpponentRole == "甲方";
var underlyingCode = trade.UnderlyingCode ?? "";
var tradeDate = trade.TradeDate ?? DateTime.MinValue;
var tradeDateStr = tradeDate.ToString("yyyyMMdd");
var prefix = $"GLMS-{clientCode}-{tradeDateStr}-{underlyingCode}-";
lock (_syncLock)
{
var existingForTrade = dbContext.trade_contract_r
.Where(r => r.TradeId == trade.id && r.Type == ContractTypeEnum.Trade && r.IsValid)
.Select(r => r.ContractCode)
.FirstOrDefault();
if (!string.IsNullOrWhiteSpace(existingForTrade))
{
return existingForTrade;
}
var existingCodes = dbContext.trade_contract_r
.Where(d => d.ContractCode.StartsWith(prefix) && d.Type == ContractTypeEnum.Trade && d.IsValid)
.Select(d => d.ContractCode)
.ToList();
var existingCodeSet = new HashSet<string>();
for (var i = 0; i < existingCodes.Count; i++)
{
var code = existingCodes[i];
if (!string.IsNullOrWhiteSpace(code))
{
existingCodeSet.Add(code);
}
}
if (isClientTrade)
{
var maxNo = 0;
var prefixLen = prefix.Length;
for (var i = 0; i < existingCodes.Count; i++)
{
var code = existingCodes[i];
if (string.IsNullOrEmpty(code) || code.Length <= prefixLen)
{
continue;
}
var suffix = code.Substring(prefixLen);
if (int.TryParse(suffix, out var n) && n > maxNo)
{
maxNo = n;
}
}
var nextNo = maxNo + 1;
var contractNo = $"{prefix}{nextNo:D3}";
while (existingCodeSet.Contains(contractNo))
{
nextNo++;
contractNo = $"{prefix}{nextNo:D3}";
}
return contractNo;
}
else
{
var maxNo = 0;
var prefixLen = prefix.Length;
for (var i = 0; i < existingCodes.Count; i++)
{
var code = existingCodes[i];
if (string.IsNullOrEmpty(code) || code.Length <= prefixLen)
{
continue;
}
var suffix = code.Substring(prefixLen);
if (!TryParseLettersToNumber(suffix, out var n))
{
continue;
}
if (n > maxNo)
{
maxNo = n;
}
}
var nextNo = maxNo + 1;
var contractNo = $"{prefix}{NumberToLetter(nextNo)}";
while (existingCodeSet.Contains(contractNo))
{
nextNo++;
contractNo = $"{prefix}{NumberToLetter(nextNo)}";
}
return contractNo;
}
}
}
private static bool TryParseLettersToNumber(string letters, out int number)
{
number = 0;
if (string.IsNullOrEmpty(letters))
{
return false;
}
for (var i = 0; i < letters.Length; i++)
{
var c = letters[i];
if (c >= 'a' && c <= 'z')
{
c = (char)(c - 32);
}
else if (c < 'A' || c > 'Z')
{
number = 0;
return false;
}
number = (number * 26) + (c - 'A' + 1);
}
return true;
}
/// <summary>
/// 将数字转换为字母序列(1=A, 2=B, 26=Z, 27=AA, 28=AB...
/// </summary>
private static string NumberToLetter(int number)
{
if (number <= 0)
{
return "A";
}
string result = "";
while (number > 0)
{
number--; // 调整为从0开始
result = (char)('A' + (number % 26)) + result;
number /= 26;
}
return result;
}
}
}