using MyCode.Project.Domain.Message.Response.BaoDian; using MyCode.Project.Domain.Model; using MyCode.Project.Domain.Repositories; using MyCode.Project.Infrastructure.Common; using MyCode.Project.Infrastructure.Constant; using MyCode.Project.Infrastructure.Enumeration; using MyCode.Project.Infrastructure.Exceptions; using MyCode.Project.Infrastructure.Extensions; using MyCode.Project.Repositories.Common; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyCode.Project.Services.BLL { public class SalesPlanCalBLL : CommonPlanCalBLL { #region 初始化 private readonly ILxmProductSalesScheduleRepository _lxmProductSalesScheduleRepository; private readonly ILxmSheetItemRepository _lxmSheetItemRepository; private readonly IAnsyDataProcessService _ansyDataProcessService; private readonly IBdOrderSalesPlanSkuRepository _bdOrderSalesPlanSkuRepository; private int OrderNum = 1; public SalesPlanCalBLL(IRepository repository, ILxmProductSalesScheduleRepository lxmProductSalesScheduleRepository, ILxmSheetItemRepository lxmSheetItemRepository, IAnsyDataProcessService ansyDataProcessService, IBdOrderSalesPlanSkuRepository bdOrderSalesPlanSkuRepository ) :base(repository) { _repository = repository; _lxmProductSalesScheduleRepository = lxmProductSalesScheduleRepository; _lxmSheetItemRepository = lxmSheetItemRepository; _ansyDataProcessService = ansyDataProcessService; _bdOrderSalesPlanSkuRepository = bdOrderSalesPlanSkuRepository; } #endregion #region Run(根据订单id来运算) /// /// 根据订单id来运算 /// /// [TransactionCallHandler] public void Run(object objSheetId) { //初始化 base.Init(objSheetId.ToString()); var checkResult = base.CheckPassed(PlanType.ProductSalesPlan); if (!checkResult) { return; } //先删掉可以保证该方法不断的被调用计算 _repository.Delete(p => p.OrderId == SheetId && p.PlanType == (int)PlanType.ProductSalesPlan); //查看当月的该店员的产品销售计划tId && p.PlanType == (int)PlanType.ProductSalesPlan); //_repository.Delete(p => p.Ord //得到该订单中的商品明细6 var sheetItems = _repository.Queryable().Where(p => p.SalesSheetId == SheetId).WithCache(100).ToList(); if (Sheet.Direct == 1) { var clerkSalesPlans = _repository .Queryable((cPlan, pPlan) => new object[] { JoinType.Left,cPlan.ProductId == pPlan.Id }) .Where((cPlan, pPlan) => cPlan.Status == 1 && cPlan.VersionTime == VersionTime && cPlan.PlanTotalAmount > 0) .WhereIF(Sheet.OrderClerkId == null, (cPlan, pPlan) => cPlan.ClerkId == null) .WhereIF(Sheet.OrderClerkId != null, (cPlan, pPlan) => cPlan.ClerkId == Sheet.OrderClerkId) .Select((cPlan, pPlan) => new ClerkProductSalesPlanResp { PlanId = cPlan.Id, PackageId = SqlFunc.ToInt64(cPlan.ProductId), PackageName = cPlan.Name, TotalPrice = pPlan.TotalPrice, SourcePackageId = pPlan.PackageId }) .WithCache(3600) .ToList(); if (clerkSalesPlans == null || clerkSalesPlans.Count == 0) { return; } clerkSalesPlans = clerkSalesPlans.OrderByDescending(p => p.TotalPrice).ToList(); var planSkus = _lxmProductSalesScheduleRepository.GetPackageProductList(clerkSalesPlans.Select(p => p.PackageId).ToList()); CalNormalOrder(clerkSalesPlans, planSkus, sheetItems); } else { CalRefundOrder(sheetItems); } } #endregion #region AddPlanSku(写入计划SKU里面) /// /// 写入计划SKU里面 /// private void AddPlanSku(List listItem,long packageId,long sourcePackageId,long planId) { if (listItem.IsEmpty()) { return; } var addList = new List(); foreach (var item in listItem) { var temp = new BdOrderSalesPlanSku() { Id = IdHelper.GetNewId(), Qty = item.TotalQty, OrderId = Sheet.Id, OrderTime = Sheet.CreateTime.Value, PlanId = planId, PackageId = packageId, SkuId = item.SkuId, UpdateTime = DateTime.Now, UnitPrice = item.UnitPrice, OrderNum = OrderNum, SourceOrderId = Sheet.Id, SourcePackageId = sourcePackageId }; addList.Add(temp); OrderNum = OrderNum + 1; } _repository.Add(addList); } #endregion #region CalNormalOrder(计算正常的订单) /// /// 计算正常的订单 /// /// /// /// private void CalNormalOrder(List listClerkPlan, List listPackage, List listSheetItem) { var cal = false; //只统计商品和服务 listSheetItem.RemoveAll(p => p.ItemType != 0 && p.ItemType != 1); var notIncludeCaiZhuan = listClerkPlan.Where(p => p.PackageId != (int)PlanProductId.ColorProduct && p.PackageId != (int)PlanProductId.HairProduct).ToList(); //所有都符合才能凑成一个,且这个本身有数量; foreach (var clerkPlan in notIncludeCaiZhuan) { var orderPlan = new BdOrderPlan() { Id = IdHelper.GetNewId(), OrderId = Sheet.Id, OrderTime = Sheet.CreateTime.Value, PackageId = clerkPlan.PackageId, PackageName = clerkPlan.PackageName, PlanId = clerkPlan.PlanId, PlanType = (int)PlanType.ProductSalesPlan, UpdateTime = DateTime.Now, SourcePackageId = clerkPlan.SourcePackageId, SourceOrderId = Sheet.Id }; //得到数量+金额,每次匹配到一个SKU就减少下数量 var matchQtyAndAmount = MatchPlanQty(listPackage, clerkPlan.PackageId, listSheetItem); if (matchQtyAndAmount == null || matchQtyAndAmount.Qty == 0) { continue; } orderPlan.Qty = matchQtyAndAmount.Qty; orderPlan.Amount = matchQtyAndAmount.Amount; orderPlan.Info = "符合[销售计划],商品或服务数需要相应减少且有跨月退款问题"; _repository.Add(orderPlan); AddPlanSku(matchQtyAndAmount.Sku,clerkPlan.PackageId,clerkPlan.SourcePackageId,clerkPlan.PlanId); cal = true; } var listColorAndHairClerkPlan = listClerkPlan.Where(p => (p.PackageId == (int)PlanProductId.ColorProduct || p.PackageId == (int)PlanProductId.HairProduct)).ToList(); var calOther = false; if (listColorAndHairClerkPlan != null && listColorAndHairClerkPlan.Count > 0) { CalColorAndHairProduct(listColorAndHairClerkPlan, listSheetItem,out calOther); //算完了其它类型,把数量改为0 if (calOther) { cal = true; } } } #endregion #region CalColorAndHairProduct(处理彩妆和发饰) /// /// 处理彩妆和发饰 /// private void CalColorAndHairProduct(List listClerkPlan, List listSheetItem, out bool calOther) { calOther = false; if (listSheetItem == null || listSheetItem.Count == 0) { return; } if (listClerkPlan == null || listClerkPlan.Count == 0) { return; } //彩妆和发饰,数量为0,计算金额就好; foreach (var clerkPlan in listClerkPlan) { var orderPlan = new BdOrderPlan() { Id = IdHelper.GetNewId(), OrderId = Sheet.Id, OrderTime = Sheet.CreateTime.Value, PackageId = clerkPlan.PackageId, PackageName = clerkPlan.PackageName, PlanId = clerkPlan.PlanId, PlanType = (int)PlanType.ProductSalesPlan, UpdateTime = DateTime.Now, Qty = 0 }; //彩妆和发饰 if (clerkPlan.PackageId == (int)PlanProductId.ColorProduct || clerkPlan.PackageId == (int)PlanProductId.HairProduct) { var categoryId = Const.CosmeticsTopCategoryId; if (clerkPlan.PackageId == (int)PlanProductId.HairProduct) { categoryId = Const.HairOrnamentsTopCategoryId; } var colorProducts = listSheetItem.Where(p => p.TopCategoryId == categoryId.ToLower() && p.Qty > 0 && p.InBlanceUnitPrice >0).ToList(); if (colorProducts == null || colorProducts.Count == 0) { continue; } orderPlan.Amount = colorProducts.Sum(p => p.InBlanceUnitPrice * p.Qty); _repository.Add(orderPlan); calOther = true; listSheetItem.RemoveAll(p => (colorProducts.Select(it => it.Id)).Contains(p.Id)); } } } #endregion #region MatchPlanQty(匹配计划中的套餐多少套) /// /// 匹配计划中的套餐可以多少套 /// /// /// /// private MatchPlanQtyResp MatchPlanQty(List listPackage, long packageId, List listSheetItem) { //匹配到的计划配置里面的sku var matchPlanSkus = listPackage.Where(p => p.Id == packageId).ToList(); if (matchPlanSkus.IsEmpty()) { return null; } foreach (var planSku in matchPlanSkus) { //先判断是否套餐的所有商品在里面都有 if (!listSheetItem.Exists(p => p.ItemId.ToLower() == planSku.ProductOrServiceId.ToLower() && p.Qty >= planSku.Qty)) { return null; } } //默认只能一套 var listMatchQty = new List(); //符合套餐,看看可以得到多少套 for (int i = 0; i < matchPlanSkus.Count; i++) { var matchProduct = listSheetItem.Find(p => p.ItemId.ToLower() == matchPlanSkus[i].ProductOrServiceId.ToLower()); // 上面已经匹配,这里不可能为null,只关心可以得到多少 var tempQty = matchProduct.Qty / matchPlanSkus[i].Qty; listMatchQty.Add(tempQty); } var matchQty = listMatchQty.Min(p => p); var amount = 0m; var listMatchItem = new List(); //按这个数量移除 for (int i = 0; i < matchPlanSkus.Count; i++) { var matchProduct = listSheetItem.Find(p => p.ItemId.ToLower() == matchPlanSkus[i].ProductOrServiceId.ToLower()); amount = amount + Math.Round(matchProduct.InBlanceUnitPrice * matchQty,2,MidpointRounding.AwayFromZero); var matchItem = new ItemQtiyUnitPriceResp() { TotalQty = matchPlanSkus[i].Qty * matchQty, SkuId = matchProduct.ItemId, UnitPrice = matchProduct.InBlanceUnitPrice }; listMatchItem.Add(matchItem); //订单明细这里 matchProduct.Qty = matchProduct.Qty - matchQty; } return new MatchPlanQtyResp { Qty = matchQty,Amount = amount, Sku = listMatchItem }; } #endregion #region CalRefundOrder(如果是退款单) /// /// 如果是退款单 /// private void CalRefundOrder(List listSheetItem) { //这个月如果产生了或者上个月产生了,则 if (Sheet.SourceOrderId == null) { LogHelper.Info($"[销售运算]退款单={Sheet.Id}找不到原始订单"); return; } var sourceOrderId = Sheet.SourceOrderId; //判断原始销售单是否上个月 var sourceOrder = GetSourceSimpleOrder(Sheet.SourceOrderId); if (sourceOrder.OrderPreorderId != null) { sourceOrderId = sourceOrder.OrderPreorderId; } //订单上个月开始时间,因为销售计划只需要计算从上个月开始就行 var sheetOrderLastMonthFirstDay = Sheet.CreateTime.Value.AddMonths(-1).GetFirstDayOfMonth(); if (sourceOrder.CreateTime < sheetOrderLastMonthFirstDay) { return; } //如果不是全退,则不用处理 var sourceQty = _repository.Queryable().Where(p => p.SalesSheetId == sourceOrderId).Select(p => SqlFunc.AggregateSum(p.Qty)).First(); var refundQty = _lxmSheetItemRepository.GetRefundQty(sourceOrderId, sheetOrderLastMonthFirstDay, Sheet.CreateTime.Value.AddSeconds(1)); if (sourceQty != refundQty) { return; } var clerkSalesPlans = _repository .Queryable((cPlan, pPlan) => new object[] { JoinType.Left,cPlan.ProductId == pPlan.Id }) .Where((cPlan, pPlan) => cPlan.Status == 1 && cPlan.VersionTime == VersionTime && cPlan.PlanTotalAmount > 0) .WhereIF(Sheet.OrderClerkId == null, (cPlan, pPlan) => cPlan.ClerkId == null) .WhereIF(Sheet.OrderClerkId != null, (cPlan, pPlan) => cPlan.ClerkId == sourceOrder.OrderClerkId) .Select((cPlan, pPlan) => new ClerkProductSalesPlanResp { PlanId = cPlan.Id, PackageId = SqlFunc.ToInt64(cPlan.ProductId), PackageName = cPlan.Name, TotalPrice = pPlan.TotalPrice, SourcePackageId = pPlan.PackageId }) .WithCache(3600) .ToList(); if (clerkSalesPlans == null || clerkSalesPlans.Count == 0) { return; } var listClerkPlan = clerkSalesPlans.OrderByDescending(p => p.TotalPrice).ToList(); //店员的销售计划id var clerkPackageIds = listClerkPlan.Select(p => p.SourcePackageId).Distinct().ToList(); //只能在这些店员有的计划上扣 var planSkus = _repository.Queryable().Where(p => p.OrderId == sourceOrderId && p.PlanType == (int)PlanType.ProductSalesPlan && (p.Qty > 0 || p.Amount > 0)).ToList(); if (planSkus == null || planSkus.Count == 0) { LogHelper.Info($"退款单id={Sheet.Id}当前店员在上个月和这个月没有产生对应的销售计划"); return; } foreach (var planSku in planSkus) { //当前店员如果有这个计划,则可以扣减 var clerkPlan = listClerkPlan.Find(p => p.SourcePackageId == planSku.SourcePackageId); if (clerkPlan == null) { continue; } planSku.Qty = -planSku.Qty; planSku.OrderId = SheetId; planSku.PlanId = clerkPlan.PlanId; planSku.PackageId = clerkPlan.PackageId; planSku.OrderTime = Sheet.CreateTime.Value; planSku.SourceOrderId = sourceOrderId; planSku.UpdateTime = DateTime.Now; planSku.Amount = -planSku.Amount; planSku.Id = IdHelper.GetNewId(); planSku.Info = "[销售计划]全额退导致的反向流水"; _repository.Add(planSku); } } #endregion } }