12 changed files with 472 additions and 11 deletions
@ -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); |
|||
} |
|||
} |
|||
} |
@ -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
|
|||
} |
|||
} |
@ -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; } |
|||
|
|||
} |
|||
|
|||
} |
@ -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; } |
|||
} |
|||
} |
Loading…
Reference in new issue