Files
zszq-trs/YLErpDAL/Modules/TradeModule/DocGenerateModule/GuolianContractNoGenerator.cs
T

180 lines
6.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using YLErp.BLL;
using YLErp.DBModels;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Enums;
namespace YLErp.Modules.TradeModule.DocGenerateModule
{
/// <summary>
/// 国贸交易确认书编号生成器
/// 规则:
/// - 对客交易(OpponentRole为"乙方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{当日第N笔对客交易(数字递增)}-{标的代码},从01开始
/// 例:GLMS-IS-20260424-01-250210IB
/// - 非对客交易(OpponentRole为"甲方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{当日第N笔非对客交易使用字母递增}-{标的代码},从A开始
/// 例:GLMS-IS-20260424-A-250210IB
/// </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 ?? "").Replace(".", ""); // 去掉标的代码中的点号
var tradeDate = trade.TradeDate ?? DateTime.MinValue;
var tradeDateStr = tradeDate.ToString("yyyyMMdd");
var prefix = $"GLMS-{clientCode}-{tradeDateStr}-";
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)
{
// 对客交易:GLMS-{clientCode}-{date}-{counter:D2}-{underlyingCode}
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 + 2)
{
continue;
}
var counterStr = code.Substring(prefixLen, 2);
if (int.TryParse(counterStr, out var n) && n > maxNo)
{
maxNo = n;
}
}
var nextNo = maxNo + 1;
var contractNo = $"{prefix}{nextNo:D2}-{underlyingCode}";
while (existingCodeSet.Contains(contractNo))
{
nextNo++;
contractNo = $"{prefix}{nextNo:D2}-{underlyingCode}";
}
return contractNo;
}
else
{
// 非对客交易:GLMS-{clientCode}-{date}-{letter}-{underlyingCode}
// 找当日已有的非对客交易最大字母序号
var maxLetter = 0;
var prefixLen = prefix.Length;
for (var i = 0; i < existingCodes.Count; i++)
{
var code = existingCodes[i];
if (string.IsNullOrEmpty(code) || code.Length <= prefixLen + 2)
{
continue;
}
var rest = code.Substring(prefixLen);
var dashIdx = rest.IndexOf('-');
if (dashIdx > 0)
{
var letterPart = rest.Substring(0, dashIdx);
if (TryParseLettersToNumber(letterPart, out var ln) && ln > maxLetter)
{
maxLetter = ln;
}
}
}
var nextLetter = maxLetter + 1;
var contractNo = $"{prefix}{NumberToLetter(nextLetter)}-{underlyingCode}";
while (existingCodeSet.Contains(contractNo))
{
nextLetter++;
contractNo = $"{prefix}{NumberToLetter(nextLetter)}-{underlyingCode}";
}
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;
}
}
}