using YLErp.BLL; using YLErp.DBModels; using YLErp.Enums; using YLErp.Modules.MarginModule; namespace YLErp.Modules.CalcModules { /// /// R1 模板三层级找到即停回退集成测试(连 dev 库,MarginTemplateV2RateHelper.ResolveTieredTemplate/GetTradeMarginRate): /// 交易绑定(自定义)→ 客户默认(client_margin_template 按客户)→ 全局默认(IsDefault&&!IsForClient)。 /// 测试数据全部带 "ZZZ-R1回退测试-" 名称前缀,TestInitialize/TestCleanup 双向清理,不触碰真实交易。 /// [TestClass] public class MarginTemplateV2RateHelperFallbackTest { private const string Marker = "ZZZ-R1回退测试-"; private const int SentinelTradeId = 1900000001; private const int SentinelTradeId2 = 1900000002; private DateTime EffectiveDate = new DateTime(2000, 1, 1); private YLContext db; private int clientId; [TestInitialize] public void Init() { db = new YLContext(); Cleanup(); //取一个真实客户做客户级绑定(只写 client_margin_template,不动客户数据) using (var clientDb = DbContextFactory.GetClientDbContext(OptUserInfo.SystemUser)) { clientId = clientDb.client.Where(c => c.id > 0).OrderBy(c => c.id).Select(c => c.id).First(); } } [TestCleanup] public void CleanupFixture() { Cleanup(); db.Dispose(); } private void Cleanup() { var templateIds = db.margin_template_v2.Where(x => x.Name.StartsWith(Marker)).Select(x => x.id).ToList(); if (templateIds.Count > 0) { db.margin_template_detail.RemoveRange(db.margin_template_detail.Where(x => templateIds.Contains(x.MarginTemplateId))); db.trade_margin_template.RemoveRange(db.trade_margin_template.Where(x => templateIds.Contains(x.MarginTemplateId))); db.client_margin_template.RemoveRange(db.client_margin_template.Where(x => templateIds.Contains(x.MarginTemplateId))); db.margin_template_v2.RemoveRange(db.margin_template_v2.Where(x => templateIds.Contains(x.id))); db.SaveChanges(); } db.trade_margin_template.RemoveRange(db.trade_margin_template.Where(x => x.TradeId == SentinelTradeId || x.TradeId == SentinelTradeId2)); db.SaveChanges(); } private margin_template_v2 AddTemplate(string name, bool isDefault, bool isForClient, string tradeTypes = "收益互换", bool isValid = true, int ruleType = (int)MarginRuleTypeEnum.区间追保结构) { var t = new margin_template_v2 { Name = name, IsDefault = isDefault, IsForClient = isForClient, IsValid = isValid, TradeTypes = tradeTypes, RuleType = ruleType, ValueDate = EffectiveDate }; db.margin_template_v2.Add(t); db.SaveChanges(); return t; } [TestMethod] public void TF_001_交易绑定优先_压过客户与全局() { var custom = AddTemplate(Marker + "自定义", isDefault: false, isForClient: false); var clientTpl = AddTemplate(Marker + "客户", isDefault: true, isForClient: true); var globalTpl = AddTemplate(Marker + "全局", isDefault: true, isForClient: false); db.trade_margin_template.Add(new trade_margin_template { TradeId = SentinelTradeId, MarginTemplateId = custom.id, ValueDate = EffectiveDate, IsLatest = true }); db.client_margin_template.Add(new client_margin_template { ClientId = clientId, MarginTemplateId = clientTpl.id, ValueDate = EffectiveDate, ClientLevel = "" }); db.SaveChanges(); var resolved = MarginTemplateV2RateHelper.ResolveTieredTemplate(SentinelTradeId, clientId, DateTime.Today, db); Assert.IsNotNull(resolved); Assert.AreEqual(custom.id, resolved.id, "交易绑定(自定义)应找到即停,压过客户与全局默认"); } [TestMethod] public void TF_002_无交易绑定_落到客户默认() { var clientTpl = AddTemplate(Marker + "客户", isDefault: true, isForClient: true); var globalTpl = AddTemplate(Marker + "全局", isDefault: true, isForClient: false); db.client_margin_template.Add(new client_margin_template { ClientId = clientId, MarginTemplateId = clientTpl.id, ValueDate = EffectiveDate, ClientLevel = "" }); db.SaveChanges(); var resolved = MarginTemplateV2RateHelper.ResolveTieredTemplate(tradeId: null, clientId, DateTime.Today, db); Assert.IsNotNull(resolved); Assert.AreEqual(clientTpl.id, resolved.id, "无交易绑定时应命中客户默认,压过全局默认"); } [TestMethod] public void TF_003_无交易无客户绑定_落到全局默认() { var globalTpl = AddTemplate(Marker + "全局", isDefault: true, isForClient: false); AddTemplate(Marker + "客户", isDefault: true, isForClient: true); //未绑定不应被取到 var resolved = MarginTemplateV2RateHelper.ResolveTieredTemplate(tradeId: null, clientId, DateTime.Today, db); AssertGlobal(resolved, globalTpl); } [TestMethod] public void TF_004_客户绑定指向非互换模板_跳过落全局() { var globalTpl = AddTemplate(Marker + "全局", isDefault: true, isForClient: false); var optionTpl = AddTemplate(Marker + "期权客户模板", isDefault: true, isForClient: true, tradeTypes: "香草期权"); db.client_margin_template.Add(new client_margin_template { ClientId = clientId, MarginTemplateId = optionTpl.id, ValueDate = EffectiveDate, ClientLevel = "" }); db.SaveChanges(); var resolved = MarginTemplateV2RateHelper.ResolveTieredTemplate(tradeId: null, clientId, DateTime.Today, db); AssertGlobal(resolved, globalTpl); } /// /// 同日并存"互换绑定+期权绑定"(页面互斥只挡适用结构重叠,此组合允许保存): /// 应命中互换绑定,不因先取到期权绑定被过滤而误穿透到全局。 /// [TestMethod] public void TF_007_同日并存互换与期权绑定_命中间换绑定() { var swapTpl = AddTemplate(Marker + "客户", isDefault: true, isForClient: true); var optionTpl = AddTemplate(Marker + "期权客户模板", isDefault: true, isForClient: true, tradeTypes: "香草期权"); var globalTpl = AddTemplate(Marker + "全局", isDefault: true, isForClient: false); db.client_margin_template.Add(new client_margin_template { ClientId = clientId, MarginTemplateId = swapTpl.id, ValueDate = EffectiveDate, ClientLevel = "" }); db.client_margin_template.Add(new client_margin_template { ClientId = clientId, MarginTemplateId = optionTpl.id, ValueDate = EffectiveDate, ClientLevel = "" }); db.SaveChanges(); var resolved = MarginTemplateV2RateHelper.ResolveTieredTemplate(tradeId: null, clientId, DateTime.Today, db); Assert.IsNotNull(resolved); Assert.AreEqual(swapTpl.id, resolved.id, "同日期权+互换绑定并存时应命中互换绑定(过滤后再取最新),而非穿透全局"); } [TestMethod] public void TF_005_绑定模板已失效_找到即停返回null() { var invalidTpl = AddTemplate(Marker + "已失效", isDefault: false, isForClient: false, isValid: false); var globalTpl = AddTemplate(Marker + "全局", isDefault: true, isForClient: false); db.trade_margin_template.Add(new trade_margin_template { TradeId = SentinelTradeId2, MarginTemplateId = invalidTpl.id, ValueDate = EffectiveDate, IsLatest = true }); db.SaveChanges(); var resolved = MarginTemplateV2RateHelper.ResolveTieredTemplate(SentinelTradeId2, clientId, DateTime.Today, db); Assert.IsNull(resolved, "交易绑定指向已失效模板时应找到即停(不向下回退到全局默认)"); } /// /// 端到端:交易绑定(区间追保结构 + 明细 x/y)经 GetTradeMarginRate 完整取到率—— /// 兼容回归交易级取数路径在新回退结构下行为不变。 /// [TestMethod] public void TF_006_交易绑定端到端取率() { var custom = AddTemplate(Marker + "自定义", isDefault: false, isForClient: false); db.margin_template_detail.Add(new margin_template_detail { MarginTemplateId = custom.id, ValueDate = EffectiveDate, UnderlyingType = UnderlyingTypeEnum.None, MarginRatio1 = 0.05, MarginRatio2 = 0.03 }); db.trade_margin_template.Add(new trade_margin_template { TradeId = SentinelTradeId, MarginTemplateId = custom.id, ValueDate = EffectiveDate, IsLatest = true }); db.SaveChanges(); var rate = MarginTemplateV2RateHelper.GetTradeMarginRate(SentinelTradeId, "240004.IB", "TBonds", DateTime.Today, db); Assert.IsNotNull(rate); Assert.AreEqual(custom.id, rate.Template.id); Assert.AreEqual(0.05m, rate.InitRate.Value); Assert.AreEqual(0.03m, rate.MaintainRate.Value); } private void AssertGlobal(margin_template_v2 resolved, margin_template_v2 expected) { Assert.IsNotNull(resolved); if (resolved.Name.StartsWith(Marker)) { Assert.AreEqual(expected.id, resolved.id, "应命中本用例创建的全局默认模板"); } //dev 库存在其他真实全局默认模板时,按 ValueDate 最新者胜出,不做更严格断言 } } }