using System; using System.Collections.Generic; using System.Linq; using System.Data; using MySystem.Models.Main; using Library; using System.Threading; using Microsoft.Extensions.Hosting; using System.Threading.Tasks; using LitJson; using MySystem.Models; namespace MySystem { public class ProfitHelper { public readonly static ProfitHelper Instance = new ProfitHelper(); private ProfitHelper() { } #region 消费队列(执行消费退款金额的统计) public void StartListenTrade() { Thread th = new Thread(StartListenTradeDo); th.IsBackground = true; th.Start(); } public void StartListenTradeDo() { while (true) { string orderidstring = RedisDbconn.Instance.RPop("ConsumerOrdersHd:Divi:1:List"); if (!string.IsNullOrEmpty(orderidstring)) { ReturnStat(orderidstring, 1); } else { Thread.Sleep(60000); } } } public void StartListenWxTrade() { Thread th = new Thread(StartListenWxTradeDo); th.IsBackground = true; th.Start(); } public void StartListenWxTradeDo() { while (true) { string orderidstring = RedisDbconn.Instance.RPop("ConsumerOrdersHd:Divi:2:List"); if (!string.IsNullOrEmpty(orderidstring)) { ReturnStat(orderidstring, 2); } else { Thread.Sleep(10000); } } } public void ReturnStat(string orderidstring, int PayMode) { function.WriteLog("开始返现:" + orderidstring, "返现逻辑日志"); int OrderId = int.Parse(function.CheckInt(orderidstring)); WebCMSEntities db = new WebCMSEntities(); using (var tran = db.Database.BeginTransaction()) { try { ConsumerOrders order = db.ConsumerOrders.FirstOrDefault(m => m.Id == OrderId); if (order != null) { decimal PayMoney = order.PayMoney; int MerchantId = order.MerchantId; function.WriteLog("MerchantId:" + MerchantId, "返现逻辑日志"); MerchantInfo merchant = db.MerchantInfo.FirstOrDefault(m => m.Id == MerchantId); if (merchant != null) { int UserId = merchant.UserId; List customTagSets = db.CustomTagSet.ToList(); //获取公用配置参数集和 //获取参数 CustomTagSet profitPercentSet = customTagSets.FirstOrDefault(m => m.Tags == "CusumerProfitPercent") ?? new CustomTagSet(); decimal profitPercent = decimal.Parse(function.CheckNum(profitPercentSet.Contents)); //基于收款金额的总分润比例; CustomTagSet cusumerFeePercentSet = customTagSets.FirstOrDefault(m => m.Tags == "CusumerFeePercent") ?? new CustomTagSet(); decimal cusumerFeePercent = decimal.Parse(function.CheckNum(cusumerFeePercentSet.Contents)); //费率; CustomTagSet minProfitSet = customTagSets.FirstOrDefault(m => m.Tags == "MinProfit") ?? new CustomTagSet(); decimal minProfit = decimal.Parse(function.CheckNum(minProfitSet.Contents)); //最小分润值; MerchantParamSet set = Newtonsoft.Json.JsonConvert.DeserializeObject(order.SeoDescription); int DiviPersons = set.DiviPersons; //单笔订单分红人数 decimal DiviPercent = set.DiviPercent; //单人最大分红比例 int ProfitDays = set.ProfitDays; //分红期限(天) decimal GetPercent = set.GetPercent / 100; //商家实收比例 decimal MinPayMoney = set.MinPayMoney; //订单参与门槛 int IsAll = set.IsAll; //是否收全额 // decimal TotalActual = 0; if (IsAll == 0 && PayMoney >= MinPayMoney && GetPercent < 1) { function.WriteLog("活动开启", "返现逻辑日志"); // PayMoney * (1 - 0.1 - 0.0038 - 0.01); decimal DiviMoney = PayMoney * (1 - GetPercent - cusumerFeePercent - profitPercent); if (DiviMoney > 0) { function.WriteLog("返现队列开始", "返现逻辑日志"); RedisDbconn.Instance.AddRightList("ConsumerOrdersHd:Divi:" + PayMode + ":" + order.MerchantId, order); order.ReturnFlag = 1; db.SaveChanges(); DiviMoney = DiviMoney / DiviPersons; DiviMoney = Math.Round(DiviMoney, 2); List deletes = new List(); long CurDiviPersons = DiviPersons; long QueueCount = RedisDbconn.Instance.Count("ConsumerOrdersHd:Divi:" + PayMode + ":" + MerchantId); long CurQueueCount = QueueCount; if (CurDiviPersons >= CurQueueCount) { CurDiviPersons = CurQueueCount; } if (DiviPersons < QueueCount) { QueueCount = DiviPersons; } // 减去自己付的订单 List orderids = new List(); function.WriteLog("人数:" + CurDiviPersons, "返现逻辑日志"); while (CurDiviPersons > 0) { ConsumerOrders suborder = RedisDbconn.Instance.RPopLPush("ConsumerOrdersHd:Divi:" + PayMode + ":" + MerchantId, "ConsumerOrdersHd:Divi:" + PayMode + ":" + MerchantId); if (suborder != null) { decimal TmpCurDivi = suborder.CurDivi; function.WriteLog("返现对象订单:" + suborder.Id, "返现逻辑日志"); MerchantParamSet subset = Newtonsoft.Json.JsonConvert.DeserializeObject(suborder.SeoDescription); int subProfitDays = subset.ProfitDays; //分红期限(天) bool IsOut = suborder.UpdateDate.Value.AddDays(subProfitDays) < DateTime.Now ? true : false; if (suborder.CurDivi < suborder.MaxDivi && suborder.MaxDivi - suborder.CurDivi >= 0.01M && !IsOut) { function.WriteLog("没出局:" + suborder.CurDivi + "--" + suborder.MaxDivi, "返现逻辑日志"); //如果没过期并且当前退款金额没超过最大退款金额,就执行 decimal GetMoney = suborder.MaxDivi - suborder.CurDivi; if (GetMoney >= DiviMoney) { GetMoney = DiviMoney; } function.WriteLog("GetMoney:" + GetMoney, "返现逻辑日志"); if (GetMoney > minProfit) { suborder.CurDivi += GetMoney; MerchantAddInfo merchantAdd = db.MerchantAddInfo.FirstOrDefault(m => m.Id == suborder.MerchantId) ?? new MerchantAddInfo(); //聚合支付退款 bool BackStatus = false; decimal RefundAmount = GetMoney * 100; RefundAmount = Math.Round(RefundAmount, 2); if(!orderids.Contains(suborder.Id)) { function.WriteLog("请求退款接口", "返现逻辑日志"); string RefundNo = "HDTK" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + function.get_Random(8); var info = HaoDaHelper.Instance.AggregatedPayRefund(merchantAdd.OutMchtNo, merchantAdd.StoreNo, RefundNo, suborder.OrderNo, RefundAmount.ToString("f0")); if(info.Contains("\"resultCode\":\"1\"") && info.Contains("\"tradeStatus\":\"2\"")) { db.ConsumerProfit.Add(new ConsumerProfit() { CreateDate = DateTime.Now, ConsumerId = suborder.ConsumerId, MerchantId = suborder.MerchantId, OrderId = suborder.Id, GetMoney = Math.Round(GetMoney, 2), QueryCount = PayMode, Sort = OrderId, SeoTitle = suborder.OrderNo, SeoKeyword = suborder.PayMoney.ToString(), SeoDescription = RefundNo, }); db.SaveChanges(); BackStatus = true; } function.WriteLog("接口返回:" + info, "返现逻辑日志"); orderids.Add(suborder.Id); } if(BackStatus) { merchant.ActCurrentAmount += Math.Round(GetMoney, 2); //活动已返金额 db.SaveChanges(); function.WriteLog(suborder.CurDivi + ":" + suborder.MaxDivi, "返现逻辑日志"); if (suborder.CurDivi < suborder.MaxDivi) { function.WriteLog("返现未达最大值继续", "返现逻辑日志"); // RedisDbconn.Instance.AddList("ConsumerOrdersHd:Divi:" + PayMode + ":" + MerchantId, suborder); RedisDbconn.Instance.SetList("ConsumerOrdersHd:Divi:" + PayMode + ":" + MerchantId, 0, suborder); RedisDbconn.Instance.AddList("ConsumerOrdersSetDiviHd", "{\"OrderId\":\"" + suborder.Id + "\",\"DiviAmt\":\"" + suborder.CurDivi + "\"}"); } else { suborder.CurDivi = TmpCurDivi; function.WriteLog("返现达最大值,出局", "返现逻辑日志"); ConsumerOrders editOrder = db.ConsumerOrders.FirstOrDefault(m => m.Id == suborder.Id); if (editOrder != null) { editOrder.ReturnFlag = 0; db.SaveChanges(); RedisDbconn.Instance.AddList("ConsumerOrdersSetDiviHd", "{\"OrderId\":\"" + suborder.Id + "\",\"DiviAmt\":\"" + suborder.MaxDivi + "\"}"); } RedisDbconn.Instance.DelFromList("ConsumerOrdersHd:Divi:" + PayMode + ":" + MerchantId, suborder); } } Thread.Sleep(1000); } } else { //否者计算人数不计入退款名额 suborder.CurDivi = TmpCurDivi; function.WriteLog("返现达最大值,出局", "返现逻辑日志"); ConsumerOrders editOrder = db.ConsumerOrders.FirstOrDefault(m => m.Id == suborder.Id); if (editOrder != null) { editOrder.ReturnFlag = 0; db.SaveChanges(); RedisDbconn.Instance.AddList("ConsumerOrdersSetDiviHd", "{\"OrderId\":\"" + suborder.Id + "\",\"DiviAmt\":\"" + suborder.MaxDivi + "\"}"); } RedisDbconn.Instance.DelFromList("ConsumerOrdersHd:Divi:" + PayMode + ":" + MerchantId, suborder); CurDiviPersons += 1; function.WriteLog("出局:CurDiviPersons:" + CurDiviPersons, "返现逻辑日志"); } } CurDiviPersons -= 1; QueueCount = RedisDbconn.Instance.Count("ConsumerOrdersHd:Divi:" + PayMode + ":" + MerchantId); function.WriteLog("当前队列数量:" + QueueCount, "返现逻辑日志"); if (QueueCount == 0) { CurDiviPersons = 0; } } function.WriteLog("返现队列结束", "返现逻辑日志"); } } } } tran.Commit(); } catch (Exception ex) { LogHelper.Instance.WriteLog(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":" + ex.ToString(), "分红返现异常"); tran.Rollback(); RedisDbconn.Instance.AddList("ConsumerProfitCheck", orderidstring); } } db.Dispose(); function.WriteLog("结束返现:" + orderidstring + "\n\n\n", "返现逻辑日志"); } #endregion #region 分润 public void StartListenProfit() { Thread th = new Thread(StartListenProfitDo); th.IsBackground = true; th.Start(); } public void StartListenProfitDo() { while(true) { if(DateTime.Now.Day < 10 && DateTime.Now.Hour > 2 && DateTime.Now.Hour < 23) { try { DoProfit(); } catch(Exception ex) { LogHelper.Instance.WriteLog(DateTime.Now.ToString() + "\n" + ex.ToString(), "来客吧分润异常"); } Thread.Sleep(600000); } else { Thread.Sleep(3600000); } } } //分润算法 public void DoProfit() { string TradeMonth = DateTime.Now.AddMonths(-1).ToString("yyyyMM"); string check = function.ReadInstance("/ProfitFlag/" + TradeMonth + ".txt"); if(!string.IsNullOrEmpty(check)) { return; } function.WritePage("/ProfitFlag/", TradeMonth + ".txt", DateTime.Now.ToString()); Models.KxsMain.WebCMSEntities kxsdb = new Models.KxsMain.WebCMSEntities(); WebCMSEntities dbnew = new WebCMSEntities(); DataTable dt = CustomerSqlConn.dtable("select IsAct,UserId,sum(TotalAmount) from UserAmountSummary where TradeMonth='" + TradeMonth + "' and SeoTitle='self' group by IsAct,UserId", AppConfig.Base.SqlConnStr); foreach(DataRow dr in dt.Rows) { int UserId = int.Parse(dr["UserId"].ToString()); bool IsActive = dr["IsAct"].ToString() == "1"; decimal TotalAmount = decimal.Parse(dr[2].ToString()); List users = new List(); int TopUserId = 0; //顶级创客Id Models.KxsMain.Users us = kxsdb.Users.FirstOrDefault(a => a.Id == UserId); if (us != null) { string uidstring = us.Id.ToString(); if (!string.IsNullOrEmpty(us.ParentNav)) { uidstring = us.ParentNav.Trim(',').Replace(",,", ",") + "," + uidstring; string[] parents = us.ParentNav.Trim(',').Replace(",,", ",").Split(','); if(parents.Length > 1) { TopUserId = int.Parse(function.CheckInt(parents[1])); } else { TopUserId = int.Parse(function.CheckInt(parents[0])); } } string[] uidlist = uidstring.Split(','); Array.Reverse(uidlist); foreach (string uidstr in uidlist) { int puid = int.Parse(function.CheckInt(uidstr)); Models.KxsMain.Users pus = kxsdb.Users.FirstOrDefault(a => a.Id == puid); if (pus != null) { users.Add(new ProfitUsers() { UserId = pus.Id, MakerCode = pus.MakerCode, RealName = pus.RealName, UserNav = pus.ParentNav, UserLevel = pus.UserLevel, CreateDate = pus.CreateDate.Value, }); } } } Models.KxsMain.Users topUser = kxsdb.Users.FirstOrDefault(a => a.Id == TopUserId) ?? new Models.KxsMain.Users(); LogHelper.Instance.WriteLog("---UserId:" + UserId + ";TotalAmount:" + TotalAmount + ";", "来客吧分润日志"); List list = new List(); list = StartProft(TotalAmount, 1, users, IsActive); LogHelper.Instance.WriteLog("---list:" + list.Count + ";", "来客吧分润日志"); try { foreach (ProfitResult sub in list) { int ProfitType = sub.UserId == UserId ? 0 : 1; ProfitRewardRecord editprofitrecord = dbnew.ProfitRewardRecord.FirstOrDefault(m => m.UserId == sub.UserId && m.BrandId == 1 && m.ProfitType == ProfitType && m.TradeMonth == TradeMonth); if (editprofitrecord == null) { editprofitrecord = dbnew.ProfitRewardRecord.Add(new ProfitRewardRecord() { CreateDate = DateTime.Now, UserId = sub.UserId, //创客 BrandId = 1, //品牌 ProfitType = ProfitType, //创客分润类型 TradeMonth = TradeMonth, //交易月 TopUserId = TopUserId, //顶级创客 CreateMan = sub.MakerCode, //创客编号 UpdateMan = topUser.MakerCode, //顶级编号 SeoTitle = sub.RealName, //创客姓名 SeoKeyword = topUser.RealName, //创客姓名 }).Entity; dbnew.SaveChanges(); string RecordNo = "KPM"; int RecordId = editprofitrecord.Id; string RecordIdString = RecordId.ToString(); for (int i = 0; i < 14 - RecordId.ToString().Length; i++) { RecordIdString = "0" + RecordIdString; } RecordNo += RecordIdString; editprofitrecord.RecordNo = RecordNo; dbnew.SaveChanges(); } if(IsActive) { editprofitrecord.CreditTradeAmt += TotalAmount; editprofitrecord.CreditTradeProfit += sub.Money; } else { editprofitrecord.TradeAmt += TotalAmount; editprofitrecord.TradeProfit += sub.Money; } dbnew.SaveChanges(); } dbnew.SaveChanges(); } catch (Exception ex) { LogHelper.Instance.WriteLog(ex.ToString(), "分润异常"); } } dbnew.Dispose(); kxsdb.Dispose(); } #endregion #region 分润算法 public List StartProft(decimal TotalAmount, int LevelKindId, List users, bool IsActive = true) { LogHelper.Instance.WriteLog("\n\nTotalAmount:" + TotalAmount + ";", "来客吧分润日志"); string Month = DateTime.Now.AddMonths(-1).ToString("yyyyMM"); WebCMSEntities db = new WebCMSEntities(); List levels = db.UserLevelSet.ToList(); List result = new List(); ProfitObjects obj = db.ProfitObjects.FirstOrDefault(); if (obj.Status == 1) //判断分润是否开启 { int maxLevel = obj.MaxLevel; //最大等级 int maxFloor = obj.MaxFloor; //最大层级 decimal diffLevelProfit = 0; //等级级差 ProfitObjectLevels maxlevel = db.ProfitObjectLevels.FirstOrDefault(m => m.Id == 9) ?? new ProfitObjectLevels(); //获取最高等级参数 decimal maxPercent = IsActive ? maxlevel.DebitPercents : maxlevel.Percents; LogHelper.Instance.WriteLog("maxPercent:" + maxPercent + ";", "来客吧分润日志"); decimal maxLevelProfit = TotalAmount * maxPercent; LogHelper.Instance.WriteLog("maxLevelProfit:" + maxLevelProfit + ";", "来客吧分润日志"); maxLevelProfit = PublicFunction.NumberFormat(maxLevelProfit); LogHelper.Instance.WriteLog("maxLevelProfit:" + maxLevelProfit + ";", "来客吧分润日志"); // decimal diffDiviProfit = 0; //分红级差 int curLevel = 0; //当前层级的会员等级 for (int curFloor = 1; curFloor <= users.Count; curFloor++) { ProfitUsers user = new ProfitUsers(); if (curFloor <= users.Count) { user = users[curFloor - 1]; } SubUser selfUser = GetUser(user.UserId, Month) ?? new SubUser(); int UserLevel = GetUserLevel(selfUser); //当前会员等级 //判断当前创客是否有直推的激活机具,并且在活动时间内 if (curLevel == maxLevel) { break; } if (UserLevel <= maxLevel && UserLevel >= curLevel) { ProfitObjectLevels objlevel = db.ProfitObjectLevels.FirstOrDefault(m => m.Id == UserLevel); //获取当前等级参数 if (objlevel != null) { decimal getLevelProfit = 0; //等级分润 UserProfitSet profitSet = new UserProfitSet(); decimal profitPercent = IsActive ? objlevel.DebitPercents : objlevel.Percents; LogHelper.Instance.WriteLog("money:" + UserLevel + ":" + profitPercent + ";", "来客吧分润日志"); if (profitPercent > 0) { decimal profitTmp = TotalAmount * profitPercent; getLevelProfit += profitTmp; LogHelper.Instance.WriteLog("money:" + UserLevel + ":" + profitTmp + ";", "来客吧分润日志"); } decimal money = getLevelProfit; getLevelProfit -= diffLevelProfit; if (objlevel.LevelDiff == 1) //判断是否有级差 { diffLevelProfit = money; } if (getLevelProfit >= obj.MinProfitVal) { result.Add(new ProfitResult() { UserId = user.UserId, MakerCode = user.MakerCode, RealName = user.RealName, UserNav = user.UserNav, Money = PublicFunction.NumberFormat(getLevelProfit), ProfitRate = profitSet.ProfitRate, ProfitPercent = profitSet.ProfitPercent, AddOrSubRate = profitSet.AddOrSubRate, ProfitRateBase = profitSet.ProfitRateBase, }); LogHelper.Instance.WriteLog("money:" + UserLevel + ":" + PublicFunction.NumberFormat(getLevelProfit) + ";", "来客吧分润日志"); } } } if(curLevel < UserLevel) { curLevel = UserLevel; } } } db.Dispose(); return result; } public SubUser GetUser(int UserId, string Month) { SubUser user = new SubUser(); DataTable dt = GetDataTable("select * from Users" + Month + " where Id=" + UserId); if(dt.Rows.Count > 0) { user.Id = int.Parse(dt.Rows[0]["Id"].ToString()); user.ParentUserId = int.Parse(dt.Rows[0]["ParentUserId"].ToString()); user.ParentNav = dt.Rows[0]["ParentNav"].ToString(); user.UserLevel = int.Parse(dt.Rows[0]["UserLevel"].ToString()); user.PreUserLevel = int.Parse(dt.Rows[0]["PreUserLevel"].ToString()); user.PreLeaderLevel = int.Parse(dt.Rows[0]["PreLeaderLevel"].ToString()); user.PreOpLevel = int.Parse(dt.Rows[0]["PreOpLevel"].ToString()); } return user; } public int GetUserLevel(SubUser user) { int level = user.UserLevel; if(user.PreUserLevel > level) level = user.PreUserLevel; if(user.PreLeaderLevel > level) level = user.PreLeaderLevel; if(user.PreOpLevel > level) level = user.PreOpLevel; return level; } public DataTable GetDataTable(string sqlstr) { DataTable dt = CustomerSqlConn.dtable(sqlstr, Library.ConfigurationManager.AppSettings["KxsStatSqlConnStr"].ToString()); return dt; } #endregion public void StartSetDivi() { Thread th = new Thread(StartSetDiviDo); th.IsBackground = true; th.Start(); } public void StartSetDiviDo() { while (true) { string content = RedisDbconn.Instance.RPop("ConsumerOrdersSetDiviHd"); if (!string.IsNullOrEmpty(content)) { SetDivi(content); } else { Thread.Sleep(10000); } } } public void SetDivi(string content) { try { JsonData jsonObj = JsonMapper.ToObject(content); int orderId = int.Parse(function.CheckInt(jsonObj["OrderId"].ToString())); decimal diviAmt = decimal.Parse(function.CheckNum(jsonObj["DiviAmt"].ToString())); WebCMSEntities db = new WebCMSEntities(); ConsumerOrders order = db.ConsumerOrders.FirstOrDefault(m => m.Id == orderId); if(order != null) { order.CurDivi = diviAmt; db.SaveChanges(); } db.Dispose(); } catch(Exception ex) { function.WriteLog(DateTime.Now.ToString() + "\n" + ex.ToString(), "设置订单当前返现金额异常"); } } } }