using BBWYB.Common.Extensions; using BBWYB.Common.Log; using BBWYB.Common.Models; using BBWYB.Server.Model; using BBWYB.Server.Model.Db; using BBWYB.Server.Model.Db.BBWY; using BBWYB.Server.Model.Dto; using FreeSql; using Newtonsoft.Json; using Yitter.IdGenerator; namespace BBWYB.Server.Business { public class SkuOptimizationBusiness : BaseBusiness, IDenpendency { private FreeSqlMultiDBManager fsqlManager; private VenderBusiness venderBusiness; private TimeLimitRules timeLimitRules; public SkuOptimizationBusiness(IFreeSql fsql, NLogManager nLogManager, IIdGenerator idGenerator, FreeSqlMultiDBManager fsqlManager, VenderBusiness venderBusiness, TimeLimitRules timeLimitRules) : base(fsql, nLogManager, idGenerator) { this.fsqlManager = fsqlManager; this.venderBusiness = venderBusiness; this.timeLimitRules = timeLimitRules; } private (User user, Userdepartment department) GetYiJiaDepartmentByUserId(string userId) { var user = fsqlManager.MDSfsql.Select(userId).ToOne(); if (user == null) throw new BusinessException("用户不存在"); if (string.IsNullOrEmpty(user.DepartmentId)) throw new BusinessException("该用户没有归属部门"); var department = fsqlManager.MDSfsql.Select(user.DepartmentId).ToOne(); if (department == null) throw new BusinessException("部门不存在"); if (department.ParentDepartmentId != "1760971468360912896") throw new BusinessException("该用户所在部门不属于议价组"); return (user, department); } public Enums.TriggerOptimizationReason? GetOptimizationReason(SpuTotalSaleInfo s) { if (s.IsFirstPurchaseCompleted == false) return Enums.TriggerOptimizationReason.首次采购; if (s.IsFirstPurchaseCompleted == true && s.IsFirstOptimizationCompleted == false && s.ItemCount - s.FirstPurchaseCompletedItemCount >= 20) return Enums.TriggerOptimizationReason.首次优化; if (s.IsFirstOptimizationCompleted == true && s.LastOptimizationItemCount != 0 && s.ItemCount * 1.0 / s.LastOptimizationItemCount >= 2) return Enums.TriggerOptimizationReason.再次优化; return null; } /// /// 良库预警 /// /// /// public void LKInventoryAlertNotification(BatchLKInventoryAlertRequest request) { nLogManager.Default().Info($"LKInventoryAlertNotification {JsonConvert.SerializeObject(request)}"); #region 确定JDSKU对应的拳探SKU和拳探SPU var jdSkuIdList = request.Items.Select(x => x.Sku).Distinct().ToList(); var jdqtskuList = fsqlManager.BBWYCfsql.Select() .Where(ps1 => ps1.ShopId == request.ShopId && jdSkuIdList.Contains(ps1.SkuId)) .GroupBy(ps1 => ps1.SkuId) .WithTempQuery(g => new { MaxId = g.Max(g.Value.Id) }) .From() .InnerJoin((ps1, ps2) => ps1.MaxId == ps2.Id) .ToList((ps1, ps2) => ps2); var qtSkuIdList = jdqtskuList.Select(x => x.PurchaseSkuIds).Distinct().ToList(); var productSkuList = fsql.Select(qtSkuIdList).ToList(); var productIdList = productSkuList.Select(ps => ps.ProductId).Distinct().ToList(); var spuTotalInfoList = fsql.Select().Where(spi => productIdList.Contains(spi.ProductId)).ToList(); #endregion //查询已存在未结束的优化任务 var dbSkuOptimizationTaskList = fsql.Select() .Where(t => t.ShopId == request.ShopId && t.IsOptimizationCompleted == false && qtSkuIdList.Contains(t.SkuId)) .ToList(); //优化历史 var dbSkuOptimizationHistoryList = fsql.Select() .Where(s1 => s1.ShopId == request.ShopId && qtSkuIdList.Contains(s1.SkuId)) .GroupBy(s1 => s1.SkuId) .WithTempQuery(g => new { MaxId = g.Max(g.Value.Id) }) .From() .InnerJoin((s1, s2) => s1.MaxId == s2.Id) .ToList((s1, s2) => s2); #region DB Operation var insertSkuOptimizationTaskList = new List(); var insertSkuOptimizationChildTaskList = new List(); var insertTimeLimitTaskList = new List(); #endregion var belongShop = venderBusiness.GetShopList(request.ShopId).FirstOrDefault(); if (belongShop == null) throw new BusinessException("店铺不存在"); foreach (var reqItem in request.Items) { var qtsku = jdqtskuList.FirstOrDefault(x => x.SkuId == reqItem.Sku); if (qtsku == null) continue; var qtskuId = qtsku.PurchaseSkuIds; //拳探skuId if (dbSkuOptimizationTaskList.Any(s => s.SkuId == qtskuId)) //过滤未结束的sku continue; var productSku = productSkuList.FirstOrDefault(ps => ps.Id == qtskuId); if (productSku == null) continue; var spuTotalInfo = spuTotalInfoList.FirstOrDefault(psi => psi.ProductId == productSku.ProductId); //spu销量 if (spuTotalInfo == null) continue; var reason = GetOptimizationReason(spuTotalInfo); //过滤不需要优化的spu if (reason == null) continue; var skuOptimizationHistory = dbSkuOptimizationHistoryList.FirstOrDefault(h => h.SkuId == qtskuId); #region 创建待议价任务 var skuOptimizationTask = new SkuOptimizationTask() { Id = idGenerator.NewLong(), BelongShopName = belongShop.ShopName, ShopId = productSku.ShopId, CompletionTime = null, CreateTime = DateTime.Now, IsOptimizationCompleted = false, IsPurchasementCompleted = false, JDSkuId = reqItem.Sku, PreItemCount = reqItem.PreItemCount, ProductId = productSku.ProductId, SafeWarningRemainingDay = reqItem.SafeWarningRemainingDay, SkuId = qtskuId, TriggerOptimizationReason = reason, LastOptimizationRatio = skuOptimizationHistory?.OptimizationRatio ?? 0M, LastPurchasePrice = skuOptimizationHistory?.CurrentPurchasePrice, PrePurchasedAmount = (skuOptimizationHistory?.CurrentPurchasePrice ?? 0M) * reqItem.PreItemCount, LastOptimizationTime = skuOptimizationHistory?.CreateTime }; #endregion #region 创建待优化子任务 { var yijiagroups = venderBusiness.GetYiJiaGroup(); foreach (var department in yijiagroups) { var skuOptimizationChildTask = new SkuOptimizationChildTask() { Id = idGenerator.NewLong(), BelongTeamId = department.Id, BelongTeamName = department.DepartmentName, CompletionTime = null, IsOptimizationCompleted = false, OptimizationTaskId = skuOptimizationTask.Id }; insertSkuOptimizationChildTaskList.Add(skuOptimizationChildTask); } } #endregion #region 创建待优化限时任务 insertTimeLimitTaskList.Add(new TimeLimitTask() { Id = idGenerator.NewLong(), CreateTme = DateTime.Now, //ExpirationTime = DateTime.Now.AddDays(isFirst ? 2 : 1), ExpirationTime = timeLimitRules.CalculateExpirationTime(Enums.TimeLimitTaskType.待议价任务, DateTime.Now.AddDays(reason == Enums.TriggerOptimizationReason.首次采购 ? 1 : 0)), //OrderId = o.OrderId, //OrderSn = o.OrderSn, ShopId = productSku.ShopId, SkuId = qtskuId, TaskType = Enums.TimeLimitTaskType.待议价任务, TaskId = skuOptimizationTask.Id, Remark = reason.ToString() }); #endregion } fsql.Transaction(() => { if (insertSkuOptimizationTaskList.Count() > 0) fsql.Insert(insertSkuOptimizationTaskList).ExecuteAffrows(); if (insertSkuOptimizationChildTaskList.Count() > 0) fsql.Insert(insertSkuOptimizationChildTaskList).ExecuteAffrows(); if (insertTimeLimitTaskList.Count() > 0) fsql.Insert(insertTimeLimitTaskList).ExecuteAffrows(); }); } /// /// 完成优化 /// /// /// /// public void CompleteOptimization(long taskId, string userId) { #region 验证待议价任务 var optimazaionTask = fsql.Select(taskId).ToOne(); if (optimazaionTask == null) throw new BusinessException("优化任务不存在"); if (optimazaionTask.IsOptimizationCompleted == true) throw new BusinessException("优化任务已完成"); #endregion #region 获取用户和部门信息 var uInfo = GetYiJiaDepartmentByUserId(userId); #endregion #region 验证待议价子任务 var optimazaionChildTaskList = fsql.Select() .Where(sc => sc.OptimizationTaskId == optimazaionTask.Id) .ToList(); var currentOptimazaionChildTaskList = optimazaionChildTaskList.FirstOrDefault(sc => sc.BelongTeamId == uInfo.department.Id); if (currentOptimazaionChildTaskList == null) throw new BusinessException($"未找到议价组{uInfo.department.DepartmentName}的议价子任务"); if (currentOptimazaionChildTaskList.IsOptimizationCompleted == true) throw new BusinessException($"{uInfo.department.DepartmentName}的议价子任务已完成"); currentOptimazaionChildTaskList.IsOptimizationCompleted = true; #endregion IUpdate updateChildTask = null; IUpdate updateTask = null; IUpdate updateSpuSaleInfo = null; IUpdate updateTimeLimitTask = null; if (!optimazaionChildTaskList.Any(sc => sc.IsOptimizationCompleted == false)) { //全部完成 #region 更新spu销量表 var spuSaleInfo = fsql.Select(optimazaionTask.ProductId).ToOne(); if (spuSaleInfo == null) throw new BusinessException($"未找到spu{optimazaionTask.ProductId}销量"); updateSpuSaleInfo = fsql.Update(optimazaionTask.ProductId) .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == false, s => s.IsFirstPurchaseCompleted, true) .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == false, s => s.FirstPurchaseCompletedItemCount == s.ItemCount) .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == true && spuSaleInfo.IsFirstOptimizationCompleted == false, s => s.IsFirstOptimizationCompleted, true) .SetIf(spuSaleInfo.IsFirstPurchaseCompleted == true && spuSaleInfo.IsFirstOptimizationCompleted == false, s => s.FirstOptimizationCompletedItemCount == s.ItemCount) .Set(s => s.LastOptimizationItemCount == s.ItemCount) .Set(s => s.LastOptimizationTime, DateTime.Now) .Set(s => s.UpdateTime, DateTime.Now); #endregion #region 更新待议价任务 updateTask = fsql.Update(optimazaionTask.Id) .Set(t => t.IsOptimizationCompleted, true) .Set(t => t.CompletionTime, DateTime.Now); #endregion #region 更新待议价限时任务 updateTimeLimitTask = fsql.Update().Set(t => t.CompletionTime, DateTime.Now) .Set(t => t.IsTimely == (DateTime.Now < t.ExpirationTime ? true : false)) .Where(t => t.TaskId == optimazaionTask.Id && t.CompletionTime == null && t.TaskType == Enums.TimeLimitTaskType.待议价任务); #endregion } #region 更新待议价子任务 updateChildTask = fsql.Update(currentOptimazaionChildTaskList.Id) .Set(sc => sc.IsOptimizationCompleted, true) .Set(sc => sc.CompletionTime, DateTime.Now); #endregion fsql.Transaction(() => { updateChildTask?.ExecuteAffrows(); updateTask?.ExecuteAffrows(); updateSpuSaleInfo?.ExecuteAffrows(); updateTimeLimitTask?.ExecuteAffrows(); }); } public ListResponse GetNoCompletionSkuOptimizationTask(PageRequest request, string userId) { var uInfo = GetYiJiaDepartmentByUserId(userId); var taskList = fsql.Select() .InnerJoin((t, tt) => t.Id == tt.TaskId) .Where((t, tt) => t.IsOptimizationCompleted == false) .OrderByDescending((t, tt) => t.CreateTime) .Count(out var total) .Page(request.PageIndex, request.PageSize) .ToList((t, tt) => new SkuOptimizationTask { Id = t.Id, ShopId = t.ShopId, BelongShopName = t.BelongShopName, JDSkuId = t.JDSkuId, ProductId = t.ProductId, SkuId = t.SkuId, PreItemCount = t.PreItemCount, PrePurchasedAmount = t.PrePurchasedAmount, SafeWarningRemainingDay = t.SafeWarningRemainingDay, IsOptimizationCompleted = t.IsOptimizationCompleted, IsPurchasementCompleted = t.IsPurchasementCompleted, CreateTime = t.CreateTime, CompletionTime = t.CompletionTime, TriggerOptimizationReason = t.TriggerOptimizationReason, LastOptimizationRatio = t.LastOptimizationRatio, LastPurchasePrice = t.LastPurchasePrice, LastOptimizationTime = t.LastOptimizationTime, TimeLimitTaskId = tt.Id, TimeLimitTaskBelongTaskId = tt.TaskId, TimeLimitTaskCompletionTime = tt.CompletionTime, TimeLimitTaskCreateTme = tt.CreateTme, TimeLimitTaskExpirationTime = tt.ExpirationTime, TimeLimitTaskIsTimely = tt.IsTimely, TimeLimitTaskOrderId = tt.OrderId, TimeLimitTaskOrderSn = tt.OrderSn, TimeLimitTaskPayTime = tt.PayTime, TimeLimitTaskRemark = tt.Remark, TimeLimitTaskShopId = tt.ShopId, TimeLimitTaskSkuId = tt.SkuId, TimeLimitTaskTaskType = tt.TaskType }).Map>(); List taskIdList = taskList.Select(t => t.Id).ToList(); var childTaskList = fsql.Select().Where(ct => taskIdList.Contains(ct.OptimizationTaskId)).ToList(); foreach (var task in taskList) { task.ChildTaskList = childTaskList.Where(ct => ct.OptimizationTaskId == task.Id).ToList(); var currentChildTask = task.ChildTaskList.FirstOrDefault(ct => ct.BelongTeamId == uInfo.user.DepartmentId); task.IsOptimizationCompletedByCurrentTeam = currentChildTask?.IsOptimizationCompleted ?? false; } return new ListResponse() { Items = taskList, TotalCount = total }; } } }