Files
YunTongJackYunTask/Reportapi/MyCode.Project.Services/BaoDianBLL/SalesPlanCalBLL.cs
2025-07-04 09:50:02 +08:00

393 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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来运算)
/// <summary>
/// 根据订单id来运算
/// </summary>
/// <param name="objSheetId"></param>
[TransactionCallHandler]
public void Run(object objSheetId)
{
//初始化
base.Init(objSheetId.ToString());
var checkResult = base.CheckPassed(PlanType.ProductSalesPlan);
if (!checkResult) { return; }
//先删掉可以保证该方法不断的被调用计算
_repository.Delete<BdOrderPlan>(p => p.OrderId == SheetId && p.PlanType == (int)PlanType.ProductSalesPlan);
//查看当月的该店员的产品销售计划tId && p.PlanType == (int)PlanType.ProductSalesPlan);
//_repository.Delete<BdOrderSalesPlanSku>(p => p.Ord
//得到该订单中的商品明细6
var sheetItems = _repository.Queryable<LxmSheetItem>().Where(p => p.SalesSheetId == SheetId).WithCache(100).ToList();
if (Sheet.Direct == 1)
{
var clerkSalesPlans = _repository
.Queryable<BdClerkProductSalesPlan, LxmProductSalesSchedule>((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里面)
/// <summary>
/// 写入计划SKU里面
/// </summary>
private void AddPlanSku(List<ItemQtiyUnitPriceResp> listItem,long packageId,long sourcePackageId,long planId)
{
if (listItem.IsEmpty()) { return; }
var addList = new List<BdOrderSalesPlanSku>();
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<BdOrderSalesPlanSku>(addList);
}
#endregion
#region CalNormalOrder()
/// <summary>
/// 计算正常的订单
/// </summary>
/// <param name="listClerkPlan"></param>
/// <param name="listPackage"></param>
/// <param name="listSheetItem"></param>
private void CalNormalOrder(List<ClerkProductSalesPlanResp> listClerkPlan,
List<PackageListResp> listPackage,
List<LxmSheetItem> 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<BdOrderPlan>(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()
/// <summary>
/// 处理彩妆和发饰
/// </summary>
private void CalColorAndHairProduct(List<ClerkProductSalesPlanResp> listClerkPlan,
List<LxmSheetItem> 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<BdOrderPlan>(orderPlan);
calOther = true;
listSheetItem.RemoveAll(p => (colorProducts.Select(it => it.Id)).Contains(p.Id));
}
}
}
#endregion
#region MatchPlanQty()
/// <summary>
/// 匹配计划中的套餐可以多少套
/// </summary>
/// <param name="orderSkuId"></param>
/// <param name="listPlanSkuId"></param>
/// <returns></returns>
private MatchPlanQtyResp MatchPlanQty(List<PackageListResp> listPackage,
long packageId,
List<LxmSheetItem> 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<int>();
//符合套餐,看看可以得到多少套
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<ItemQtiyUnitPriceResp>();
//按这个数量移除
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(退)
/// <summary>
/// 如果是退款单
/// </summary>
private void CalRefundOrder(List<LxmSheetItem> 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<LxmSheetItem>().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<BdClerkProductSalesPlan, LxmProductSalesSchedule>((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<BdOrderPlan>().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<BdOrderPlan>(planSku);
}
}
#endregion
}
}