using BaseOUDAL; using System.Data; using System.Text.RegularExpressions; using YLErp.BLL; using YLErp.DBModels.Consts; using YLErp.DBModels.Enums; using YLErp.Modules.EodModule; using YLErp.Modules.SuperviseReportModule.SAC.Common; using YLErp.Modules.SuperviseReportModule.SAC.Model; using static YLErp.DBModels.Consts.ConsReport; namespace YLErp.Modules.SuperviseReportModule.SAC.Service { class ReportOptionConfirmationService : ReportBaseService { public ReportOptionConfirmationService(OptUserInfo optUser) : base(optUser) { } protected override string _excelDataSourcePath => "交易相关\\"; protected override string _excelDataSourceFileName => "import_OptionConfirmation_template.xlsx"; protected override DataFlagsEnum BusiDataType => DataFlagsEnum.A1004; private List _validOperationType = null; public override List ValidOperationType { get { if (_validOperationType == null) { _validOperationType = new List() { OptFlagsEnum.A, OptFlagsEnum.U, OptFlagsEnum.D, }; } return _validOperationType; } } protected override SuperviseReportTypeEnum ReportType => SuperviseReportTypeEnum.SAC_OptionConfirmation; List noteList = new List(); protected override BodyModel GenerateBody(out bool noData, out List fileList) { fileList = new List(); noData = true; BodyModel model = new BodyModel(); LogFactory.GetLogger("loadSubsystemDataSource").Error($"x1:"); var cacheKey = $"{BusiDataType}"; List dataList = new List(); if ((PS.Config.ErpElement.SAC_ReportDataSource & SAC_ReportDataSourceEnum.Template) == SAC_ReportDataSourceEnum.Template) { dataList = GetOptionConfirmationModelFromExcel(ref fileList); } LogFactory.GetLogger("loadSubsystemDataSource").Error($"x2:"); if ((PS.Config.ErpElement.SAC_ReportDataSource & SAC_ReportDataSourceEnum.System) == SAC_ReportDataSourceEnum.System) { var nextDate = _reqInfo.ReportDate.AddDays(1); var nextDataDate = _reqInfo.DataDate.AddDays(1); using (var db = new YLContext()) { var codeList = ReportStatus.GetCacheInfo(cacheKey); var query = (from t in db.trade join tc in db.trade_cash on t.id equals tc.TradeId join tr in db.trade_contract_r on tc.id equals tr.TradeCashId join td in db.trade_contract_document on tr.ContractCode equals td.Code where ((_operationType == OptFlagsEnum.A && t.TradeDate >= _reqInfo.DataDate && t.TradeDate < nextDataDate)//新增时使用交易日期判断 || (_operationType != OptFlagsEnum.A && tc.OptDate >= _reqInfo.ReportDate && tc.OptDate < nextDate))//补正和废止时使用操作日期判断 && (_operationType == OptFlagsEnum.D || (t.ValidState != "InValid" && tc.ValidState != "InValid" && !tc.IsDeleted && tr.IsValid)) && /*t.UnderlyingInstrumentType == "Stock" &&*/ t.TradeType != "收益互换" && tc.Action == "系统操作-期权费" && t.ParentTradeId == 0 select new { tcId = tc.id, tc.OptDate, tradeValid = t.ValidState != "InValid", tradecashValid = tc.ValidState != "InValid" && !tc.IsDeleted, tradeContractRValid = tr.IsValid, t.id, t.ClientId, t.TradeDate, t.ExerciseDate, t.SettlementDate, t.ExerciseMode, t.BuySell, TradeType = t.StructureType ?? t.TradeType, t.OptionType, t.OriginalStockEqvNotional, t.StockEqvNotionalReal, t.OriginalNotional, t.IsMoneynessOption, t.SpotPrice, t.Strike, t.MarginTemplateName, t.MarginType, t.InitialMargin, t.UnderlyingCode, t.AnnualizeFactor, tr.ContractCode, td.Paths, td.StampDocumentFileName, t.TradePrice, t.PremiumRate, t.QuoteCurrency, t.SettlementCurrency }).OrderBy(O => O.OptDate).ToArray().Where(O => !codeList.Contains(O.id + "")).ToArray(); List ids = query.Select(O => O.id).ToList(); List delIds = new List(); if (_operationType == OptFlagsEnum.D) { delIds = DbContext.TradeAuditLog.Where(O => ids.Contains(O.TradeId) && O.OptDate >= _reqInfo.ReportDate && O.OptDate < nextDate && O.OptType == "删除交易").Select(O => O.TradeId).ToList(); } Dictionary> metaDic = DbContext.TradeMeta.Where(O => ids.Contains(O.TradeId)).AsEnumerable().GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.ToDictionary(K1 => K1.MetaKey, V1 => V1.MetaValue)); Dictionary reportDescDic = DbContext.AppConfig.Where(O => O.PGroup == ConsAppConfig.ReportDescOption).ToDictionary(K => K.PName, V => V.PValue); foreach (var item in query.ToArray()) { var cacheValue = item.id.ToString(); if (ReportStatus.CheckCacheInfo(cacheKey, cacheValue)) { continue; } //如果存在重复数据,则始终用较新的数据 OptionConfirmationModel info = new OptionConfirmationModel(); info.TradeId = item.id.ToString(); info.ConfirmationNo = item.ContractCode; SACReportNotes note = base.GetReportNotes(ReportType, formatInfoTag(info)).FirstOrDefault(); if (note == null && _operationType == OptFlagsEnum.A) { info.OperationType = OptFlagsEnum.A; note = new SACReportNotes() { IsValid = true, }; } else { if (note == null) { continue; } switch (_operationType) { case OptFlagsEnum.A: continue;//新增数据已报送,跳过 case OptFlagsEnum.U: if (!note.changeStatus) { continue;//交易没有被修改过,跳过 } info.OperationType = OptFlagsEnum.U; note.IsValid = true; break; case OptFlagsEnum.D: if (!delIds.Contains(item.id)) { continue;//交易没有被删除,跳过 } info.OperationType = OptFlagsEnum.D; note.IsValid = false; break; case OptFlagsEnum.NONE: default: throw new ServiceException("未知操作类型"); } } if (info.OperationType != _operationType) { continue; } if (info.OperationType != OptFlagsEnum.D && (!item.tradeValid || !item.tradecashValid || !item.tradeContractRValid)) {//非废止报送中,应跳过所有存在无效数据的数据 continue; } if (metaDic.ContainsKey(item.id)) { var metaInfo = metaDic[item.id]; info.MasterAgrmtNo = metaInfo.ContainsKey(ConsTradeMetaKey.MainProtocolCode) ? metaInfo[ConsTradeMetaKey.MainProtocolCode] : ""; info.SupAgrmtNo = metaInfo.ContainsKey(ConsTradeMetaKey.SupProtocolCode) ? metaInfo[ConsTradeMetaKey.SupProtocolCode] : ""; info.ClearingAgency = metaInfo.ContainsKey(ConsTradeMetaKey.ClearingAgency) ? ClearingAgencyMap[metaInfo[ConsTradeMetaKey.ClearingAgency]] : ""; info.TradingPlace = metaInfo.ContainsKey(ConsTradeMetaKey.TradingPlace) ? TradingPlaceMap[metaInfo[ConsTradeMetaKey.TradingPlace]] : ""; if (info.TradingPlace == "1")//跳过交易场所为报价系统的交易; { continue; } } var rate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(item.QuoteCurrency, "CNY", _reqInfo.DataDate); if (info.OperationType != OptFlagsEnum.A) { info.ConfirmationID = note.BizId;//确认书编号; } info.ConfirmationType = ReportTypeMap[info.OperationType == OptFlagsEnum.A ? "首次" : "变更"]; info.FillParty = FillPartyMap["甲方"]; info.OptionSeller = item.BuySell == "卖出" ? OptionTraderMap["填报方"] : OptionTraderMap["对手方"]; info.OptionDirection = OptionDirectionMap[item.OptionType]; string defaultDesc = reportDescDic.ContainsKey("默认") ? reportDescDic["默认"] : ""; info.ProfitCalculationInfo = reportDescDic.ContainsKey(item.TradeType) && !string.IsNullOrWhiteSpace(reportDescDic[item.TradeType]) ? reportDescDic[item.TradeType] : defaultDesc; info.ExercisePriceOne = ((item.IsMoneynessOption == "是" ? item.Strike : item.Strike / item.SpotPrice) * 100)?.ToString("0.00"); string tradeType = item.TradeType; if (tradeType.Contains("价差")) { tradeType = "价差期权"; } double? strike = null; switch (tradeType) { case "香草期权": info.OptionStructureType = OptionStructureTypeMap["香草"]; break; case "二元期权": info.OptionStructureType = OptionStructureTypeMap["二元"]; break; case "价差期权": info.OptionStructureType = OptionStructureTypeMap["价差"]; break; case "障碍期权": info.OptionStructureType = OptionStructureTypeMap["障碍"]; break; case "双鲨期权": info.OptionStructureType = OptionStructureTypeMap["鲨鱼鳍"]; var sharkfin = DbContext.trade_double_sharkfin_option.Where(O => O.TradeId == item.id).Select(O => new { O.StrikeHigh, O.StrikeLow }).FirstOrDefault(); info.ExercisePriceOne = ((item.IsMoneynessOption == "是" ? sharkfin.StrikeLow : sharkfin.StrikeLow / item.SpotPrice) * 100)?.ToString("0.00"); info.ExercisePriceTwo = ((item.IsMoneynessOption == "是" ? sharkfin.StrikeHigh : sharkfin.StrikeHigh / item.SpotPrice) * 100)?.ToString("0.00"); break; case "区间累积期权": info.OptionStructureType = OptionStructureTypeMap["区间累计"]; break; case "凤凰期权": info.OptionStructureType = OptionStructureTypeMap["AutoCallable"]; var autocall = DbContext.trade_autocall.Where(O => O.TradeId == item.id).FirstOrDefault(); if (autocall.KIPayoffType != KIPayoffTypeEnum.None) { strike = autocall.SpreadStrike ?? autocall.SpreadStrike1; } if (strike != null) { info.ExercisePriceTwo = ((item.IsMoneynessOption == "是" ? strike : strike / item.SpotPrice) * 100)?.ToString("0.00"); } break; case "雪球期权": info.OptionStructureType = OptionStructureTypeMap["AutoCallable"]; var snowball = DbContext.trade_snowball.Where(O => O.TradeId == item.id).FirstOrDefault(); if (snowball.KIPayoffType != KIPayoffTypeEnum.None) { strike = snowball.SpreadStrikeAtMaturity ?? snowball.SpreadStrikeAtMaturity1; } else if (snowball.KOPayoffType != KOPayoffTypeEnum.Rebate) { strike = snowball.SpreadStrikeAtKO ?? snowball.SpreadStrikeAtKO1; } if (strike != null) { info.ExercisePriceTwo = ((item.IsMoneynessOption == "是" ? strike : strike / item.SpotPrice) * 100)?.ToString("0.00"); } break; default: info.OptionStructureType = OptionStructureTypeMap["其他"]; info.OptionStructure = item.TradeType; break; } if (string.IsNullOrWhiteSpace(info.ExercisePriceOne) && !string.IsNullOrWhiteSpace(info.ExercisePriceTwo)) { info.ExercisePriceOne = info.ExercisePriceTwo; info.ExercisePriceTwo = null; } if (string.IsNullOrWhiteSpace(info.ExercisePriceTwo)) { info.ExercisePriceTwo = null; } info.ExerciseApproach = ExerciseApproachMap[item.ExerciseMode == "American" ? "美式" : "欧式"]; info.StartDate = item.TradeDate?.ToString("yyyy-MM-dd"); info.DueDate = item.ExerciseDate?.ToString("yyyy-MM-dd"); info.SettlementDate = item.SettlementDate?.ToString("yyyy-MM-dd"); info.OptionPremium = (item.PremiumRate * 100)?.ToString("0.00"); var currency = item.SettlementCurrency == "CNH" ? "CNY" : item.SettlementCurrency ?? "CNY"; info.Currency = ((int)(CurrencyEnum)Enum.Parse(typeof(CurrencyEnum), currency)).ToString();// ((int)CurrencyEnum.CNY).ToString(); info.NotinalPrincipleAmt = (item.OriginalStockEqvNotional * rate)?.ToString("0.00"); info.BusinessModelType = BusinessModelTypeMap["传统型期权"]; //系统中的交易修改时必须回退,所以报送不存在修改时还存在有效的存续期记录的情况; //Dictionary reportCacheDic = JsonHelper.ToObject>(note.InfoCache) ?? new Dictionary(); //if (info.OperationType == OptFlagsEnum.U) //{ // if (reportCacheDic.ContainsKey("DueDate") && !reportCacheDic["DueDate"].StartsWith(info.DueDate) && !info.DueDate.StartsWith(reportCacheDic["DueDate"])) // { // throw new ServiceException("补正时,如果该交易还存在有效的存续期记录,到期日字段不能修改"); // } // if (reportCacheDic.ContainsKey("NotinalPrincipleAmt") && reportCacheDic["NotinalPrincipleAmt"] != info.NotinalPrincipleAmt && reportCacheDic["NotinalPrincipleAmt"] != item.OriginalStockEqvNotional?.ToString("0")) // { // throw new ServiceException("补正时,如果该交易还存在有效的存续期记录,名义本金额(人民币)字段不能修改"); // } //} info.ConfirmationAttTuple = new List(); ConfirmationAttModel confirmationInfo = new ConfirmationAttModel(); string path = item.StampDocumentFileName ?? item.Paths; if (!(path.StartsWith("\\") || path.StartsWith("/"))) { path = "\\" + path; } var absolutePath = OtcAppContext.MapPath(path); absolutePath = Path.ChangeExtension(absolutePath, "pdf"); confirmationInfo.ConfirmationAtt = Path.GetFileName(absolutePath); info.ConfirmationAttTuple.Add(confirmationInfo); var um = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode); switch (um.UnderlyingInstrumentType) { case ConsGlobal.InstrumentType.Stock: case ConsGlobal.InstrumentType.StockIndex: case ConsGlobal.InstrumentType.NewOtcStock: case ConsGlobal.InstrumentType.HKStock: case ConsGlobal.InstrumentType.HKStockIndex: case ConsGlobal.InstrumentType.AbroadStock: case ConsGlobal.InstrumentType.AbroadStockIndex: info.UndrlygAssetType = UndrlygAssetTypeMap["权益类"]; break; case ConsGlobal.InstrumentType.StockIF: case ConsGlobal.InstrumentType.CommodityFutures: case ConsGlobal.InstrumentType.GoldFutures: case ConsGlobal.InstrumentType.TBFutures: case ConsGlobal.InstrumentType.OtherFutures: case ConsGlobal.InstrumentType.AbroadFutures: case ConsGlobal.InstrumentType.CommoditySpot: case ConsGlobal.InstrumentType.GoldSpot: case ConsGlobal.InstrumentType.OtherSpot: case ConsGlobal.InstrumentType.AbroadSpot: info.UndrlygAssetType = UndrlygAssetTypeMap["大宗商品"]; break; case ConsGlobal.InstrumentType.ExRate: info.UndrlygAssetType = UndrlygAssetTypeMap["汇率"]; break; case ConsGlobal.InstrumentType.Shibor: case ConsGlobal.InstrumentType.OtherRate: break; default: info.UndrlygAssetType = UndrlygAssetTypeMap["其他"]; break; } info.UndrlygAssetNo = um.CommodityCode == "组合标的" ? UndrlygAssetNoMap["组合标的"] : UndrlygAssetNoMap["单一标的"]; #region 标的信息 info.UndrlygAssetTuple = new List(); List sCodeList = null; if (um.CommodityCode == "组合标的") { sCodeList = DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(item.UnderlyingCode).GetUnderlyingCodes().ToList(); } else { sCodeList = new List() { um.UnderlyingCode }; } for (int i = 0; i < sCodeList.Count; i++) { var codeInfo = DataCacheProvider.GetUnderlyingDataSource().GetData(sCodeList[i]); UndrlygAssetModel undrlygAsset = new UndrlygAssetModel(); undrlygAsset.UndrlygAssetCode = Regex.Replace(codeInfo.UnderlyingCode, @"\..+", ""); undrlygAsset.UndrlygAssetName = codeInfo.UnderlyingName; undrlygAsset.UndrlygAssetAmt = item.OriginalNotional?.ToString(); switch (codeInfo.MarketCode) { case "SHFE": undrlygAsset.UndrlygAssetTradgPlc = UndrlygAssetTradgPlceMap["上海期货交易所"]; break; case "DCE": undrlygAsset.UndrlygAssetTradgPlc = UndrlygAssetTradgPlceMap["大连商品交易所"]; break; case "CZC": case "CZCE": undrlygAsset.UndrlygAssetTradgPlc = UndrlygAssetTradgPlceMap["郑州商品期货交易所"]; break; case "CFFEX": undrlygAsset.UndrlygAssetTradgPlc = UndrlygAssetTradgPlceMap["中国金融期货交易所"]; break; case "INE": undrlygAsset.UndrlygAssetTradgPlc = UndrlygAssetTradgPlceMap["上海国际能源交易中心"]; break; case "SGE": undrlygAsset.UndrlygAssetTradgPlc = UndrlygAssetTradgPlceMap["上海黄金交易所"]; break; case "SH": undrlygAsset.UndrlygAssetTradgPlc = UndrlygAssetTradgPlceMap["上海证券交易所"]; break; case "SZ": undrlygAsset.UndrlygAssetTradgPlc = UndrlygAssetTradgPlceMap["深圳证券交易所"]; break; case "CFETS": undrlygAsset.UndrlygAssetTradgPlc = UndrlygAssetTradgPlceMap["外汇交易中心"]; break; default: undrlygAsset.UndrlygAssetTradgPlc = UndrlygAssetTradgPlceMap["其他"]; break; } if (UndrlygAssetDtldTypeMap.TryGetValue(ConsGlobal.InstrumentType.GetDesc(codeInfo.UnderlyingInstrumentType), out var AssetDtldType)) { undrlygAsset.UndrlygAssetDtldType = AssetDtldType; } else { undrlygAsset.UndrlygAssetDtldType = UndrlygAssetDtldTypeMap["其他标的"]; } info.UndrlygAssetTuple.Add(undrlygAsset); } #endregion #region 履约担保 var files = db.trade_file.Where(O => O.TradeId == item.id).ToArray(); info.PerformanceGuaranteeType = item.MarginType == MarginTypeEnum.NONE ? PerformanceGuaranteeMap["无履约担保"] : PerformanceGuaranteeMap["部分担保"]; if (item.MarginType != MarginTypeEnum.NONE) { info.PerformanceCollProvider = PerformanceCollProviderMap["乙方"]; info.PartyUseColl = ConsReport.BoolMap[valuedateBLL.SystemDate.PartyUseColl || PS.Config.Company == Configuration.CompanyEnum.东莞 ? "是" : "否"];//todo:读取用户输入 info.CollInstruction = valuedateBLL.SystemDate.CollInstruction;//todo:读取用户输入 info.CalculateCollInterest = BoolMap["否"]; info.PerformanceCollInitialRatio = "0";//((item.InitialMargin / item.OriginalStockEqvNotional * 100) ?? 0).ToString("0.00"); info.PerformanceCollAddtlRatio = "0"; info.PerformanceCollOffsetRatio = "0"; var file_PerformanceGuarante = files.FirstOrDefault(O => O.Path.ToLower().EndsWith("履约保证书.pdf")); if (!string.IsNullOrWhiteSpace(file_PerformanceGuarante?.Path)) { string fileName = Path.GetFileName(file_PerformanceGuarante?.Path); path = file_PerformanceGuarante?.Path; info.PerformanceGuaranteeAtt = fileName; info.PerformanceGuaranteeRemark = file_PerformanceGuarante?.Description; if (!ReportStatus.CheckFileLength(path)) { break; } fileList.Add(path); } info.PerformanceCollTuple = new List(); info.PerformanceCollTuple.Add(new PerformanceGuaranteeAttModel() { PerformanceCollType = PerformanceCollTypeMap["现金"], PerformanceCollRange = /*item.MarginType == MarginTypeEnum.DEFAULT ? PerformanceCollRangeMap["本笔交易对应主协议框架下的所有交易"] :*/ PerformanceCollRangeMap["仅本笔交易"] }); } #endregion var file_ComplianceOpinion = files.FirstOrDefault(O => O.Path.ToLower().EndsWith("合规意见书.pdf")); if (!string.IsNullOrWhiteSpace(file_ComplianceOpinion?.Path)) { string fileName = Path.GetFileName(file_ComplianceOpinion?.Path); path = file_ComplianceOpinion?.Path; info.ComplianceOpinion = fileName; if (!ReportStatus.CheckFileLength(path)) { break; } fileList.Add(path); } info.ValidNotinalPrincipleAmt = (item.StockEqvNotionalReal * rate).ToString("0.00"); var client = DataCacheProvider.GetClientDataSource().GetData(item.ClientId); if (client.ClientType == "产品") { using (var baseDb = new ClientDBContext()) { if (PS.Config.Company == Configuration.CompanyEnum.中金) { info.FillParty = FillPartyMap["甲方"]; info.PtyBPdctName = client.Abbreviation ?? ""; info.PytBPdctCode = client.ProductNumber ?? ""; } else { //var clientFile = baseDb.client_file.Where(O => ((O.FileTypeName == ConsGlobal.ClientFileType.MainProtocol && O.ProtocolNumber == info.MasterAgrmtNo) || (O.FileTypeName == ConsGlobal.ClientFileType.AllographProduct && O.MainProtocolNumber == info.MasterAgrmtNo)) && O.ClientId == client.id && O.IsValid).AsEnumerable().GroupBy(O => O.FileTypeName).ToDictionary(K => K.Key, V => V.FirstOrDefault()); //if (!clientFile.ContainsKey(ConsGlobal.ClientFileType.MainProtocol)) //{ // throw new ServiceException($"{client.Name} 主协议文件不存在,生成失败!"); //} ////下面这行注释掉是因为目前系统报送互换时只处理了报送方是甲方的情况,假如报送方为乙方,则所有涉及支付方向的参数都应该对调,期权为了逻辑保持一直,所以暂时一起注释掉; ////info.FillParty = FillPartyMap[clientFile[ConsGlobal.ClientFileType.MainProtocol].ReportorRole]; //var productFile = clientFile.ContainsKey(ConsGlobal.ClientFileType.AllographProduct) ? clientFile[ConsGlobal.ClientFileType.AllographProduct] : null; if (info.FillParty == FillPartyMap["甲方"]) { info.PtyBPdctName = client.Name ?? ""; info.PytBPdctCode = client.Number ?? ""; } else { info.PtyAPdctName = client.Name ?? ""; info.PytAPdctCode = client.Number ?? ""; } } } } info.ExceID = base.formatExceID(); if (!ReportStatus.CheckFileLength(absolutePath)) { break; } fileList.Add(absolutePath); ReportStatus.AddCacheInfo(cacheKey, cacheValue); dataList.Add(info); note.id = 0; note.InfoCache = $"{{\"NotinalPrincipleAmt\":\"{info.NotinalPrincipleAmt}\",\"DueDate\":\"{info.DueDate}\",\"Tag\":\"{info.ConfirmationNo}\",\"Source\":\"System\"}}"; note.ExceId = info.ExceID; note.CreateTime = DateTime.Now; note.FileTag = FileTag; note.ReportType = ReportType; note.ReportDate = _reqInfo.ReportDate; note.InfoTag = formatInfoTag(info, true); note.OptTime = note.CreateTime; note.ReportResponse = false; note.RetCode = ""; note.RetMsg = ""; note.DataId = item.tcId.ToString(); note.BizId = ""; note.changeStatus = false; noteList.Add(note); } } } LogFactory.GetLogger("loadSubsystemDataSource").Error($"x3:"); var subsystemDataList = loadSubsystemDataSource(fileList, AddSubsystemNote); LogFactory.GetLogger("loadSubsystemDataSource").Error($"x4:"); if (subsystemDataList != null && subsystemDataList.Count > 0) dataList.AddRange(subsystemDataList); fileList = fileList.Distinct().ToList(); noData = dataList.Count == 0; model.OptionConfirmation = dataList; return model; } public bool AddSubsystemNote(OptionConfirmationModel model, List fileList, string tag) { SACReportNotes note = base.GetReportNotes(ReportType, formatInfoTag(model, true)).FirstOrDefault();//参数true要加,要不A和D会查到同一条记录,在D时候,就会和A相同的数据 if (note == null) { note = new SACReportNotes() { InfoCache = $"{{\"NotinalPrincipleAmt\":\"{model.NotinalPrincipleAmt}\",\"DueDate\":\"{model.DueDate}\",\"Tag\":\"{model.ConfirmationNo}\",\"Source\":\"Subsystem\",\"SubFileTag\":\"{tag}\",\"ExceID\":\"{model.ExceID}\"}}", IsValid = true, }; } else//多次U的时候,每次用最新的tag来赋值SubFileTag { switch (model.OperationType) { case OptFlagsEnum.A: return false;//新增数据已报送,跳过 case OptFlagsEnum.U: //多次U的时候,每次用最新的tag来赋值SubFileTag note.InfoCache = $"{{\"NotinalPrincipleAmt\":\"{model.NotinalPrincipleAmt}\",\"DueDate\":\"{model.DueDate}\",\"Tag\":\"{model.ConfirmationNo}\",\"Source\":\"Subsystem\",\"SubFileTag\":\"{tag}\",\"ExceID\":\"{model.ExceID}\"}}"; note.IsValid = true; break; case OptFlagsEnum.D:// note.IsValid = false; break; case OptFlagsEnum.NONE: default: throw new ServiceException("未知操作类型"); } } if (!string.IsNullOrWhiteSpace(model.ComplianceOpinion)) { fileList.Add(model.ComplianceOpinion); } if (!string.IsNullOrWhiteSpace(model.PerformanceGuaranteeAtt)) { fileList.Add(model.PerformanceGuaranteeAtt); } if (model.ConfirmationAttTuple != null && model.ConfirmationAttTuple.Count > 0) { fileList.AddRange(model.ConfirmationAttTuple.Select(x => x.ConfirmationAtt)); } model.ExceID = base.formatExceID(); note.id = 0; note.ExceId = model.ExceID; note.CreateTime = DateTime.Now; note.FileTag = FileTag; note.ReportType = ReportType; note.ReportDate = _reqInfo.ReportDate; note.InfoTag = formatInfoTag(model, true); note.OptTime = note.CreateTime; note.RetCode = ""; note.RetMsg = ""; note.ReportResponse = false; note.BizId = ""; note.changeStatus = false; noteList.Add(note); return true; } private List GetOptionConfirmationModelFromExcel(ref List fileList) { List result = new List(); string path = ""; if (_excelDataSource != null) { LogFactory.GetLogger("loadSubsystemDataSource").Info($"xrrrr:"); if (_excelDataSource.Tables != null) LogFactory.GetLogger("loadSubsystemDataSource").Info($"ggg:"); if (_excelDataSource.Tables == null) LogFactory.GetLogger("loadSubsystemDataSource").Info($"ghh:"); } if (_excelDataSource != null && _excelDataSource.Tables.Contains("期权交易确认书明细")) { LogFactory.GetLogger("loadSubsystemDataSource").Info($"x111:"); var cacheKey = $"{BusiDataType}"; string sourcePath = Path.Combine(_excelDataSourceRootPath, "附件"); DataTable dt = _excelDataSource.Tables["期权交易确认书明细"]; for (int i = 1; i < dt.Rows.Count; i++) { if (string.IsNullOrWhiteSpace(dt.Rows[i][0]?.ToString())) { //第一列空白说明数据结束了; break; } var optType = OptFlagsEnum.NONE; switch (dt.Rows[i][3]?.ToString()) { case "首次": optType = OptFlagsEnum.A; break; case "变更": optType = OptFlagsEnum.U; break; case "废止": optType = OptFlagsEnum.D; break; } if (optType != _operationType) { continue; } OptionConfirmationModel model = new OptionConfirmationModel(); model.OperationType = optType; model.MasterAgrmtNo = GetDataSetValue(dt, i, 0); model.SupAgrmtNo = GetDataSetValue(dt, i, 1); model.ConfirmationNo = GetDataSetValue(dt, i, 2); model.ConfirmationType = ConsReport.ReportTypeMap[optType == OptFlagsEnum.A ? "首次" : "变更"]; model.FillParty = ConsReport.FillPartyMap[GetDataSetValue(dt, i, 4)]; model.OptionSeller = ConsReport.OptionTraderMap[GetDataSetValue(dt, i, 5)]; model.OptionDirection = ConsReport.OptionDirectionMap[GetDataSetValue(dt, i, 6)]; model.OptionStructureType = ConsReport.OptionStructureTypeMap[GetDataSetValue(dt, i, 7)]; model.OptionStructure = GetDataSetValue(dt, i, 8); model.ExerciseApproach = ConsReport.ExerciseApproachMap[GetDataSetValue(dt, i, 9)]; model.StartDate = GetDataSetValue(dt, i, 10); model.DueDate = GetDataSetValue(dt, i, 11); model.SettlementDate = GetDataSetValue(dt, i, 12); model.OptionPremium = GetDataSetValue(dt, i, 13); if (!Enum.TryParse(GetDataSetValue(dt, i, 14), out CurrencyEnum currency)) { currency = CurrencyEnum.CNY; } model.Currency = ((int)currency).ToString(); model.NotinalPrincipleAmt = GetDataSetValue(dt, i, 15); model.ClearingAgency = ConsReport.ClearingAgencyMap[GetDataSetValue(dt, i, 16)]; model.TradingPlace = ConsReport.TradingPlaceMap[GetDataSetValue(dt, i, 17)]; model.BusinessModelType = ConsReport.BusinessModelTypeMap[GetDataSetValue(dt, i, 18)]; model.ConfirmationRemark = GetDataSetValue(dt, i, 20); model.UndrlygAssetType = ConsReport.UndrlygAssetTypeMap[GetDataSetValue(dt, i, 21)]; model.UndrlygAssetNo = ConsReport.UndrlygAssetNoMap[GetDataSetValue(dt, i, 22)]; model.ProfitCalculationInfo = GetDataSetValue(dt, i, 23); model.ProfitRemark = GetDataSetValue(dt, i, 24); model.PerformanceGuaranteeType = ConsReport.PerformanceGuaranteeMap[GetDataSetValue(dt, i, 25)]; model.PerformanceCollProvider = ConsReport.PerformanceCollProviderMap[GetDataSetValue(dt, i, 26)]; model.PartyUseColl = ConsReport.BoolMap[GetDataSetValue(dt, i, 27)]; model.CollInstruction = GetDataSetValue(dt, i, 28); model.CalculateCollInterest = ConsReport.BoolMap[GetDataSetValue(dt, i, 29)]; model.PerformanceCollInitialRatio = GetDataSetValue(dt, i, 30); model.PerformanceCollAddtlRatio = GetDataSetValue(dt, i, 31); model.PerformanceCollOffsetRatio = GetDataSetValue(dt, i, 32); model.PerformanceGuaranteeRemark = GetDataSetValue(dt, i, 33); model.PerformanceGuaranteeAtt = GetDataSetValue(dt, i, 34); model.Remark = GetDataSetValue(dt, i, 35); model.ValidNotinalPrincipleAmt = GetDataSetValue(dt, i, 36); model.ComplianceOpinion = GetDataSetValue(dt, i, 37); model.ExercisePriceOne = GetDataSetValue(dt, i, 38); model.ExercisePriceTwo = GetDataSetValue(dt, i, 39); model.PtyAPdctName = GetDataSetValue(dt, i, 40); model.PytAPdctCode = GetDataSetValue(dt, i, 41); model.PtyBPdctName = GetDataSetValue(dt, i, 42); model.PytBPdctCode = GetDataSetValue(dt, i, 43); var notinalPrincipleAmt = GetDataSetValueToDouble(dt, i, 15); var cacheValue = model.ConfirmationNo; if (ReportStatus.CheckCacheInfo(cacheKey, cacheValue)) { continue; } SACReportNotes note = base.GetReportNotes(ReportType, formatInfoTag(model)).FirstOrDefault(); if (note == null && _operationType == OptFlagsEnum.A) { note = new SACReportNotes() { IsValid = true, }; } else { if (note == null) { continue; } switch (_operationType) { case OptFlagsEnum.A: continue;//新增数据已报送,跳过 case OptFlagsEnum.U: note.IsValid = true; break; case OptFlagsEnum.D: note.IsValid = false; break; case OptFlagsEnum.NONE: default: throw new ServiceException("未知操作类型"); } if (_operationType == OptFlagsEnum.U) { Dictionary reportCacheDic = JsonHelper.ToObject>(note.InfoCache) ?? new Dictionary(); var settleList = base.GetReportNotes(SuperviseReportTypeEnum.SAC_OptionTermination, formatInfoTag(model, false, true)); if (settleList.Count > 0) { if (reportCacheDic.ContainsKey("DueDate") && !reportCacheDic["DueDate"].StartsWith(model.DueDate) && !model.DueDate.StartsWith(reportCacheDic["DueDate"])) { throw new ServiceException("补正时,如果该交易还存在有效的存续期记录,到期日字段不能修改"); } if (reportCacheDic.ContainsKey("NotinalPrincipleAmt") && reportCacheDic["NotinalPrincipleAmt"] != model.NotinalPrincipleAmt && reportCacheDic["NotinalPrincipleAmt"] != notinalPrincipleAmt.ToString("0")) { throw new ServiceException("补正时,如果该交易还存在有效的存续期记录,名义本金额(人民币)字段不能修改"); } } } } if (model.OperationType != OptFlagsEnum.A) { model.ConfirmationID = note.BizId;//确认书编号; } string[] confirmationAttTuple = GetDataSetValue(dt, i, 19).Split(','); foreach (var item in confirmationAttTuple) { if (string.IsNullOrWhiteSpace(item)) { continue; } if (model.ConfirmationAttTuple == null) { model.ConfirmationAttTuple = new List(); } model.ConfirmationAttTuple.Add(new ConfirmationAttModel() { ConfirmationAtt = item }); path = Path.Combine(sourcePath, item); if (!ReportStatus.CheckFileLength(path)) { break; } fileList.Add(path); } model.UndrlygAssetTuple = GetUndrlygAssetModel(model.ConfirmationNo); model.PerformanceCollTuple = GetPerformanceGuaranteeAttModel(model.ConfirmationNo); path = Path.Combine(sourcePath, model.PerformanceGuaranteeAtt); if (!string.IsNullOrWhiteSpace(model.PerformanceGuaranteeAtt)) { if (!ReportStatus.CheckFileLength(path)) { break; } fileList.Add(path); } if (!string.IsNullOrWhiteSpace(model.ComplianceOpinion)) { path = Path.Combine(sourcePath, model.ComplianceOpinion); if (!ReportStatus.CheckFileLength(path)) { break; } fileList.Add(path); } model.ExceID = base.formatExceID(); result.Add(model); ReportStatus.AddCacheInfo(cacheKey, cacheValue); note.id = 0; note.InfoCache = $"{{\"NotinalPrincipleAmt\":\"{model.NotinalPrincipleAmt}\",\"DueDate\":\"{model.DueDate}\",\"Tag\":\"{model.ConfirmationNo}\",\"Source\":\"Template\"}}"; note.ExceId = model.ExceID; note.CreateTime = DateTime.Now; note.FileTag = FileTag; note.ReportType = ReportType; note.ReportDate = _reqInfo.ReportDate; note.InfoTag = formatInfoTag(model, true); note.OptTime = note.CreateTime; note.RetCode = ""; note.RetMsg = ""; note.ReportResponse = false; note.BizId = ""; note.changeStatus = false; noteList.Add(note); } } return result; } private List GetPerformanceGuaranteeAttModel(string masterAgrmtNo) { List result = new List(); if (_excelDataSource != null && _excelDataSource.Tables.Contains("履约担保品详情明细")) { DataTable dt = _excelDataSource.Tables["履约担保品详情明细"]; for (int i = 1; i < dt.Rows.Count; i++) { if (string.IsNullOrWhiteSpace(dt.Rows[i][0]?.ToString())) { //第一列空白说明数据结束了; break; } if (dt.Rows[i][0]?.ToString() != masterAgrmtNo) { continue; } PerformanceGuaranteeAttModel model = new PerformanceGuaranteeAttModel(); model.PerformanceCollType = ConsReport.PerformanceCollTypeMap[GetDataSetValue(dt, i, 1)]; model.PerformanceCollRange = ConsReport.PerformanceCollRangeMap[GetDataSetValue(dt, i, 2)]; model.MultiConfirmationID = GetDataSetValue(dt, i, 3); result.Add(model); } } return result; } private List GetUndrlygAssetModel(string masterAgrmtNo) { List result = new List(); if (_excelDataSource != null && _excelDataSource.Tables.Contains("标的详情明细")) { DataTable dt = _excelDataSource.Tables["标的详情明细"]; for (int i = 1; i < dt.Rows.Count; i++) { if (string.IsNullOrWhiteSpace(dt.Rows[i][0]?.ToString())) { //第一列空白说明数据结束了; break; } if (dt.Rows[i][0]?.ToString() != masterAgrmtNo) { continue; } UndrlygAssetModel model = new UndrlygAssetModel(); model.UndrlygAssetDtldType = ConsReport.UndrlygAssetDtldTypeMap[GetDataSetValue(dt, i, 1)]; model.UndrlygAssetName = GetDataSetValue(dt, i, 2); model.UndrlygAssetTradgPlc = ConsReport.UndrlygAssetTradgPlceMap[GetDataSetValue(dt, i, 3)]; model.UndrlygAssetCode = GetDataSetValue(dt, i, 4); model.UndrlygAssetAmt = GetDataSetValue(dt, i, 5); result.Add(model); } } return result; } private string formatInfoTag(OptionConfirmationModel model, bool suffixType = false, bool isSettlement = false) { string result = $"{(isSettlement ? "" : BusiDataType.ToString())}_{model.ConfirmationNo.Replace("_", "-")}_{(isSettlement ? "" : "成交_")}"; if (suffixType) { result = $"{result}{_operationType}"; } return result; } protected override List CheckBodyValue(BodyModel model, out bool checkStatus) { List result = new List(); if (model?.OptionConfirmation != null) { CheckHelper helper = new Common.CheckHelper(); CheckHelper cAttHelper = new Common.CheckHelper(); CheckHelper undrlygHelper = new Common.CheckHelper(); CheckHelper pAttHelper = new Common.CheckHelper(); for (int i = 0; i < model.OptionConfirmation.Count; i++) { List listRoot = new List(); var item = model.OptionConfirmation[i]; if (item.IgnoreCheck) continue; helper.ExecuteCheck(item, (name, value, msg) => { listRoot.Add(new SacInfo(name, value, msg)); }); if (item.ConfirmationAttTuple != null) { for (int j = 0; j < item.ConfirmationAttTuple.Count; j++) { var listItem = new List(); var attItem = item.ConfirmationAttTuple[j]; cAttHelper.ExecuteCheck(attItem, (name, value, msg) => { listItem.Add(new SacInfo(name, value, msg)); }); if (listItem.Count > 0) { var temp = new SacInfo("ConfirmationAttTuple", j); temp.SubMaps = new List(listItem); listRoot.Add(temp); } } } if (item.UndrlygAssetTuple != null) { for (int j = 0; j < item.UndrlygAssetTuple.Count; j++) { var listItem = new List(); var undrlygItem = item.UndrlygAssetTuple[j]; undrlygHelper.ExecuteCheck(undrlygItem, (name, value, msg) => { listItem.Add(new SacInfo(name, value, msg)); }); if (listItem.Count > 0) { var temp = new SacInfo("UndrlygAssetTuple", j); temp.SubMaps = new List(listItem); listRoot.Add(temp); } } } if (item.PerformanceCollTuple != null) { for (int j = 0; j < item.PerformanceCollTuple.Count; j++) { var listItem = new List(); var pItem = item.PerformanceCollTuple[j]; pAttHelper.ExecuteCheck(pItem, (name, value, msg) => { listItem.Add(new SacInfo(name, value, msg)); }); if (listItem.Count > 0) { var temp = new SacInfo("PerformanceCollTuple", j); temp.SubMaps = new List(listItem); listRoot.Add(temp); } } } if (listRoot.Count > 0) { var errMsg = new SacInfo("OptionConfirmation", i); errMsg.SubMaps = new List(listRoot); result.Add(errMsg); } } } checkStatus = result.Count > 0; return result; } public override bool BeforeOfGenerated(out string errMsg) { errMsg = ""; foreach (var file in xmlAttachmentList) { try { File.Delete(file); } catch (Exception e) { LogFactory.GetLogger().Error(e); }; } for (int i = 0; i < noteList.Count; i++) { base.SaveReportNotes(noteList[i]); } return true; } } }