Browse Source

预估成本自动任务

pjzs_starttask_update
shanji 2 years ago
parent
commit
6f1f52fc9b
  1. 4
      BBWY.Server.API/BBWY.Server.API.csproj
  2. 37
      BBWY.Server.API/Controllers/OrderEstimateCostSyncController.cs
  3. 4
      BBWY.Server.Business/BBWY.Server.Business.csproj
  4. 300
      BBWY.Server.Business/Sync/OrderEstimateCostSyncBusiness.cs
  5. 4
      BBWY.Server.Business/TaskSchedulerManager.cs
  6. 2
      BBWY.Server.Model/BBWY.Server.Model.csproj
  7. 6
      BBWY.Server.Model/Db/Order/OrderCost.cs
  8. 9
      BBWY.Server.Model/Db/Order/OrderCostDetail.cs
  9. 94
      BBWY.Server.Model/Db/Order/SkuRecentCost.cs
  10. 15
      BBWY.Server.Model/Dto/Request/Sync/SkuRecentCostRequest.cs
  11. 4
      BBWY.Test/BBWY.Test.csproj
  12. 4
      JD.API/JD.API.csproj

4
BBWY.Server.API/BBWY.Server.API.csproj

@ -6,8 +6,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FreeSql" Version="2.6.100" />
<PackageReference Include="FreeSql.Provider.MySql" Version="2.6.100" />
<PackageReference Include="FreeSql" Version="3.2.805" />
<PackageReference Include="FreeSql.Provider.MySql" Version="3.2.805" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.32" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.21" />
<PackageReference Include="NLog" Version="4.7.12" />

37
BBWY.Server.API/Controllers/OrderEstimateCostSyncController.cs

@ -0,0 +1,37 @@
using BBWY.Server.Business;
using BBWY.Server.Model.Dto;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace BBWY.Server.API.Controllers
{
public class OrderEstimateCostSyncController : BaseApiController
{
private OrderEstimateCostSyncBusiness orderEstimateCostSyncBusiness;
public OrderEstimateCostSyncController(IHttpContextAccessor httpContextAccessor, OrderEstimateCostSyncBusiness orderEstimateCostSyncBusiness) : base(httpContextAccessor)
{
this.orderEstimateCostSyncBusiness = orderEstimateCostSyncBusiness;
}
/// <summary>
/// 同步所有店铺的SKU最近成本
/// </summary>
[HttpPost]
public void SyncAllShopOrderSkuRecentCost()
{
orderEstimateCostSyncBusiness.SyncAllShopOrderSkuRecentCost();
}
/// <summary>
/// 同步指定条件的SKU最近成本
/// </summary>
/// <param name="request"></param>
[HttpPost]
public void SyncOrderSkuRecentCost([FromBody] SkuRecentCostRequest request)
{
orderEstimateCostSyncBusiness.SyncOrderSkuRecentCost(request);
}
}
}

4
BBWY.Server.Business/BBWY.Server.Business.csproj

@ -6,8 +6,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FreeSql" Version="2.6.100" />
<PackageReference Include="FreeSql.Provider.MySql" Version="2.6.100" />
<PackageReference Include="FreeSql" Version="3.2.805" />
<PackageReference Include="FreeSql.Provider.MySql" Version="3.2.805" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="NLog" Version="4.7.12" />

300
BBWY.Server.Business/Sync/OrderEstimateCostSyncBusiness.cs

@ -0,0 +1,300 @@
using BBWY.Common.Extensions;
using BBWY.Common.Models;
using BBWY.Server.Business.Extensions;
using BBWY.Server.Model;
using BBWY.Server.Model.Db;
using BBWY.Server.Model.Dto;
using FreeSql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Yitter.IdGenerator;
namespace BBWY.Server.Business
{
public class OrderEstimateCostSyncBusiness : BaseBusiness, IDenpendency
{
private TaskSchedulerManager taskSchedulerManager;
private VenderBusiness venderBusiness;
private List<Enums.OrderState?> invalidOrderStateList;
public OrderEstimateCostSyncBusiness(IFreeSql fsql,
NLogManager nLogManager,
IIdGenerator idGenerator,
TaskSchedulerManager taskSchedulerManager,
VenderBusiness venderBusiness) : base(fsql, nLogManager, idGenerator)
{
this.taskSchedulerManager = taskSchedulerManager;
this.venderBusiness = venderBusiness;
invalidOrderStateList = new List<Enums.OrderState?>() {
Enums.OrderState.,
Enums.OrderState.,
Enums.OrderState.
};
}
#region 同步SKU最近成本
public void SyncAllShopOrderSkuRecentCost()
{
var date = DateTime.Now.Date.AddDays(-1);
SyncOrderSkuRecentCost(new SkuRecentCostRequest()
{
ShopId = null,
StartDate = date,
EndDate = date
});
}
/// <summary>
/// 同步昨天SKU的采购成本
/// </summary>
/// <param name="request"></param>
public void SyncOrderSkuRecentCost(SkuRecentCostRequest request)
{
var shopList = venderBusiness.GetShopList(request.ShopId, Model.Enums.Platform.);
request.EndDate = request.EndDate.Date.AddDays(1).AddSeconds(-1);
foreach (var shop in shopList)
{
var _shopId = long.Parse(shop.ShopId);
Task.Factory.StartNew(() => SyncOrderSkuRecentCost(shop, request.StartDate, request.EndDate), CancellationToken.None, TaskCreationOptions.LongRunning, taskSchedulerManager.SyncSkuYesterdayCostTaskScheduler);
}
}
private void SyncOrderSkuRecentCost(ShopResponse shop, DateTime startDate, DateTime endDate)
{
try
{
var shopId = long.Parse(shop.ShopId);
var yesterdaycostDetailist = fsql.Select<OrderCostDetail, Order>()
.InnerJoin((ocd, o) => ocd.OrderId == o.Id)
.Where((ocd, o) => o.ShopId == shopId &&
o.StartTime >= startDate &&
o.StartTime <= endDate &&
!invalidOrderStateList.Contains(o.OrderState) &&
o.IsGift == false &&
o.StorageType != Enums.StorageType.SD &&
ocd.IsEnabled == true &&
ocd.IsEstimateCost == false)
.GroupBy((ocd, o) => ocd.SkuId)
.WithTempQuery(g => new { MaxId = g.Sum(g.Value.Item1.Id), SkuId = g.Key })
.From<OrderCostDetail>()
.InnerJoin((ocd1, ocd2) => ocd1.MaxId == ocd2.Id)
.ToList((ocd1, ocd2) => ocd2);
if (yesterdaycostDetailist.Count() == 0)
return;
var skuIdList = yesterdaycostDetailist.Select(ocd => ocd.SkuId).Distinct().ToList();
var dbSkuRecentCostList = fsql.Select<SkuRecentCost>(skuIdList).ToList();
List<SkuRecentCost> insertSkuRecetCostList = new List<SkuRecentCost>();
List<IUpdate<SkuRecentCost>> updateSkuRecentCostList = new List<IUpdate<SkuRecentCost>>();
foreach (var yesocd in yesterdaycostDetailist)
{
var q = yesocd.DeductionQuantity;
if (q <= 0)
q = 1;
var singleConsumableAmount = yesocd.ConsumableAmount / q;
var singleDeliveryFreight = yesocd.DeliveryExpressFreight / q;
var singleFirstFreight = yesocd.FirstFreight / q;
var singleFreight = yesocd.PurchaseFreight / q;
var singleInStorageAmount = yesocd.InStorageAmount / q;
var singleOutStorageAmount = yesocd.OutStorageAmount / q;
var singleSkuAmount = yesocd.SkuAmount / q;
var singleStorageAmount = yesocd.StorageAmount / q;
var skuRecentCost = dbSkuRecentCostList.FirstOrDefault(x => x.SkuId == yesocd.SkuId);
if (skuRecentCost != null)
{
skuRecentCost.SingleConsumableAmount = singleConsumableAmount;
skuRecentCost.SingleDeliveryFreight = singleDeliveryFreight;
skuRecentCost.SingleFirstFreight = singleFirstFreight;
skuRecentCost.SingleFreight = singleFreight;
skuRecentCost.SingleInStorageAmount = singleInStorageAmount;
skuRecentCost.SingleOutStorageAmount = singleOutStorageAmount;
skuRecentCost.SingleSkuAmount = singleSkuAmount;
skuRecentCost.SingleStorageAmount = singleStorageAmount;
skuRecentCost.UpdateTime = DateTime.Now;
var update = fsql.Update<SkuRecentCost>(yesocd.SkuId).SetSource(skuRecentCost);
updateSkuRecentCostList.Add(update);
}
else
{
skuRecentCost = new SkuRecentCost()
{
SkuId = yesocd.SkuId,
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now,
ProductId = yesocd.ProductId,
RecentOrderId = yesocd.OrderId,
ShopId = shopId,
SingleConsumableAmount = singleConsumableAmount,
SingleDeliveryFreight = singleDeliveryFreight,
SingleFirstFreight = singleFirstFreight,
SingleFreight = singleFreight,
SingleInStorageAmount = singleInStorageAmount,
SingleOutStorageAmount = singleOutStorageAmount,
SingleSkuAmount = singleSkuAmount,
SingleStorageAmount = singleStorageAmount
};
insertSkuRecetCostList.Add(skuRecentCost);
}
}
fsql.Transaction(() =>
{
if (insertSkuRecetCostList.Count() > 0)
fsql.Insert(insertSkuRecetCostList).ExecuteAffrows();
if (updateSkuRecentCostList.Count() > 0)
{
foreach (var update in updateSkuRecentCostList)
update.ExecuteAffrows();
}
});
}
catch (Exception ex)
{
nLogManager.GetLogger($"SKU最近成本-{shop.ShopName}").Error(ex);
}
}
#endregion
#region 预估成本
public void EstimateCostForAllShopNoCostOrder()
{
EstimateCostForNoCostOrder(new SkuRecentCostRequest()
{
ShopId = null,
StartDate = DateTime.Now.AddHours(-3),
EndDate = DateTime.Now
});
}
public void EstimateCostForNoCostOrder(SkuRecentCostRequest request)
{
var shopList = venderBusiness.GetShopList(request.ShopId, Model.Enums.Platform.);
//request.EndDate = request.EndDate.Date.AddDays(1).AddSeconds(-1);
foreach (var shop in shopList)
{
Task.Factory.StartNew(() => EstimateCostForNoCostOrder(shop, request.StartDate, request.EndDate), CancellationToken.None, TaskCreationOptions.LongRunning, taskSchedulerManager.SyncSkuYesterdayCostTaskScheduler);
}
}
private void EstimateCostForNoCostOrder(ShopResponse shop, DateTime startTime, DateTime endTime)
{
try
{
var shopId = long.Parse(shop.ShopId);
var orderList = fsql.Select<Order>().Where(o => o.ShopId == shopId &&
o.ModifyTime >= startTime &&
o.ModifyTime <= endTime &&
!invalidOrderStateList.Contains(o.OrderState) &&
o.IsGift == false &&
o.StorageType == null &&
!fsql.Select<OrderCost>().Where(oc => oc.OrderId == o.Id).Any())
.ToList();
if (orderList.Count() == 0)
return;
var orderIdList = orderList.Select(o => o.Id).ToList();
/*
decimal skuShouldPay,
decimal pingTaiChengDanYouHuiQuan,
decimal superRedEnvelope,
decimal xianPinLeiDongQuan,
decimal skuVenderFee,
decimal jingdou,
decimal dongquan,
decimal balance,
*/
/*
SkuAmount +
PurchaseFreight +
FirstFreight +
InStorageAmount +
OutStorageAmount +
StorageAmount +
ConsumableAmount
*/
var orderSkuAndRecentList = fsql.Select<OrderSku, SkuRecentCost>()
.LeftJoin((osku, src) => osku.SkuId == src.SkuId)
.Where((osku, src) => orderIdList.Contains(osku.SkuId) && osku.Price > 0)
.ToList((osku, src) => new
{
osku.Id,
osku.OrderId,
osku.SkuId,
osku.ProductId,
osku.ShouldPay,
osku.PingTaiChengDanYouHuiQuan,
osku.SuperRedEnvelope,
osku.XianPinLeiDongQuan,
osku.VenderFee,
osku.JingDou,
osku.DongQuan,
osku.Balance,
osku.ItemTotal,
src.SingleConsumableAmount,
src.SingleSkuAmount,
src.SingleDeliveryFreight,
src.SingleFirstFreight,
src.SingleFreight,
src.SingleInStorageAmount,
src.SingleOutStorageAmount,
src.SingleStorageAmount
});
foreach (var order in orderList)
{
var currentOrderSkuList = orderSkuAndRecentList.Where(osku => osku.OrderId == order.Id).ToList();
if (currentOrderSkuList.Any(osku => osku.ShouldPay == null ||
osku.ShouldPay == 0 ||
osku.SingleSkuAmount == null ||
osku.SingleSkuAmount == 0))
continue; //预估成本和毛利,必须订单下的每一笔sku都具备最近成本
foreach (var osku in currentOrderSkuList)
{
var ocd = new OrderCostDetail()
{
Id = idGenerator.NewLong(),
ConsumableAmount = (osku.SingleConsumableAmount * osku.ItemTotal) ?? 0M,
DeductionQuantity = osku.ItemTotal ?? 1,
CreateTime = DateTime.Now,
DeliveryExpressFreight = (osku.SingleDeliveryFreight * osku.ItemTotal) ?? 0M,
FirstFreight = (osku.SingleFirstFreight * osku.ItemTotal) ?? 0M,
InStorageAmount = (osku.SingleInStorageAmount * osku.ItemTotal) ?? 0M,
OutStorageAmount = (osku.SingleOutStorageAmount * osku.ItemTotal) ?? 0M,
OrderId = order.Id,
ProductId = osku.ProductId,
PurchaseFreight = (osku.SingleFreight * osku.ItemTotal) ?? 0M,
PurchaseOrderPKId = 0,
SkuAmount = (osku.SingleSkuAmount * osku.ItemTotal) ?? 0M,
SkuId = osku.SkuId,
StorageAmount = (osku.SingleStorageAmount * osku.ItemTotal) ?? 0M,
IsEnabled = true,
IsEstimateCost = true
};
ocd.CalculationSkuGrossProfit(osku.ShouldPay ?? 0M,
osku.PingTaiChengDanYouHuiQuan ?? 0M,
osku.SuperRedEnvelope ?? 0M,
osku.XianPinLeiDongQuan ?? 0M,
osku.VenderFee ?? 0M,
osku.JingDou ?? 0M,
osku.DongQuan ?? 0M,
osku.Balance ?? 0M,
shop.PlatformCommissionRatio ?? 0.05M);
}
}
}
catch (Exception ex)
{
nLogManager.GetLogger($"预估成本-{shop.ShopName}").Error(ex);
}
}
#endregion
}
}

4
BBWY.Server.Business/TaskSchedulerManager.cs

@ -34,6 +34,8 @@ namespace BBWY.Server.Business
public LimitedConcurrencyLevelTaskScheduler JDPromotionAutoStartTaskScheduler { get; private set; }
public LimitedConcurrencyLevelTaskScheduler SyncSkuYesterdayCostTaskScheduler { get; private set; }
public TaskSchedulerManager()
{
RepairOrderTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(5);
@ -55,6 +57,8 @@ namespace BBWY.Server.Business
JDPromotionAutoStartTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(10);
SyncPauseOrderTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(10);
SyncSkuYesterdayCostTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(10);
}
}
}

2
BBWY.Server.Model/BBWY.Server.Model.csproj

@ -7,7 +7,7 @@
<ItemGroup>
<PackageReference Include="AutoMapper" Version="10.1.1" />
<PackageReference Include="FreeSql" Version="2.6.100" />
<PackageReference Include="FreeSql" Version="3.2.805" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

6
BBWY.Server.Model/Db/Order/OrderCost.cs

@ -84,6 +84,12 @@ namespace BBWY.Server.Model.Db
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal AfterTotalCost { get; set; } = 0.0M;
/// <summary>
/// 是否为预估成本
/// </summary>
[Column(DbType = "bit")]
public bool IsEstimateCost { get; set; }
}
}

9
BBWY.Server.Model/Db/Order/OrderCostDetail.cs

@ -104,6 +104,7 @@ namespace BBWY.Server.Model.Db
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal SkuGrossProfit { get; set; } = 0.00M;
/// <summary>
/// 总计
/// </summary>
@ -115,8 +116,12 @@ namespace BBWY.Server.Model.Db
return SkuAmount + PurchaseFreight + FirstFreight + InStorageAmount + OutStorageAmount + StorageAmount + ConsumableAmount;
}
}
//[Column(DbType = "decimal(20,2)")]
//public decimal TotalCost { get; set; } = 0.00M;
/// <summary>
/// 是否为预估成本
/// </summary>
[Column(DbType = "bit")]
public bool IsEstimateCost { get; set; }
}
}

94
BBWY.Server.Model/Db/Order/SkuRecentCost.cs

@ -0,0 +1,94 @@
using FreeSql.DataAnnotations;
using System;
namespace BBWY.Server.Model.Db
{
[Table(Name = "skurecentcost", DisableSyncStructure = true)]
public partial class SkuRecentCost
{
[Column(StringLength = 50, IsPrimary = true, IsNullable = false)]
public string SkuId { get; set; }
[Column(DbType = "datetime")]
public DateTime? CreateTime { get; set; }
[Column(StringLength = 50)]
public string ProductId { get; set; }
/// <summary>
/// 最近一笔订单来源
/// </summary>
[Column(StringLength = 50)]
public string RecentOrderId { get; set; }
[Column(DbType = "bigint")]
public long? ShopId { get; set; }
/// <summary>
/// 耗材费(单件)
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal? SingleConsumableAmount { get; set; } = 0.00M;
/// <summary>
/// 发货运费(单件)
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal? SingleDeliveryFreight { get; set; } = 0.00M;
/// <summary>
/// 头程运费(单件)
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal? SingleFirstFreight { get; set; }
/// <summary>
/// 采购运费(单件)
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal? SingleFreight { get; set; } = 0.00M;
/// <summary>
/// 入仓操作费(单件)
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal? SingleInStorageAmount { get; set; } = 0.00M;
/// <summary>
/// 操作费(单件)
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal? SingleOperationAmount { get; set; } = 0.00M;
/// <summary>
/// 出仓操作费(单件)
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal? SingleOutStorageAmount { get; set; } = 0.00M;
/// <summary>
/// 退货入仓操作费(单件)
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal? SingleRefundInStorageAmount { get; set; } = 0.00M;
/// <summary>
/// SKU成本(单件)
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal? SingleSkuAmount { get; set; }
/// <summary>
/// 仓储费(单件)
/// </summary>
[Column(DbType = "decimal(20,2)")]
public decimal? SingleStorageAmount { get; set; } = 0.00M;
[Column(DbType = "datetime")]
public DateTime? UpdateTime { get; set; }
}
}

15
BBWY.Server.Model/Dto/Request/Sync/SkuRecentCostRequest.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BBWY.Server.Model.Dto
{
public class SkuRecentCostRequest
{
public long? ShopId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
}

4
BBWY.Test/BBWY.Test.csproj

@ -18,8 +18,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FreeSql" Version="2.6.100" />
<PackageReference Include="FreeSql.Provider.MySql" Version="2.6.100" />
<PackageReference Include="FreeSql" Version="3.2.805" />
<PackageReference Include="FreeSql.Provider.MySql" Version="3.2.805" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NLog" Version="4.7.12" />
</ItemGroup>

4
JD.API/JD.API.csproj

@ -6,8 +6,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FreeSql" Version="2.6.100" />
<PackageReference Include="FreeSql.Provider.MySql" Version="2.6.100" />
<PackageReference Include="FreeSql" Version="3.2.805" />
<PackageReference Include="FreeSql.Provider.MySql" Version="3.2.805" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.21" />
<PackageReference Include="NLog" Version="4.7.12" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />

Loading…
Cancel
Save