using BaseOUDAL; using Qdp.Pricing.Library.Common.Interfaces; using System.ComponentModel; using YLErp.BLL; using YLErp.DBModels.Helpers; using YLErp.Model; using YLErp.Modules.CalculationModule; namespace YLErp.Modules.SalesModule { public class SalesCommissionDetailDataService : YLBaseService { public SalesCommissionDetailDataService(OptUserInfo userInfo) : base(userInfo) { } public SalesCommissionDetailDataService(YLBaseService baseService) : base(baseService) { } public SearchListResult FunDunCommissionDetailQueryByClient(BaseSearchReq req, List salesmen, List departments, List clients) { // EF Core 不支持from group select g 用法 //var query = from s in DbContext.SalesCommissionDetail // where s.IsValid && s.TradeCashID != 0 // group s by s.ClientID into g // select g; ////根据客户查询 //if (clients != null && clients.Count > 0) //{ // query = query.Where(o => clients.Contains(o.Key)); //} //var temp = query.ToList(); var query = DbContext.SalesCommissionDetail.Where(b => b.IsValid && b.TradeCashID != 0); if (clients != null && clients.Count > 0) { query = query.Where(o => clients.Contains(o.ClientID)); } var temp = query?.ToList()?.GroupBy(g => g.ClientID)?.ToList(); var commissionGroups = new List(); foreach (var item in temp) { var commissionGroup = new CommissionsDetailGroupByClient { id = item.Key }; item.OrderBy(o => o.TradeID); foreach (var c in item) { double? tempCommission; if (!c.CommissionFixed) { tempCommission = c.CommissionProportionAmount; } else { tempCommission = c.Commission; } commissionGroup.commissionCount++; commissionGroup.commissionAmount = (commissionGroup.commissionAmount == null ? 0 : commissionGroup.commissionAmount) + tempCommission; } var tempSalesmen = new List(); foreach (var com in item) { tempSalesmen.Add(com.SalesmanID); } //根据销售员查询 if (salesmen != null && salesmen.Count > 0) { if (tempSalesmen.Except(salesmen).Count() == tempSalesmen.Distinct().Count()) { continue; } } var men = new SalesmenDataService(OptUser).GetSalesmen(tempSalesmen); //根据部门查询 if (departments != null && departments.Count > 0) { var departmentGroup = men.GroupBy(o => o.Department).Select(o => o.Key); if (departmentGroup.Except(departments).Count() == (departmentGroup).Distinct().Count()) { continue; } } foreach (var man in men) { commissionGroup.salesman += man.Name + "、"; if (commissionGroup.department == null || !commissionGroup.department.Contains(man.Department)) { commissionGroup.department += man.Department + "、"; } } commissionGroup.salesman = commissionGroup.salesman?.TrimEnd('、'); commissionGroup.department = commissionGroup.department?.TrimEnd('、'); commissionGroup.clientname = DataCacheProvider.GetClientDataSource().GetData(commissionGroup.id)?.Name; commissionGroups.Add(commissionGroup); } var ret = commissionGroups.AsQueryable().ToSearchList(req); ret.Sum = new { AmountSum = ret.rows.Sum(o => o.commissionAmount), CountSum = ret.rows.Sum(o => o.commissionCount) }; return ret; } public SearchListResult CommissionDetailQuery(SalesCommissionDetailReq req) { var salesDic = new Lazy>(() => { return DbContext.salesmen.Select(n => new { n.id, n.Name }).ToDictionary(n => n.id, m => m.Name); }); var fliterSalesNames = new List(); var query = from s in DbContext.SalesCommissionDetail where s.IsValid && s.TradeCashID != 0 join t in DbContext.trade on s.TradeID equals t.id select new CommissionDetailByTrade { id = s.id, tradeid = t.id, tradeNumber = t.TradeNumber, tradeStatus = t.TradeStatus, salesmanId = s.SalesmanID, traderName = t.TraderName, clientName = t.ClientName, clientId = t.ClientId.ToString(), buySell = t.BuySell, tradeDate = t.TradeDate, tradeType = t.TradeType, structureType = t.StructureType, StockEqvNotional = t.OriginalStockEqvNotional, TradeSinglePrice = t.TradeType == "现金流交易" ? (t.TradePrice ?? 0) : (t.TradeSinglePrice ?? 0), commissionAmout = s.CommissionFixed ? s.Commission : s.CommissionProportionAmount, CommissionCalcu = s.CommissionFixed ? "" : s.CommissionCalcu }; if (!string.IsNullOrWhiteSpace(req.salesmanIds)) { var ids = req.salesmanIds.Split(',').Select(O => int.TryParse(O, out int id) ? id : 0).ToList(); query = query.Where(o => ids.Contains(o.salesmanId)); } if (!string.IsNullOrWhiteSpace(req.clientIds)) { var clients = req.clientIds.Split(',').ToList(); query = query.Where(o => clients.Contains(o.clientId)); } if (!string.IsNullOrWhiteSpace(req.TradeNumber)) { query = query.Where(o => o.tradeNumber.Contains(req.TradeNumber)); } if (req.tradeDateStart != null) { query = query.Where(o => o.tradeDate >= req.tradeDateStart); } if (req.tradeDateEnd != null) { query = query.Where(o => o.tradeDate <= req.tradeDateEnd); } var temp = query.ToList().OrderBy(o => o.tradeid); if (temp.Count() == 0) { return null; } var line = new CommissionDetailByTrade(); var result = new List(); foreach (var item in temp) { line = new CommissionDetailByTrade() { id = item.id, tradeid = item.tradeid, buySell = item.buySell, clientId = item.clientId, clientName = item.clientName, commissionAmout = item.commissionAmout, StockEqvNotional = item.StockEqvNotional, TradeSinglePrice = item.TradeSinglePrice, structureType = item.structureType, tradeDate = item.tradeDate, tradeNumber = item.tradeNumber, traderName = item.traderName, tradeStatus = item.tradeStatus, tradeType = item.tradeType, CommissionCalcu = item.CommissionCalcu, }; if (salesDic.Value.TryGetValue(item.salesmanId, out var name)) { line.salesmanName = name; } result.Add(line); //if (int.TryParse(item.salesmanName, out var id) && id > 0 // && salesDic.Value.TryGetValue(id, out var name) && !string.IsNullOrWhiteSpace(name)) //{ // line.salesmanName = name; //} } //if (line != null && !string.IsNullOrWhiteSpace(line.salesmanName)) //{ // line.salesmanName = line.salesmanName.TrimEnd('、'); //} //if (JudgeSalesmanName(line, fliterSalesNames)) //{ // result.Add(line); //} var ret = result.AsQueryable().ToSearchList(req); return ret; } /// /// 移除交易提成 /// /// /// public void RemoveTradeCommissionDetail(int tradeId, bool useSave = true) { //删除原来的数据 var oldCommissionsDetail = DbContext.SalesCommissionDetail.Where(o => o.TradeID == tradeId); if (oldCommissionsDetail.Any()) oldCommissionsDetail.ToList().ForEach(l => { l.IsValid = false; l.TradeCashID = l.TradeCashID == 0 ? -1 : l.TradeCashID;//这个操作是防止计算提成的时候,查到这条记录; }); if (useSave) { DbContext.SaveChanges(); } } /// /// 保存交易提成明细 /// public int SaveTradeCommissionDetail(int tradeId, int? ClientId, double? Commission, bool? CommissionFixed, IEnumerable SalesIds, bool isValid, bool delOldData = true) { if (tradeId < 0) { throw new ServiceException("参数错误:" + nameof(tradeId)); } if (ClientId < 1) { throw new ServiceException("参数错误:" + nameof(ClientId)); } if (Commission < 0) { throw new ServiceException("提成金额 必须大于等于0"); } if (delOldData) { //删除原来的数据 RemoveTradeCommissionDetail(tradeId, false); } //如果销售员,销售提成没了,那也没必要新增了 if (!SalesIds.Any()) { DbContext.SaveChanges(); return 0; } if (!Commission.HasValue || Commission == 0) { DbContext.SaveChanges(); return 0; } var saleCount = SalesIds.Count(); var commissions = SalesIds.Select(n => new SalesCommissionDetail { ClientID = (int)ClientId, Commission = Commission.Value / saleCount, CommissionFixed = (bool)CommissionFixed, OptDate = OptDate, SalesmanID = n, TradeID = tradeId, IsValid = isValid }).ToArray(); DbContext.SalesCommissionDetail.AddRange(commissions); return DbContext.SaveChanges(); } public void CalcuSalesCommissionDetail(trade_cash trade_Cash) { var trade = DbContext.trade.Where(l => l.id == trade_Cash.TradeId).FirstOrDefault(); if (trade == null) return; var tradeClone = trade.Clone(); var salesCommissions = DbContext.SalesCommissionDetail.Where(x => x.TradeID == trade.id && x.TradeCashID == 0 && !x.CommissionFixed).ToList(); if (!salesCommissions.Any()) return; if (!ConsTrade.TradeTypesForHedge.Contains(trade.TradeType)) { double? nowPrice = tradeClone.SpotPrice; //计算全额payoff var notional = tradeClone.Notional; tradeClone.Notional = tradeClone.OriginalNotional.Value;//原始份额不应该为Null FangDunGetPayoff(tradeClone, Convert.ToDouble(nowPrice), out var amount); tradeClone.Notional = notional; //计算全额时间价值 var timePrice = (tradeClone.TradeSinglePrice.GetValueOrDefault() * tradeClone.OriginalNotional - (amount <= 0 ? 0 : amount)); //把全额时间价值换成当前了结部分的时间价值 timePrice = timePrice < 0 ? 0 : timePrice * trade_Cash.UnwindPercentRate; //实际存续天数 var ActualExistenceDate = trade_Cash.ValueDate.Subtract(Convert.ToDateTime(trade.TradeDate)).TotalDays; ActualExistenceDate = ActualExistenceDate < 1 ? 1 : ((int)ActualExistenceDate); // var ActualExistenceDate = QdpModule.QdpCalendarHelper.AllBizDays(Convert.ToDateTime(trade.TradeDate), Convert.ToDateTime(tc.ValueDate)).Count; //约定存续天数 var AgreedExistenceDate = Convert.ToDateTime(trade.ExerciseDate).Subtract(Convert.ToDateTime(trade.TradeDate)).TotalDays; AgreedExistenceDate = AgreedExistenceDate < 1 ? 1 : ((int)AgreedExistenceDate); // var AgreedExistenceDate = QdpModule.QdpCalendarHelper.AllBizDays(Convert.ToDateTime(trade.TradeDate), Convert.ToDateTime(trade.ExerciseDate)).Count; foreach (var commission in salesCommissions) { //计算 提成金额 公式 var commissionProportionAmount = timePrice * ActualExistenceDate / AgreedExistenceDate * commission.Commission; var commissionCalcu = $"{timePrice}*{ActualExistenceDate}/{AgreedExistenceDate}*{commission.Commission}"; commission.TradeCashID = trade_Cash.id; commission.CommissionCalcu = commissionCalcu; commission.CommissionProportionAmount = commissionProportionAmount; commission.IsValid = true; } if (!trade_Cash.IsLastAction) { SaveTradeCommissionDetail(trade.id, trade.ClientId, salesCommissions.Sum(O => O.Commission), false, salesCommissions.Select(O => O.SalesmanID), false, false); } DbContext.SaveChanges(); } } public static void FangDunGetPayoff(trade trade, double price, out double amount) { amount = 0; string fixings = null; DateTime? finalPriceSettleDate = null; tradeBLL.SetFieldsByTradeType(trade); var isAsianOption = trade.TradeType == "亚式期权"; if (isAsianOption && trade.trade_asian_option == null) { throw new ServiceException("缺少亚式期权交易信息"); } if (isAsianOption) { var startDate = trade.trade_asian_option.AveragingPeriodStartDate ?? trade.TradeDate.Value; var settleDate = finalPriceSettleDate ?? valuedateBLL.ValueDate; //亚式浮动行权价并且行权价有输入值的情况下 if (trade.trade_asian_option.StrikeType == "Floating") { //均价起算日大于结算日的情况下取计值日 if (startDate > settleDate) { startDate = settleDate; } fixings = $"{startDate:yyyy-MM-dd},{price}"; } else { //均价起算日大于结算日的情况下取不到fixing则直接赋值 if (startDate > settleDate) { fixings = $"{settleDate:yyyy-MM-dd},{price}"; } else { fixings = AsianOptionFixingService.GetFixingString(settleDate, trade); if (string.IsNullOrEmpty(fixings)) { //取不到fixing则直接赋值 fixings = $"{settleDate:yyyy-MM-dd},{price}"; } } } } var QdpTrade = TradeCalcHelper.GetQdpTrade(trade, finalPriceSettleDate, fixings); if (QdpTrade != null && QdpTrade.Instrument != null && QdpTrade.Instrument is IOption opt) { var value = 1; if (trade.BuySell == "卖出") { value = -1; } var cashFlows = opt.GetPayoff(new double[] { price }); if (cashFlows != null && (cashFlows[0].PaymentAmount == 0 || double.IsNaN(cashFlows[0].PaymentAmount))) { amount = TradeHelper.GetAmountByPaymentAmount(0, trade.PrincipalSum(), trade.BuySell) * value; } else { //cashFlows[0].PaymentAmount包含了买卖方向的处理了 amount = TradeHelper.GetAmountByPaymentAmount(cashFlows[0].PaymentAmount, trade.PrincipalSum(), trade.BuySell) * value; } } } } public class SalesCommissionDetailReq : BaseSearchReq { /// /// 销售员ID /// public string salesmanIds { get; set; } /// /// 客户ID /// public string clientIds { get; set; } /// /// 交易编号 /// public string TradeNumber { get; set; } /// /// 交易日期始 /// public DateTime? tradeDateStart { get; set; } /// /// 交易日期末 /// public DateTime? tradeDateEnd { get; set; } } public class CommissionsDetailGroupByClient { public int id; [DisplayName("销售员")] public string salesman { get; set; } [DisplayName("部门")] public string department { get; set; } [DisplayName("客户名称")] public string clientname { get; set; } [DisplayName("提成金额")] public double? commissionAmount { get; set; } [DisplayName("交易数目")] public int commissionCount { get; set; } } }