using YLErp.BLL; using YLErp.DBModels; using YLErp.DBModels.Consts; using YLErp.DBModels.Enums; namespace YLErp.Modules.TradeModule.DocGenerateModule { /// /// 国贸交易确认书编号生成器 /// 规则: /// - 对客交易(OpponentRole为"甲方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{标的代码}-{当日第N笔对客交易(数字递增)},从001开始 /// - 非对客交易(OpponentRole为"乙方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{标的代码}-{当日第N笔非对客交易(字母递增)},从A开始 /// public class GuolianContractNoGenerator { private static readonly object _syncLock = new object(); /// /// 生成国贸交易确认书编号 /// /// 数据库上下文 /// 交易记录 /// 客户代码 /// 确认书编号 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(); 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; } /// /// 将数字转换为字母序列(1=A, 2=B, 26=Z, 27=AA, 28=AB...) /// 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; } } }