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