using BaseOUDAL; using Dapper; using System.ComponentModel.DataAnnotations.Schema; using System.Text; using YLErp.BLL; using YLErp.Helpers; using YLErp.Model; using YLErp.Model.Enum; using YLErp.Modules.SuperviseReportModule.CFMMC2022.Model; namespace YLErp.Modules.SuperviseReportModule.CFMMC2022.Service { /// /// 监管报告-客户资金服务 /// public class SuperviseReportClientCashService : YLBaseService { public SuperviseReportClientCashService(OptUserInfo userInfo) : base(userInfo) { } /// /// 计算出客户资金信息 /// public SearchListResult NewSearchSuperviseReportList(SuperviseReportReq req, IEnumerable clienIds = null) { if (string.IsNullOrWhiteSpace(req.sidx)) { req.sidx = "ClientId"; } var config = DbContext.valuedate.FirstOrDefault(x => x.State == valuedate.当前使用); var insidedClientIds = DataCacheProvider.GetClientDataSource().AsQueryable().Where(O => O.IsInsided == 1).Select(O => O.id).ToList(); #region 新增客户筛选 tw if (clienIds != null) { insidedClientIds = insidedClientIds.Where(l => clienIds.Contains(l)).ToList(); } #endregion SuperviseReportClientCashModelEx[] tempQuery = null; List clientIds = new List(); if (req.DataType != null && !req.DataType.Contains("全量客户")) { foreach (var dataType in req.DataType) { switch (dataType) { case "有持仓": clientIds.AddRange(DbContext.eod_trade.Where(O => O.ValueDate == req.ValueDate).Select(O => O.ClientId)); break; case "有资金": clientIds.AddRange(from cb in DbContext.ClientBalanceDaily.Where(n => n.BalanceDate == req.ValueDate) join cr in DbContext.credit.Where(n => n.ProcessStatus == "已审批" && (n.CreditStartDate == null || n.CreditStartDate <= req.ValueDate) && n.CreditDeadLine >= req.ValueDate) on cb.ClientId equals cr.ClientId into t_cr from cr in t_cr.DefaultIfEmpty() where !((cb.ToDayRemainFund == null || (cb.ToDayRemainFund < 0.0001 && cb.ToDayRemainFund > -0.0001)) && (cb.MarginBalance == null || (cb.MarginBalance < 0.0001 && cb.MarginBalance > -0.0001)) && (cb.PayableMargin == null || (cb.PayableMargin < 0.0001 && cb.PayableMargin > -0.0001)) && (cb.PositionPremiumNetCash == null || (cb.PositionPremiumNetCash < 0.0001 && cb.PositionPremiumNetCash > -0.0001)) && (cr == null || cr.Credit == null || (cr.Credit < 0.0001 && cr.Credit > -0.0001))) select cb.ClientId); break; } } if (clientIds.Any()) { clientIds = clientIds.Distinct().ToList(); var parentClientIds = new HashSet(clientIds); foreach (var item in clientIds) { Client clientInfo = DataCacheProvider.GetClientDataSource().GetData(item); do { if (clientInfo == null)//客户不存在,提示错误 { throw new ServiceException($"{clientInfo.Name} 的所属机构不存在,请维护后生成!"); } if (clientInfo.IsInsided == 1)//跳过内部客户 { break; } if (clientInfo.ParentId == 0)//没有父客户则跳出; { break; } clientInfo = DataCacheProvider.GetClientDataSource().GetData(clientInfo.ParentId); if (clientInfo != null)//将找到的父客户Id增加到客户列表 { parentClientIds.Add(clientInfo.ParentId); } } while (true); } clientIds = parentClientIds.ToList(); } } else { if (PS.Config.Is浙期) { using (var clientDb = DbContextFactory.GetClientDbContext(OptUser)) { var tempIds = (from cb in clientDb.client_black join c in clientDb.client on cb.Name equals c.Name select c.id).ToList(); if (tempIds.Count > 0) { insidedClientIds.AddRange(tempIds); } } } } if (clienIds != null) { clientIds.AddRange(clienIds); } tempQuery = QueryList(req, insidedClientIds, clientIds, out var count); var result = new SearchListResult { records = count, rows = tempQuery, page = req.page }; result.total = (result.records - 1) / req.rows + 1; var clientIdArr = result.rows.Select(O => O.ClientId).ToHashSet(); //一级子客户 var subClientIdArr = DataCacheProvider.GetClientDataSource().AsQueryable(O => clientIdArr.Contains(O.ParentId) && O.IsDocShowParentName == 1).Select(O => O.id); //二级子客户 subClientIdArr.Concat(DataCacheProvider.GetClientDataSource().AsQueryable(O => subClientIdArr.Contains(O.ParentId) && O.IsDocShowParentName == 1).Select(O => O.id)); Dictionary> cbDict = null; if (subClientIdArr.Any()) { cbDict = QueryList(req, null, subClientIdArr.ToList(), out _, 1).GroupBy(O => O.ParentId).ToDictionary(K => K.Key, V => V.ToList()); clientIdArr = clientIdArr.Concat(subClientIdArr).ToHashSet(); } else { cbDict = new Dictionary>(); } var creditDict = DbContext.CreditFromClient.Where(O => clientIdArr.Contains(O.ClientId) && O.CreditStartDate <= req.ValueDate && O.CreditDeadLine >= req.ValueDate).ToDictionary(K => K.ClientId); var productDict = DbContext.clientcashincashout_product .Where(O => (O.Status == Clientcashincashout_productStatusEnum.抵押.ToString() && O.OptStatus == ClientCashInCashOut.已确认 || O.Status == Clientcashincashout_productStatusEnum.赎回.ToString() && O.OptStatus != ClientCashInCashOut.已确认 || O.Status == Clientcashincashout_productStatusEnum.赎回.ToString() && O.OptStatus == ClientCashInCashOut.已确认 && O.BackDate >= req.ValueDate) && clientIdArr.Contains(O.ClientId) && O.HappenDate < req.ValueDate && O.Comments != null && O.Comments != "") .AsEnumerable().GroupBy(O => O.ClientId).ToDictionary(K => K.Key, V => V.FirstOrDefault().Comments); var clientMetaQuery = DbContextFactory.GetClientDbContext(UserInfo).ClientMeta.Where(O => clientIdArr.Contains(O.ClientId)); var clientReportInfo = clientMetaQuery.Where(O => O.MetaKey == "ReportName").ToDictionary(K => K.ClientId, V => V.MetaValue); var marginPayTimeInfo = clientMetaQuery.Where(O => O.MetaKey == "追保到账时间").ToDictionary(K => K.ClientId, V => V.MetaValue); var clientcontext = new ClientDBContext(); string marginPayTime = ""; var sDate = req.ValueDate; var eDate = sDate.AddDays(1); var cashOther = DbContext.client_cash_other.Where(O => clientIdArr.Contains(O.ClientId ?? 0) && O.HappenDate >= sDate && O.HappenDate < eDate).ToList(); //暂时增加时间保证不报错 DbContext.Database.SetCommandTimeout(600); //子公司抵押品 var companycollaterInfo = (from source in DbContext.company_collateral join underlying in DbContext.underlying_manager on source.UnderlyingId equals underlying.id into underlying_manager from underlying in underlying_manager.DefaultIfEmpty() join commodityFuturePrice in DbContext.eod_commodity_future_price.Where(n => n.ValueDate == req.ValueDate) on underlying.UnderlyingCode equals commodityFuturePrice.UnderlyingCode into commodityFuturePrices from commodityFuturePrice in commodityFuturePrices.DefaultIfEmpty() join stockPrice in DbContext.eod_stock_price.Where(n => n.ValueDate == req.ValueDate) on underlying.UnderlyingCode equals stockPrice.UnderlyingCode into stockPrices from stockPrice in stockPrices.DefaultIfEmpty() join v in DbContext.variety on source.VarietyId equals v.id into variety from v in variety.DefaultIfEmpty() where req.ValueDate >= source.HappenDate && clientIdArr.Contains(source.ClientId) && source.OptStatus == "已确认" && source.Status == company_collateralStatusEnum.抵押.ToString() select new company_collateralLinq { ClientId = source.ClientId, Comments = source.Comments ?? "", ProductTotalPrice = source.ProductAmount * source.Rate * (commodityFuturePrice != null ? (valuedateBLL.SystemDate.EodSettlePriceMode == "结算价" ? commodityFuturePrice.SettlePrice : commodityFuturePrice.ClosePrice) : (stockPrice != null ? stockPrice.ClosePrice : (underlying == null ? 0 : underlying.Price))), }).ToList(); using (ErpBaseContext basedb = new ErpBaseContext()) { marginPayTime = (from di in basedb.DictionaryItems join d in basedb.Dictionaries on di.DictId equals d.Id where d.Name == "资金报送追保到账时间" select di.ShortName).FirstOrDefault(); } int startIndex = req.rows * result.page - req.rows, i = 1; var tradeList = (from t in DbContext.eod_trade where t.ValueDate == req.ValueDate && t.TradeStatus == "确认成交" select new xodTradeBase() { TradeJson = t.TradeJson }) .ToArray().Select(O => O.trade); foreach (var item in result.rows) { var marginPayTimeValue = marginPayTimeInfo.TryGetValue(item.ClientId, out var temp) ? temp : marginPayTime; i = SetReportObj(req, config, creditDict, productDict, clientReportInfo, marginPayTimeValue, cashOther, companycollaterInfo, startIndex, i, item); //item.ToClientCredit = item.ToClientCredit.OtcFormatValue(2); //item.ClientTradePriceCredit = item.ClientTradePriceCredit.OtcFormatValue(2); //item.ClientPositionCredit = item.ClientPositionCredit.OtcFormatValue(2); //item.PositionTradePriceOut = item.PositionTradePriceOut.OtcFormatValue(2); //item.ToCompanyCredit = item.ToCompanyCredit?.OtcFormatValue(2); //item.CompanyTradePriceCredit = item.CompanyTradePriceCredit.OtcFormatValue(2); //item.CompanyPositionCredit = item.CompanyPositionCredit.OtcFormatValue(2); //item.PositionTradePriceIn = item.PositionTradePriceIn.OtcFormatValue(2); if (cbDict.TryGetValue(item.ClientId, out var list)) { foreach (var obj in list) { marginPayTimeValue = marginPayTimeInfo.TryGetValue(item.ClientId, out temp) ? temp : marginPayTime; SetReportObj(req, config, creditDict, productDict, clientReportInfo, marginPayTimeValue, cashOther, companycollaterInfo, startIndex, 0, obj); item.OpenBalance += obj.OpenBalance.OtcFormatValue(2); item.TodayCashInCashOut += obj.TodayCashInCashOut.OtcFormatValue(2); item.TodaySettleEarnings += obj.TodaySettleEarnings.OtcFormatValue(2); item.TodayOpenTradePrice += obj.TodayOpenTradePrice.OtcFormatValue(2); item.EndBalance += obj.EndBalance.OtcFormatValue(2); item.ClientMarginHold += obj.ClientMarginHold?.OtcFormatValue(2); item.CompanyMarginHold += obj.CompanyMarginHold?.OtcFormatValue(2); item.AvailableCash += obj.AvailableCash.OtcFormatValue(2); item.DesirableFund += obj.DesirableFund.OtcFormatValue(2); item.AddFunds += obj.AddFunds.OtcFormatValue(2); item.PositionValue += obj.PositionValue.OtcFormatValue(2); item.MarketValueEquity += obj.MarketValueEquity.OtcFormatValue(2); item.PositionPnl += obj.PositionPnl?.OtcFormatValue(2); item.PositionPremiumNetCash += obj.PositionPremiumNetCash.OtcFormatValue(2); item.ToDayRemainFund += obj.ToDayRemainFund.OtcFormatValue(2); item.TodayRemianFundProduct += obj.TodayRemianFundProduct.OtcFormatValue(2); } } } return new SearchListResult(result, result.rows); } private int SetReportObj(SuperviseReportReq req, valuedate config, Dictionary creditDict, Dictionary productDict, Dictionary clientReportInfo, string marginPayTime, List cashOther, List companycollaterInfo, int startIndex, int i, SuperviseReportClientCashModelEx item) { item.CompanyName = config.SuperviseMainName; item.CompanyLicenseCode = config.SuperviseMainCode; item.Date = req.ValueDate; if (creditDict.TryGetValue(item.ClientId, out var credit)) { item.ToCompanyCredit = credit.Credit; item.Remark = credit.Comments ?? ""; } var marginHold = item.ClientMarginHold; var client = DataCacheProvider.GetClientDataSource().GetData(item.ClientId); if (client != null) { item.CustomerNature2 = client.CustomerNature2 ?? ""; item.ClientName = clientReportInfo.TryGetValue(client.id, out var reportName) && !string.IsNullOrWhiteSpace(reportName) ? reportName : client.Name; item.ClientType = client.CustomerNature2; item.ClientLicenseCode = client.LicenseCode; //获取交易对手方LEI item.ClientLEI = client.LEICode; } else { return i; } //当日出入金需要从client_cash_other表中获取当天记录 if (PS.Config.ErpElement.IsSumOthersOnClientCash) { item.TodayCashInCashOut += cashOther.Where(O => O.ClientId.Value == client.id).Sum(O => O.Money ?? 0); } item.MarginType = ((MarginOptionEnum)client.MarginOptionType).ToString(); item.MarginPayTime = marginPayTime; item.id = item.Index = startIndex + i++; item.PositionTradePriceOut = 0; item.PositionTradePriceIn = 0; switch (item.MarginType) { case "单向追保": item.MarginCollectionMode = "子公司向对手方单向收预付金"; item.CompanyMarginHold = 0; item.ClientMarginHold = Math.Abs(marginHold ?? 0); break; case "对手方单向追保": item.MarginCollectionMode = "对手方向子公司单向收预付金"; item.CompanyMarginHold = Math.Abs(marginHold ?? 0); item.ClientMarginHold = 0; break; case "双向追保": item.MarginCollectionMode = "子公司和对手方互收预付金"; item.ClientMarginHold = Math.Max(0, (marginHold ?? 0)); if (PS.Config.Company != Configuration.CompanyEnum.弘业) { item.CompanyMarginHold = Math.Abs(Math.Min(0, (marginHold ?? 0)));//这里赋值是必要的,否则计算时会当做0去计算; } item.CompanyMarginHold = null; if (PS.Config.Company == Configuration.CompanyEnum.国投) { item.CompanyMarginHold = 0; } break; case "其他": default: item.MarginCollectionMode = "双方互不收取预付金"; break; } if (item.ClientType == "风险管理子公司") { item.ToCompanyCredit = null; } item.AddFunds = Math.Max(-item.AvailableCash, 0); item.ToClientCredit = item.ToClientCredit.OtcFormatValue(2); item.ClientTradePriceCredit = item.ClientTradePriceCredit.OtcFormatValue(2); item.ClientPositionCredit = item.ClientPositionCredit.OtcFormatValue(2); item.PositionTradePriceOut = item.PositionTradePriceOut.OtcFormatValue(2); item.ToCompanyCredit = item.ToCompanyCredit?.OtcFormatValue(2); item.CompanyTradePriceCredit = item.CompanyTradePriceCredit.OtcFormatValue(2); item.CompanyPositionCredit = item.CompanyPositionCredit.OtcFormatValue(2); item.PositionTradePriceIn = item.PositionTradePriceIn.OtcFormatValue(2); item.OpenBalance = item.OpenBalance.OtcFormatValue(2); item.TodayCashInCashOut = item.TodayCashInCashOut.OtcFormatValue(2); item.TodaySettleEarnings = item.TodaySettleEarnings.OtcFormatValue(2); item.TodayOpenTradePrice = item.TodayOpenTradePrice.OtcFormatValue(2); item.EndBalance = item.EndBalance.OtcFormatValue(2); item.ClientMarginHold = item.ClientMarginHold?.OtcFormatValue(2); item.CompanyMarginHold = item.CompanyMarginHold?.OtcFormatValue(2); item.AvailableCash = item.AvailableCash.OtcFormatValue(2); item.DesirableFund = item.DesirableFund.OtcFormatValue(2); item.AddFunds = item.AddFunds.OtcFormatValue(2); item.PositionValue = item.PositionValue.OtcFormatValue(2); item.MarketValueEquity = item.MarketValueEquity.OtcFormatValue(2); item.PositionPnl = item.PositionPnl?.OtcFormatValue(2); item.PositionPremiumNetCash = item.PositionPremiumNetCash.OtcFormatValue(2); item.ToDayRemainFund = item.ToDayRemainFund.OtcFormatValue(2); item.TodayRemianFundProduct = item.TodayRemianFundProduct.OtcFormatValue(2); item.ClientNumber = client.Number; if (client.ParentId != 0) { var parentClient = DataCacheProvider.GetClientDataSource().GetData(client.ParentId); item.ParentClientNumber = parentClient?.Number; } item.NonCashPerformanceGuaranteesType = formatGuaranteesType((productDict.TryGetValue(client.id, out var remark) ? remark : "")); item.NonCashPerformanceGuaranteesValuation = item.TodayRemianFundProduct.OtcFormatMoney(); if (companycollaterInfo.Count > 0) { var ccInfo = companycollaterInfo.Where(O => O.ClientId == item.ClientId).FirstOrDefault(); item.ChildNonCashPerformanceGuaranteesType = formatGuaranteesType(ccInfo != null ? ccInfo.Comments : ""); } else { item.ChildNonCashPerformanceGuaranteesType = "无"; } var collaterVal = companycollaterInfo.Where(O => O.ClientId == item.ClientId).Sum(O => O.ProductTotalPrice); item.ChildNonCashPerformanceGuaranteesValuation = collaterVal.OtcFormatMoney(); return i; } /// /// /// /// /// 要排除的客户Id /// 要包含的客户Id /// /// /// 查询模式: /// 0:主查询,仅查询出需要报送的交易; /// 1:附加查询,根据客户Id查询出所有匹配的记录,不排序,不分页; /// 默认:0 /// /// private SuperviseReportClientCashModelEx[] QueryList(SuperviseReportReq req, List insidedClientIds, List clientIds, out int count, int queryMode = 0) { #region Sql var sqlSelect = new StringBuilder(); sqlSelect.Append("cb.ClientId as 'ClientId' "); sqlSelect.Append(",c.ParentId as 'ParentId' "); sqlSelect.Append(",'' as 'CustomerNature2' "); sqlSelect.Append(",IFNULL(cb.PositionPremiumNetCash,0) as 'PositionPremiumNetCash' "); sqlSelect.Append(",IFNULL(cb.ToDayRemainFund,0) as 'ToDayRemainFund' "); sqlSelect.Append(",cb.ToDayRemainFund as 'CompanyName' "); sqlSelect.Append(",IFNULL(cb.Credit,0) as 'ToClientCredit' "); sqlSelect.Append(",IFNULL(cb.TodayRemianFundProduct,0) as 'TodayRemianFundProduct' "); sqlSelect.Append(",IFNULL(cb.LastDayRemainFund,0) as 'OpenBalance' "); sqlSelect.Append(",IFNULL(cb.NetFund,0) as 'TodayCashInCashOut' "); sqlSelect.Append(",IFNULL(cb.SettlementBalance, 0) + IFNULL(cb.Coupon, 0) + IFNULL(cb.SwapBalance, 0) as 'TodaySettleEarnings' "); sqlSelect.Append(",IFNULL(cb.OptionPremium, 0) + IFNULL(cb.OptionPremiumSwap, 0) as 'TodayOpenTradePrice' "); sqlSelect.Append(",-cb.PayableMargin as 'ClientMarginHold' "); sqlSelect.Append(",IF(cb.Margin>0,IFNULL(cb.Margin, 0), 0) as 'AddFunds' "); sqlSelect.Append($",IFNULL(IF({PS.Config.IsPVRounded},cb.RoundedPv, cb.Pv), 0) as 'PositionValue' "); sqlSelect.Append(",cb.PositionPnl as 'PositionPnl' "); var sqlStr = new StringBuilder(); sqlStr.Append("SELECT "); sqlStr.Append("{0} "); sqlStr.Append($"FROM `{DbContextFactory.GetClientDbContext(UserInfo).Database.GetDbConnection().Database}`.client c "); sqlStr.Append($"JOIN `{DbContext.Database.GetDbConnection().Database}`.clientbalancedaily cb on c.id = cb.ClientId "); sqlStr.Append($"WHERE cb.BalanceDate = '{req.ValueDate.ToString("yyyy-MM-dd")}' "); if (insidedClientIds?.Any() ?? false) { sqlStr.Append($"AND NOT c.id IN ({string.Join(",", insidedClientIds)}) "); } if (queryMode != 1) { //只查询需要单独报送的客户; sqlStr.Append($"AND (c.IsDocShowParentName is null Or c.IsDocShowParentName <> 1 Or (c.IsDocShowParentName = 1 And c.ParentId <= 0)) "); } if (clientIds.Count > 0) { sqlStr.Append($"AND c.id IN ({string.Join(",", clientIds)}) "); } sqlStr.Append("{1} ;"); var sqlLimit = queryMode == 1 ? "" : $"Order By {req.sidx ?? "id"} {req.sord} LIMIT {req.rows * (req.page - 1)},{req.rows}"; #endregion count = DbContext.Database.GetDbConnection().Query( string.Format(sqlStr.ToString(), "Count(c.id)", ""), commandTimeout: 600 //, //new SqlParameter("@clientDb", DbContextFactory.GetClientDbContext(UserInfo).Database.Connection.Database), //new SqlParameter("@dmsDb", DbContext.Database.Connection.Database) ).ToArray().FirstOrDefault(); LogFactory.GetLogger("客户资金报表2022").Info($"QueryList sql:{sqlStr.ToString()},{sqlSelect.ToString()},{sqlLimit}"); return DbContext.Database.GetDbConnection().Query( string.Format(sqlStr.ToString(), sqlSelect.ToString(), sqlLimit), commandTimeout: 600 //, //new SqlParameter("@clientDb", DbContextFactory.GetClientDbContext(UserInfo).Database.Connection.Database), //new SqlParameter("@dmsDb", DbContext.Database.Connection.Database), //new SqlParameter("@sidx", req.sidx ?? "id"), //new SqlParameter("@sord", req.sord) ).ToArray(); } [NotMapped] class SuperviseReportClientCashModelEx : NewSuperviseReportClientCashModel { public double TodayRemianFundProduct { get; set; } } private string formatGuaranteesType(string creditRemark) { var guaranteesType = ""; if (creditRemark.Contains("商品标准仓单")) { guaranteesType = "商品标准仓单"; } else if (creditRemark.Contains("商品非标仓单")) { guaranteesType = "商品非标仓单"; } else if (creditRemark.Contains("商品现货实物")) { guaranteesType = "商品现货实物"; } else if (creditRemark.Contains("有价证券")) { guaranteesType = "有价证券"; } else { if (creditRemark.Length > 0) { guaranteesType = "其他"; } else { guaranteesType = "无"; } } return guaranteesType; } } }