diff --git a/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看多】-【债券ETF】-清洁版.docx b/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看多】-【债券ETF】-清洁版.docx index e99377d3..8719402e 100644 Binary files a/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看多】-【债券ETF】-清洁版.docx and b/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看多】-【债券ETF】-清洁版.docx differ diff --git a/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看多】-【现券】-清洁版.docx b/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看多】-【现券】-清洁版.docx index ff441d10..83c478c8 100644 Binary files a/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看多】-【现券】-清洁版.docx and b/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看多】-【现券】-清洁版.docx differ diff --git a/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看空】-【债券ETF】-清洁版.docx b/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看空】-【债券ETF】-清洁版.docx index 423071ed..e60e2ce2 100644 Binary files a/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看空】-【债券ETF】-清洁版.docx and b/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看空】-【债券ETF】-清洁版.docx differ diff --git a/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看空】-【现券】-清洁版.docx b/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看空】-【现券】-清洁版.docx index 048b9eb1..ed0f6197 100644 Binary files a/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看空】-【现券】-清洁版.docx and b/Plugins/YLErp.Plugins.GuoLian/App_Docs/contract_template/国联民生-收益互换交易确认书-境内模板-【客户看空】-【现券】-清洁版.docx differ diff --git a/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeConfirmationGenerator.cs b/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeConfirmationGenerator.cs index dc16cf57..34ae5a7a 100644 --- a/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeConfirmationGenerator.cs +++ b/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeConfirmationGenerator.cs @@ -124,7 +124,7 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator protected override string GetOutputFileName(string contractNo, string contractIndex) { var trade = Context.Trade; - var rule = $"{trade.TradeType}交易确认书_{contractNo}"; + var rule = $"【待用印】{trade.TradeType}交易确认书_{contractNo}"; return $"{rule}.{DocType.ToLower()}"; } @@ -152,9 +152,9 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator dic["乙方名称"] = client.Name; // 交易日期相关 - dic["成交日期"] = trade.TradeDate?.ToString("yyyy年M月d日"); - dic["开始日期"] = trade.StartDate?.ToString("yyyy年M月d日"); - dic["到期日期"] = trade.ExerciseDate?.ToString("yyyy年M月d日"); + dic["成交日期"] = trade.TradeDate?.ToString("【yyyy】年【M】月【d】日"); + dic["开始日期"] = trade.StartDate?.ToString("【yyyy】年【M】月【d】日"); + dic["到期日期"] = trade.ExerciseDate?.ToString("【yyyy】年【M】月【d】日"); // 根据交易类型填充不同数据 switch (trade.TradeType) @@ -222,8 +222,8 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator var bond = JsonHelper.Deserialize(underlying.ExJson) ?? new UnderlyingBond(); dic["参考标的发行人"] = bond.UnderlyingIssuer ?? ""; dic["参考标的担保人"] = ""; - dic["票面利率"] = ((double)(bond.CouponRate ?? 0) * 100).ToString("N4"); - dic["参考标的到期日"] = underlying.MaturityDate?.ToString("yyyy年M月d日") ?? ""; + dic["票面利率"] = ((double)(bond.CouponRate ?? 0)).ToString("0.00"); + dic["参考标的到期日"] = underlying.MaturityDate?.ToString("【yyyy】年【M】月【d】日") ?? ""; } // 从swap_position获取期初价格、保证金率等信息 @@ -235,7 +235,7 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator if (swapPosition != null) { // 期初全价和净价(转换为百分比格式) - dic["参考标的期初全价"] = ((double)swapPosition.PosiGrossPrice).ToString("N4"); + dic["参考标的期初全价"] = ((double)swapPosition.PosiGrossPrice).ToString("0.000"); dic["参考标的期初净价"] = ((double)(swapPosition.PosiNetNoFeePrice ?? 0m)).ToString("N4"); dic["参考标的期初全价%"] = ((double)swapPosition.PosiGrossPrice * 100).ToString("N4"); @@ -257,40 +257,43 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator dic["维持保障金率"] = ((double)clientMarginRate.maintain_rate * 100).ToString("N4"); // 期初预付比例和金额 - dic["期初预付比例"] = ((double)clientMarginRate.init_rate * 100).ToString("N4"); + dic["期初预付比例"] = ((double)clientMarginRate.init_rate * 100).ToString("0.##"); dic["期初预付金额"] = ((trade.OriginalStockEqvNotional ?? 0) * (double)clientMarginRate.init_rate).ToString("N2"); } else { dic["初始保障金率"] = "0.0000"; dic["维持保障金率"] = "0.0000"; - dic["期初预付比例"] = "0.0000"; + dic["期初预付比例"] = "0"; dic["期初预付金额"] = "0.00"; } bool posiLong = IsCustomerLong(swapPosition); // 计算平仓线、预警线、档位值(利率债TRS,固定4档) - var maintainRatePercent = (double)(clientMarginRate?.maintain_rate ?? 0) * 100; // 维持保证金率 A(%) + // A = 维持保证金率(%),B = 初始保证金率(%),diff = B - A + var maintainRatePercent = (double)(clientMarginRate?.maintain_rate ?? 0) * 100; // A(%) + var initRatePercent = (double)(clientMarginRate?.init_rate ?? 0) * 100; // B(%) + var diff = initRatePercent - maintainRatePercent; // B - A if (maintainRatePercent > 0) { if (posiLong) { - // 客户看多:档位n = 100 - n * A - dic["平仓线"] = (100 - 4 * maintainRatePercent).ToString("0.##"); - dic["预警线"] = (100 - 3 * maintainRatePercent).ToString("0.##"); - dic["档位1"] = (100 - 1 * maintainRatePercent).ToString("0.##"); - dic["档位2"] = (100 - 2 * maintainRatePercent).ToString("0.##"); - dic["档位3"] = (100 - 3 * maintainRatePercent).ToString("0.##"); - dic["档位4"] = (100 - 4 * maintainRatePercent).ToString("0.##"); + // 客户看多:档位n = 100 - n * (B-A) + dic["档位1"] = (100 - 1 * diff).ToString("0.##"); + dic["档位2"] = (100 - 2 * diff).ToString("0.##"); + dic["档位3"] = (100 - 3 * diff).ToString("0.##"); + dic["档位4"] = (100 - 4 * diff).ToString("0.##"); + dic["预警线"] = dic["档位4"]; // 预警线 = 最高档位 + dic["平仓线"] = (100 - 5 * diff).ToString("0.##"); // 平仓线 = 最高档位 - (B-A) } else { - // 客户看空:档位n = 100 + n * A - dic["平仓线"] = (100 + 4 * maintainRatePercent).ToString("0.##"); - dic["预警线"] = (100 + 3 * maintainRatePercent).ToString("0.##"); - dic["档位1"] = (100 + 1 * maintainRatePercent).ToString("0.##"); - dic["档位2"] = (100 + 2 * maintainRatePercent).ToString("0.##"); - dic["档位3"] = (100 + 3 * maintainRatePercent).ToString("0.##"); - dic["档位4"] = (100 + 4 * maintainRatePercent).ToString("0.##"); + // 客户看空:档位n = 100 + n * (B-A) + dic["档位1"] = (100 + 1 * diff).ToString("0.##"); + dic["档位2"] = (100 + 2 * diff).ToString("0.##"); + dic["档位3"] = (100 + 3 * diff).ToString("0.##"); + dic["档位4"] = (100 + 4 * diff).ToString("0.##"); + dic["预警线"] = dic["档位4"]; // 预警线 = 最高档位 + dic["平仓线"] = (100 + 5 * diff).ToString("0.##"); // 平仓线 = 最高档位 + (B-A) } } else @@ -303,6 +306,96 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator dic["档位4"] = ""; } + // 追保事件/返还追保事件 价格区间和金额比例 + if (maintainRatePercent > 0) + { + if (posiLong) + { + // === 客户看多 追保事件 === + // 区间0:当前净价 ≥ {100-(B-A)}% × 期初净价,追保0% + dic["追保区间0下限"] = (100 - 1 * diff).ToString("0.##"); + dic["追保金额比例0"] = "0"; + // 区间1:{100-2A}% ≤ 当前净价 < {100-A}%,追保{B-A}% + dic["追保区间1下限"] = (100 - 2 * maintainRatePercent).ToString("0.##"); + dic["追保区间1上限"] = (100 - 1 * maintainRatePercent).ToString("0.##"); + dic["追保金额比例1"] = (1 * diff).ToString("0.##"); + // 区间2:{100-3A}% ≤ 当前净价 < {100-2A}%,追保{2(B-A)}% + dic["追保区间2下限"] = (100 - 3 * maintainRatePercent).ToString("0.##"); + dic["追保区间2上限"] = (100 - 2 * maintainRatePercent).ToString("0.##"); + dic["追保金额比例2"] = (2 * diff).ToString("0.##"); + // 区间3:{100-4A}% ≤ 当前净价 < {100-3A}%,追保{3(B-A)}% + dic["追保区间3下限"] = (100 - 4 * maintainRatePercent).ToString("0.##"); + dic["追保区间3上限"] = (100 - 3 * maintainRatePercent).ToString("0.##"); + dic["追保金额比例3"] = (3 * diff).ToString("0.##"); + + // === 客户看多 返还追保事件 === + // 区间0:当前净价 ≥ {100-(B-A)}% × 期初净价,返还0% + dic["返还区间0下限"] = (100 - 1 * diff).ToString("0.##"); + dic["返还金额比例0"] = "0"; + // 区间1:{100-2(B-A)}% ≤ 当前净价 < {100-(B-A)}%,返还{B-A}% + dic["返还区间1下限"] = (100 - 2 * diff).ToString("0.##"); + dic["返还区间1上限"] = (100 - 1 * diff).ToString("0.##"); + dic["返还金额比例1"] = (1 * diff).ToString("0.##"); + // 区间2:{100-3(B-A)}% ≤ 当前净价 < {100-2(B-A)}%,返还{2(B-A)}% + dic["返还区间2下限"] = (100 - 3 * diff).ToString("0.##"); + dic["返还区间2上限"] = (100 - 2 * diff).ToString("0.##"); + dic["返还金额比例2"] = (2 * diff).ToString("0.##"); + // 区间3:{100-4(B-A)}% ≤ 当前净价 < {100-3(B-A)}%,返还{3(B-A)}% + dic["返还区间3下限"] = (100 - 4 * diff).ToString("0.##"); + dic["返还区间3上限"] = (100 - 3 * diff).ToString("0.##"); + dic["返还金额比例3"] = (3 * diff).ToString("0.##"); + } + else + { + // === 客户看空 追保事件 === + // 区间0:当前净价 ≤ {100+(B-A)}% × 期初净价,追保0% + dic["追保区间0上限"] = (100 + 1 * diff).ToString("0.##"); + dic["追保金额比例0"] = "0"; + // 区间1:{100+(B-A)}% < 当前净价 ≤ {100+2(B-A)}%,追保{B-A}% + dic["追保区间1下限"] = (100 + 1 * diff).ToString("0.##"); + dic["追保区间1上限"] = (100 + 2 * diff).ToString("0.##"); + dic["追保金额比例1"] = (1 * diff).ToString("0.##"); + // 区间2:{100+2(B-A)}% < 当前净价 ≤ {100+3(B-A)}%,追保{2(B-A)}% + dic["追保区间2下限"] = (100 + 2 * diff).ToString("0.##"); + dic["追保区间2上限"] = (100 + 3 * diff).ToString("0.##"); + dic["追保金额比例2"] = (2 * diff).ToString("0.##"); + // 区间3:{100+3(B-A)}% < 当前净价 ≤ {100+4(B-A)}%,追保{3(B-A)}% + dic["追保区间3下限"] = (100 + 3 * diff).ToString("0.##"); + dic["追保区间3上限"] = (100 + 4 * diff).ToString("0.##"); + dic["追保金额比例3"] = (3 * diff).ToString("0.##"); + + // === 客户看空 返还追保事件 === + // 区间0:当前净价 ≤ {100+(B-A)}% × 期初净价,返还0% + dic["返还区间0上限"] = (100 + 1 * diff).ToString("0.##"); + dic["返还金额比例0"] = "0"; + // 区间1:{100+(B-A)}% < 当前净价 ≤ {100+2(B-A)}%,返还{B-A}% + dic["返还区间1下限"] = (100 + 1 * diff).ToString("0.##"); + dic["返还区间1上限"] = (100 + 2 * diff).ToString("0.##"); + dic["返还金额比例1"] = (1 * diff).ToString("0.##"); + // 区间2:{100+2(B-A)}% < 当前净价 ≤ {100+3(B-A)}%,返还{2(B-A)}% + dic["返还区间2下限"] = (100 + 2 * diff).ToString("0.##"); + dic["返还区间2上限"] = (100 + 3 * diff).ToString("0.##"); + dic["返还金额比例2"] = (2 * diff).ToString("0.##"); + // 区间3:{100+3(B-A)}% < 当前净价 ≤ {100+4(B-A)}%,返还{3(B-A)}% + dic["返还区间3下限"] = (100 + 3 * diff).ToString("0.##"); + dic["返还区间3上限"] = (100 + 4 * diff).ToString("0.##"); + dic["返还金额比例3"] = (3 * diff).ToString("0.##"); + } + } + else + { + // 清空追保/返还相关字典值 + for (int i = 0; i <= 3; i++) + { + dic[$"追保区间{i}下限"] = ""; + dic[$"追保区间{i}上限"] = ""; + dic[$"追保金额比例{i}"] = ""; + dic[$"返还区间{i}下限"] = ""; + dic[$"返还区间{i}上限"] = ""; + dic[$"返还金额比例{i}"] = ""; + } + } + // 期初预付金利率(InterestMode == 初始预付金) var initialMarginPosition = swapPositions .Where(x => x.InterestMode == (int)InterestModeEnum.初始预付金) @@ -326,8 +419,8 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator dic["IsFixed"] = "□"; dic["IsFloat"] = "□"; - dic["期初观察日"] = trade.StartDate?.ToString("yyyy年M月d日") ?? ""; - dic["期末观察日"] = trade.ExerciseDate?.ToString("yyyy年M月d日") ?? ""; + dic["期初观察日"] = trade.StartDate?.ToString("【yyyy】年【M】月【d】日") ?? ""; + dic["期末观察日"] = trade.ExerciseDate?.ToString("【yyyy】年【M】月【d】日") ?? ""; if (interestMargin != null) { if (string.IsNullOrEmpty(interestMargin.FloatRateUnderlyingCode)) @@ -349,8 +442,8 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator { var firstInterval = interestMargin.SwapIntervalList.OrderBy(o=>o.Date).First(); var lastInterval = interestMargin.SwapIntervalList.OrderBy(o => o.Date).Last(); - dic["期初观察日"] = firstInterval.Date.ToString("yyyy年M月d日") ?? ""; - dic["期末观察日"] = lastInterval.Date.ToString("yyyy年M月d日") ?? ""; + dic["期初观察日"] = firstInterval.Date.ToString("【yyyy】年【M】月【d】日") ?? ""; + dic["期末观察日"] = lastInterval.Date.ToString("【yyyy】年【M】月【d】日") ?? ""; } } else @@ -364,7 +457,7 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator var notional = trade.OriginalStockEqvNotional ?? 0; var tradingFee = (double)swapPosition.PosiTradingFeePending; var basicFeeRate = notional == 0 ? 0 : tradingFee / notional * 100; - dic["基本费率"] = basicFeeRate.ToString("N4"); + dic["基本费率"] = basicFeeRate.ToString("0.##"); // 期初现金交换比例和金额(使用初始预付金数据) dic["期初现金交换比例"] = initialMarginPosition != null @@ -376,31 +469,31 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator } else { - dic["参考标的期初全价"] = "0.0000"; + dic["参考标的期初全价"] = "0.000"; dic["参考标的期初净价"] = "0.0000"; dic["初始保障金率"] = "0.0000"; dic["维持保障金率"] = "0.0000"; - dic["期初预付比例"] = "0.0000"; + dic["期初预付比例"] = "0"; dic["期初预付金额"] = "0.00"; dic["期初预付金利率"] = "0.0000"; dic["利率类型"] = "固定利率"; dic["固定利率"] = "0.0000"; dic["利差"] = ""; - dic["基本费率"] = "0.0000"; + dic["基本费率"] = "0"; dic["期初现金交换比例"] = "0.0000"; dic["期初现金交换金额"] = "0.00"; } // 参考标的券面总额(名义本金) - dic["参考标的券面总额"] = trade.OriginalStockEqvNotional?.ToString("N2") ?? "0.00"; + dic["参考标的券面总额"] = swapPosition != null ? ((double)swapPosition.PosiQuantity).ToString("N2") : "0"; // 参考标的证券全称和参考标的名义份额(复用上方已声明的bond) dic["参考标的证券全称"] = underlying != null ? (JsonHelper.Deserialize(underlying.ExJson)?.UnderlyingFullName ?? underlying.UnderlyingName) : ""; dic["参考标的名义份额"] = swapPosition != null - ? ((double)swapPosition.PosiQuantity).ToString("N2") - : "0.00"; + ? ((double)swapPosition.PosiQuantity).ToString("0.##") + : "0"; dic["参考标的基金管理人"] = ""; var contractTypeId = (Context.GetContractTypes().FirstOrDefault(O => O.ContactType == "交易确认书接收")?.id) ?? 0; // 乙方联系人信息 @@ -417,8 +510,8 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator ["标的代码"] = underlying?.UnderlyingCode ?? "", ["标的名称"] = underlying?.UnderlyingName ?? "", ["名义本金"] = trade.OriginalStockEqvNotional?.ToString("N2") ?? "0.00", - ["成交日期"] = trade.TradeDate?.ToString("yyyy年M月d日"), - ["到期日期"] = trade.ExerciseDate?.ToString("yyyy年M月d日") + ["成交日期"] = trade.TradeDate?.ToString("【yyyy】年【M】月【d】日"), + ["到期日期"] = trade.ExerciseDate?.ToString("【yyyy】年【M】月【d】日") }; table1.Add(row); dic["table1"] = table1; diff --git a/YLErpDAL/Modules/TradeModule/DocGenerateModule/GuolianContractNoGenerator.cs b/YLErpDAL/Modules/TradeModule/DocGenerateModule/GuolianContractNoGenerator.cs index 18e0312b..7c5b9dad 100644 --- a/YLErpDAL/Modules/TradeModule/DocGenerateModule/GuolianContractNoGenerator.cs +++ b/YLErpDAL/Modules/TradeModule/DocGenerateModule/GuolianContractNoGenerator.cs @@ -8,8 +8,10 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule /// /// 国贸交易确认书编号生成器 /// 规则: - /// - 对客交易(OpponentRole为"甲方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{标的代码}-{当日第N笔对客交易(数字递增)},从001开始 - /// - 非对客交易(OpponentRole为"乙方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{标的代码}-{当日第N笔非对客交易(字母递增)},从A开始 + /// - 对客交易(OpponentRole为"乙方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{当日第N笔对客交易(数字递增)}-{标的代码},从01开始 + /// 例:GLMS-IS-20260424-01-250210IB + /// - 非对客交易(OpponentRole为"甲方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{当日第N笔非对客交易使用字母递增}-{标的代码},从A开始 + /// 例:GLMS-IS-20260424-A-250210IB /// public class GuolianContractNoGenerator { @@ -27,12 +29,12 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule trade trade, string clientCode) { - // 根据trade的OpponentRole判断是否为对客交易 - var isClientTrade = trade.OpponentRole == "甲方"; - var underlyingCode = trade.UnderlyingCode ?? ""; + // 根据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}-{underlyingCode}-"; + var prefix = $"GLMS-{clientCode}-{tradeDateStr}-"; lock (_syncLock) { @@ -63,62 +65,65 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule 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) + if (string.IsNullOrEmpty(code) || code.Length <= prefixLen + 2) { continue; } - var suffix = code.Substring(prefixLen); - if (int.TryParse(suffix, out var n) && n > maxNo) + 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:D3}"; + var contractNo = $"{prefix}{nextNo:D2}-{underlyingCode}"; while (existingCodeSet.Contains(contractNo)) { nextNo++; - contractNo = $"{prefix}{nextNo:D3}"; + contractNo = $"{prefix}{nextNo:D2}-{underlyingCode}"; } return contractNo; } else { - var maxNo = 0; + // 非对客交易: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) + if (string.IsNullOrEmpty(code) || code.Length <= prefixLen + 2) { continue; } - var suffix = code.Substring(prefixLen); - if (!TryParseLettersToNumber(suffix, out var n)) + var rest = code.Substring(prefixLen); + var dashIdx = rest.IndexOf('-'); + if (dashIdx > 0) { - continue; - } - - if (n > maxNo) - { - maxNo = n; + var letterPart = rest.Substring(0, dashIdx); + if (TryParseLettersToNumber(letterPart, out var ln) && ln > maxLetter) + { + maxLetter = ln; + } } } - var nextNo = maxNo + 1; - var contractNo = $"{prefix}{NumberToLetter(nextNo)}"; + var nextLetter = maxLetter + 1; + var contractNo = $"{prefix}{NumberToLetter(nextLetter)}-{underlyingCode}"; while (existingCodeSet.Contains(contractNo)) { - nextNo++; - contractNo = $"{prefix}{NumberToLetter(nextNo)}"; + nextLetter++; + contractNo = $"{prefix}{NumberToLetter(nextLetter)}-{underlyingCode}"; } return contractNo; }