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

175 lines
6.1 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笔对客交易(数字递增)},从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;
}
}
}