using System.Data; using YLErp.Commons; using YLErp.Model; namespace YLErp.Modules.EodModule { /// /// 结算价导入服务 /// public class SettlementPriceImportService : YLBaseService { public SettlementPriceImportService(OptUserInfo userInfo) : base(userInfo) { } public static bool UseStockPriceTable(string instrumentType) { return ConsGlobal.InstrumentType.EquityTypes().Contains(instrumentType) || instrumentType == ConsGlobal.InstrumentType.Fund; } /// /// 导入xlsx数据 /// public ImportResultModel ImportxlsxDatas(Stream stream) { var importModels = Enumerable.Empty(); var rowIndex = 0; try { var ds = Office.ExcelHelper.ReadExcelAsDataSet(stream); if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 1) { throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" }; } var table = ds.Tables[0]; var reader = new DataRowReader(table); var list = new List(); rowIndex = 1; foreach (DataRow row in table.Rows) { rowIndex++; if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString()))) { continue; } reader.SetDataRow(row); var model = new ImportModel { date = reader.GetDate("日期", true).Value, code = reader.GetString("代码", true), closePrice = reader.GetDouble("收盘价", false), settlePrice = reader.GetDouble("结算价", false), ReferencePrice = reader.GetDouble("参考价", false) }; model.underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(model.code); if (model.underlying == null) { throw new ServiceException("标的代码不存在:" + model.code) { Tag = "111" }; } list.Add(model); } importModels = list.ToArray(); } catch (ServiceException se) { if (se.Tag != null) throw; throw new ServiceException($"第{rowIndex}行,发生错误:{se.Message}"); } catch (Exception ex) { LogFactory.GetLogger("导入场内交易").Error(ex); throw new ServiceException($"第{rowIndex}行,发生错误:{ex.Message}", ex); } if (!importModels.Any()) { throw new ServiceException("没有可导入的数据"); } var result = new ImportResultModel { TotalCount = importModels.Count() }; var dates = new HashSet(); var uniqSet = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var item in importModels) { var underlying = item.underlying; if (underlying.IsBond()) { var eodPrice = DbContext.china_bond_valuation .FirstOrDefault(p => p.valuation_date == item.date && p.bond_id == underlying.UnderlyingCode); if (eodPrice == null) { var datestr = item.date.ToString("yyyyMMdd"); if (uniqSet.Add(datestr + "^" + item.code)) { eodPrice = new ChinaBondValuation(); eodPrice.credibility = 1; DbContext.china_bond_valuation.Add(eodPrice); } else { result.Errors.Add($"重复数据,忽略: {datestr},{item.code}"); continue; } } eodPrice.valuation_date = item.date; eodPrice.bond_id = underlying.UnderlyingCode; if (item.closePrice.HasValue) eodPrice.dirty_price_close =Convert.ToDecimal(item.closePrice ?? 0); if (item.settlePrice.HasValue) eodPrice.net_price = Convert.ToDecimal(item.settlePrice ?? 0); if (item.ReferencePrice.HasValue) eodPrice.yield = Convert.ToDecimal(item.ReferencePrice); eodPrice.update_time = DateTime.Now; // 手工上传也是登录用户的人工动作,戳操作人到已有列(create_user/update_user), // 使列表来源列显示上传人姓名(与 SaveBondPrice 口径一致);聚源/中债自动同步(外部ETL)不写这两列。 // eodPrice.id==0 表示本次新增(尚未落库),非0为命中已有行的更新。 EodPriceService.StampBondOperator(eodPrice, UserId, eodPrice.id == 0); result.SuccessCount++; } else if (!UseStockPriceTable(underlying.UnderlyingInstrumentType)) { var eodPrice = DbContext.eod_commodity_future_price .FirstOrDefault(p => p.ValueDate == item.date && p.UnderlyingCode == underlying.UnderlyingCode); if (eodPrice == null) { var datestr = item.date.ToString("yyyyMMdd"); if (uniqSet.Add(datestr + "^" + item.code)) { eodPrice = new eod_commodity_future_price(); DbContext.eod_commodity_future_price.Add(eodPrice); } else { result.Errors.Add($"重复数据,忽略: {datestr},{item.code}"); continue; } } eodPrice.ValueDate = item.date; eodPrice.UnderlyingCode = underlying.UnderlyingCode; eodPrice.UnderlyingId = underlying.id; // 入库前强制 UnderlyingId 与 UnderlyingCode(FutureContractId) 一致,避免网页/结算两套 JOIN 失同步。 EodPriceService.SyncUnderlyingIdFromCode(DbContext, eodPrice); if (item.closePrice.HasValue) eodPrice.ClosePrice = item.closePrice ?? 0; if (item.settlePrice.HasValue) eodPrice.SettlePrice = item.settlePrice ?? 0; if (item.ReferencePrice.HasValue) eodPrice.ReferencePrice = item.ReferencePrice; eodPrice.OptId = UserId; eodPrice.OptName = UserName; eodPrice.OptDate = DateTime.Now; eodPrice.DataSource = EodPriceBase.人工; result.SuccessCount++; } else { var stockPrice = DbContext.eod_stock_price .FirstOrDefault(p => p.ValueDate == item.date && p.UnderlyingCode == underlying.UnderlyingCode); if (stockPrice == null) { var datestr = item.date.ToString("yyyyMMdd"); if (uniqSet.Add(datestr + "^" + item.code)) { stockPrice = new eod_stock_price(); DbContext.eod_stock_price.Add(stockPrice); } else { result.Errors.Add($"重复数据,忽略: {datestr},{item.code}"); continue; } } stockPrice.ValueDate = item.date; stockPrice.UnderlyingCode = underlying.UnderlyingCode; if (item.closePrice.HasValue) stockPrice.ClosePrice = item.closePrice ?? 0; if (item.ReferencePrice.HasValue) stockPrice.ReferencePrice = item.ReferencePrice; stockPrice.OptDate = DateTime.Now; stockPrice.DataSource = EodPriceBase.人工; result.SuccessCount++; } //else //{ // result.Errors.Add("未导入,标的不属于商品或股票:" + item.code); //} dates.Add(item.date.Date); } DbContext.SaveChanges(); if (dates.Contains(BLL.valuedateBLL.ValueDate)) { var sql = $@" update underlying_manager um join eod_commodity_future_price eod on um.UnderlyingCode = eod.FutureContractId set um.Price = eod.ClosePrice where eod.ValueDate='{BLL.valuedateBLL.ValueDate:yyyy-MM-dd}'; update underlying_manager um join eod_stock_price eod on um.UnderlyingCode = eod.StockId set um.Price = eod.ClosePrice where eod.ValueDate='{BLL.valuedateBLL.ValueDate:yyyy-MM-dd}';"; DbContext.Database.ExecuteSqlRaw(sql); } return result; } class ImportModel { public DateTime date { get; set; } public string code { get; set; } public double? closePrice { get; set; } public double? settlePrice { get; set; } public double? ReferencePrice { get; set; } public underlying_manager underlying { get; set; } } } }