From 4d7042b89c38e2813f0c27146603d12feec2585b Mon Sep 17 00:00:00 2001 From: shanj <18996038927@163.com> Date: Sun, 3 Dec 2023 01:40:48 +0800 Subject: [PATCH] sbf --- SBF.API/Controllers/AutoTaskController.cs | 36 ++++ SBF.API/Controllers/TrusteeshipController.cs | 10 + SBF.Business/AutoTaskBusiness.cs | 94 +++++++++ SBF.Business/TaskSchedulerManager.cs | 11 +- SBF.Business/TrusteeshipBusiness.cs | 38 +++- SBF.Business/VenderBusiness.cs | 22 ++ SBF.Model/Db/Mds/Shops.cs | 192 ++++++++++++++++++ .../Db/Trusteeship/Sbf_TrusteeshipTask.cs | 11 + .../Request/TrusteeshipTaskMonitorRequest.cs | 7 + .../Dto/Response/TrusteeshipTaskResponse.cs | 10 + 10 files changed, 412 insertions(+), 19 deletions(-) create mode 100644 SBF.API/Controllers/AutoTaskController.cs create mode 100644 SBF.Business/AutoTaskBusiness.cs create mode 100644 SBF.Business/VenderBusiness.cs create mode 100644 SBF.Model/Db/Mds/Shops.cs create mode 100644 SBF.Model/Dto/Request/TrusteeshipTaskMonitorRequest.cs diff --git a/SBF.API/Controllers/AutoTaskController.cs b/SBF.API/Controllers/AutoTaskController.cs new file mode 100644 index 0000000..f6dd7f7 --- /dev/null +++ b/SBF.API/Controllers/AutoTaskController.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Mvc; +using SBF.Business; +using SBF.Model.Dto; + +namespace SBF.API.Controllers +{ + + public class AutoTaskController : BaseApiController + { + private AutoTaskBusiness autoTaskBusiness; + + public AutoTaskController(IHttpContextAccessor httpContextAccessor, AutoTaskBusiness autoTaskBusiness) : base(httpContextAccessor) + { + this.autoTaskBusiness = autoTaskBusiness; + } + + /// + /// 统计全店托管任务 + /// + [HttpPost] + public void StartAllShopTrusteeshipTaskStatistics() + { + autoTaskBusiness.StartTrusteeshipTaskStatistics(new TrusteeshipTaskMonitorRequest() { ShopId = null }); + } + + /// + /// 统计指定店铺托管任务 + /// + /// + [HttpPost] + public void StartTrusteeshipTaskStatistics(TrusteeshipTaskMonitorRequest request) + { + autoTaskBusiness.StartTrusteeshipTaskStatistics(request); + } + } +} diff --git a/SBF.API/Controllers/TrusteeshipController.cs b/SBF.API/Controllers/TrusteeshipController.cs index b58bc17..bed9fef 100644 --- a/SBF.API/Controllers/TrusteeshipController.cs +++ b/SBF.API/Controllers/TrusteeshipController.cs @@ -56,6 +56,16 @@ namespace SBF.API.Controllers trusteeshipBusiness.StopTrusteeship(id); } + /// + /// 删除托管 + /// + /// + [HttpPost("id")] + public void DeleteTrusteehip([FromRoute] long id) + { + trusteeshipBusiness.DeleteTrusteehip(id); + } + /// /// 查询托管任务曲线图详情 /// diff --git a/SBF.Business/AutoTaskBusiness.cs b/SBF.Business/AutoTaskBusiness.cs new file mode 100644 index 0000000..bf00b04 --- /dev/null +++ b/SBF.Business/AutoTaskBusiness.cs @@ -0,0 +1,94 @@ +using FreeSql; +using SBF.Common.Log; +using SBF.Common.Models; +using SBF.Model.Db; +using SBF.Model.Dto; +using SiNan.Business; +using Yitter.IdGenerator; + +namespace SBF.Business +{ + public class AutoTaskBusiness : BaseBusiness, IDenpendency + { + private VenderBusiness venderBusiness; + private TaskSchedulerManager taskSchedulerManager; + + public AutoTaskBusiness(IFreeSql fsql, NLogManager nLogManager, IIdGenerator idGenerator, VenderBusiness venderBusiness, TaskSchedulerManager taskSchedulerManager) : base(fsql, nLogManager, idGenerator) + { + this.venderBusiness = venderBusiness; + this.taskSchedulerManager = taskSchedulerManager; + } + + public void StartTrusteeshipTaskStatistics(TrusteeshipTaskMonitorRequest request) + { + var shopList = venderBusiness.GetShopList(request.ShopId); + foreach (var shop in shopList) + { + Task.Factory.StartNew(() => TrusteeshipTaskStatistics(long.Parse(shop.ShopId)), CancellationToken.None, TaskCreationOptions.LongRunning, taskSchedulerManager.TaskMonitorScheduler); + } + } + + private void TrusteeshipTaskStatistics(long shopId) + { + var inTrusteeshipTaskList = fsql.Select().Where(s => s.ShopId == shopId && s.IsEnd == false && s.IsEnabled == true) + .ToList(); + + if (inTrusteeshipTaskList.Count() == 0) + return; + + var mindate = inTrusteeshipTaskList.Min(s => s.StartTrusteeshipDate); + var maxdate = DateTime.Now.Date.AddDays(-1); + + if (maxdate < mindate) + return; + + var skuIdList = inTrusteeshipTaskList.Select(s => s.SkuId).Distinct().ToList(); + + #region 推广花费 + var adskudailyAggregationList = fsql.Select() + .Where(x => x.ShopId == shopId && + x.Date >= mindate && x.Date <= maxdate && + skuIdList.Contains(x.SkuId)) + .ToList(x => new + { + x.Date, + x.SkuId, + x.CampaignId, + x.BusinessType, + x.Cost + }); + #endregion + + #region SKU商品营业额 + var actualAmountList = fsql.Select() + .Where(x => x.ShopId == shopId && + x.Date >= mindate && x.Date <= maxdate && + skuIdList.Contains(x.SkuId)) + .ToList(x => new + { + x.Date, + x.SkuId, + //x.Cost, + x.ActualAmount + }); + + #endregion + + IList> updateList = new List>(); + foreach (var task in inTrusteeshipTaskList) + { + task.CostInTrusteeship = adskudailyAggregationList.Where(x => x.SkuId == task.SkuId && x.CampaignId == task.CampaignId).Sum(x => x.Cost); + task.ActualAmountInTrusteeship = actualAmountList.Where(x => x.SkuId == task.SkuId).Sum(x => x.ActualAmount); + var update = fsql.Update(task.Id).Set(t => t.CostInTrusteeship, task.CostInTrusteeship) + .Set(t => t.ActualAmountInTrusteeship, task.ActualAmountInTrusteeship); + updateList.Add(update); + } + + fsql.Transaction(() => + { + foreach (var update in updateList) + update.ExecuteAffrows(); + }); + } + } +} diff --git a/SBF.Business/TaskSchedulerManager.cs b/SBF.Business/TaskSchedulerManager.cs index 9c1d764..74e1c2c 100644 --- a/SBF.Business/TaskSchedulerManager.cs +++ b/SBF.Business/TaskSchedulerManager.cs @@ -4,18 +4,11 @@ namespace SBF.Business { public class TaskSchedulerManager { - public LimitedConcurrencyLevelTaskScheduler AggregationSpuGOIScheduler { get; private set; } - - - public LimitedConcurrencyLevelTaskScheduler AggregationCampaignGOIScheduler { get; private set; } - - public LimitedConcurrencyLevelTaskScheduler AggregationAdGroupGOIScheduler { get; private set; } + public LimitedConcurrencyLevelTaskScheduler TaskMonitorScheduler { get; set; } public TaskSchedulerManager() { - AggregationSpuGOIScheduler = new LimitedConcurrencyLevelTaskScheduler(5); - AggregationCampaignGOIScheduler = new LimitedConcurrencyLevelTaskScheduler(5); - AggregationAdGroupGOIScheduler = new LimitedConcurrencyLevelTaskScheduler(5); + TaskMonitorScheduler = new LimitedConcurrencyLevelTaskScheduler(5); } } } diff --git a/SBF.Business/TrusteeshipBusiness.cs b/SBF.Business/TrusteeshipBusiness.cs index ec4f3d6..3523853 100644 --- a/SBF.Business/TrusteeshipBusiness.cs +++ b/SBF.Business/TrusteeshipBusiness.cs @@ -63,7 +63,7 @@ namespace SBF.Business .WhereIf(skuList.Count() > 1, (ads, c, ad) => skuList.Contains(ads.Sku)) .WhereIf(skuList.Count() == 1, (ads, c, ad) => ads.Sku == skuList[0]) .Where((ads, c, ad) => !fsql.Select() - .Where(s => s.ShopId == request.ShopId && s.CampaignId == ads.CampaignId && s.SkuId == ads.Sku) + .Where(s => s.ShopId == request.ShopId && s.CampaignId == ads.CampaignId && s.SkuId == ads.Sku && s.IsEnabled == true) .Any()) .GroupBy((ads, c, ad) => new { ads.BusinessType, ads.CampaignId, c.CampaignName, ads.AdGroupId, ad.AdGroupName, ads.AdId, ads.AdName, ads.Sku }) .ToList(g => new SkuJoinPopularizeChannelResponse @@ -85,8 +85,6 @@ namespace SBF.Business /// 查询托管任务 /// /// - /// - /// /// /// public ListResponse QueryTrusteeship(QueryTrusteeshipRequest request) @@ -97,7 +95,9 @@ namespace SBF.Business var list = fsql.Select() .InnerJoin((t, p, ps) => t.SpuId == p.Id) .InnerJoin((t, p, ps) => t.SkuId == ps.Id) - .Where((t, p, ps) => t.ShopId == request.ShopId && t.BusinessType == request.BusinessType) + .Where((t, p, ps) => t.ShopId == request.ShopId && + t.BusinessType == request.BusinessType && + t.IsEnabled == true) .WhereIf(request.Stage != null, (t, p, ps) => p.Stage == request.Stage) .WhereIf(!string.IsNullOrEmpty(request.Spu), (t, p, ps) => t.SpuId == request.Spu) .WhereIf(!string.IsNullOrEmpty(request.Sku), (t, p, ps) => t.SkuId == request.Sku) @@ -126,10 +126,12 @@ namespace SBF.Business CampaignId = t.CampaignId, CostInTrusteeship = t.CostInTrusteeship, CreateTime = t.CreateTime, + UpdateTime = t.UpdateTime, EndTime = t.EndTime, IsEnd = t.IsEnd, StartTrusteeshipDate = t.StartTrusteeshipDate, PolicyType = t.PolicyType, + IsEnabled = t.IsEnabled, Logo = ps.Logo, Price = ps.Price, @@ -179,7 +181,7 @@ namespace SBF.Business { x.Date, x.SkuId, - x.Cost, + //x.Cost, x.ActualAmount }); @@ -197,8 +199,7 @@ namespace SBF.Business foreach (var task in list) { task.CostByDateList = costList.Where(x => x.SkuId == task.SkuId && - x.CampaignId == task.CampaignId && - x.BusinessType == task.BusinessType) + x.CampaignId == task.CampaignId) .OrderBy(x => x.Date) .Select(x => new NumberByDate() { @@ -257,7 +258,8 @@ namespace SBF.Business StartTrusteeshipDate = DateTime.Now.Date.AddDays(1), ShopId = request.ShopId, SkuId = x.Sku, - PolicyType = Model.Enums.PolicyType.成长期策略包 + PolicyType = Model.Enums.PolicyType.成长期策略包, + IsEnabled = true }).ToList(); var skuIdList = insertList.Select(x => x.SkuId).Distinct().ToList(); @@ -277,16 +279,30 @@ namespace SBF.Business return; fsql.Update(id).Set(t => t.IsEnd, true) .Set(t => t.EndTime, DateTime.Now) + .Set(t => t.UpdateTime, DateTime.Now) .ExecuteAffrows(); } - public TrusteeshipTaskResponse GetTrusteeshipTaskCurveResponse(long Id) + public void DeleteTrusteehip(long id) { + var task = fsql.Select(id).ToOne(); + if (task == null) + throw new BusinessException("托管任务不存在"); + if (task.IsEnabled == false) + return; + fsql.Update(id).Set(t => t.IsEnabled, false) + .Set(t => t.IsEnd, true) + .Set(t => t.EndTime, DateTime.Now) + .Set(t => t.UpdateTime, DateTime.Now) + .ExecuteAffrows(); + } + public TrusteeshipTaskResponse GetTrusteeshipTaskCurveResponse(long Id) + { var task = fsql.Select() .InnerJoin((t, p, ps) => t.SpuId == p.Id) .InnerJoin((t, p, ps) => t.SkuId == ps.Id) - .Where((t, p, ps) => t.Id == Id) + .Where((t, p, ps) => t.Id == Id && t.IsEnabled == true) .OrderByDescending((t, p, ps) => t.CreateTime) .ToOne((t, p, ps) => new Sbf_TrusteeshipTask() { @@ -307,10 +323,12 @@ namespace SBF.Business CampaignId = t.CampaignId, CostInTrusteeship = t.CostInTrusteeship, CreateTime = t.CreateTime, + UpdateTime = t.UpdateTime, EndTime = t.EndTime, IsEnd = t.IsEnd, StartTrusteeshipDate = t.StartTrusteeshipDate, PolicyType = t.PolicyType, + IsEnabled = t.IsEnabled, Logo = ps.Logo, Price = ps.Price, diff --git a/SBF.Business/VenderBusiness.cs b/SBF.Business/VenderBusiness.cs new file mode 100644 index 0000000..9f9f381 --- /dev/null +++ b/SBF.Business/VenderBusiness.cs @@ -0,0 +1,22 @@ +using SBF.Common.Models; +using SBF.Model.Db.Mds; + +namespace SBF.Business +{ + public class VenderBusiness : IDenpendency + { + private FreeSqlMultiDBManager freeSqlMultiDBManager; + public VenderBusiness(FreeSqlMultiDBManager freeSqlMultiDBManager) + { + this.freeSqlMultiDBManager = freeSqlMultiDBManager; + } + + public IList GetShopList(long? shopId = null) + { + return freeSqlMultiDBManager.MDSfsql.Select().Where(s => !string.IsNullOrEmpty(s.ShopId)) + .WhereIf(shopId != null, s => s.ShopId == shopId.ToString()) + .Where(s => s.IsEnabled == true) + .ToList(); + } + } +} diff --git a/SBF.Model/Db/Mds/Shops.cs b/SBF.Model/Db/Mds/Shops.cs new file mode 100644 index 0000000..8c3193b --- /dev/null +++ b/SBF.Model/Db/Mds/Shops.cs @@ -0,0 +1,192 @@ +using FreeSql.DataAnnotations; +using System; + +namespace SBF.Model.Db.Mds +{ + + [Table(Name = "shops", DisableSyncStructure = true)] + public partial class Shops + { + + /// + /// Id + /// + [Column(StringLength = 50, IsPrimary = true, IsNullable = false)] + public string Id { get; set; } + + /// + /// 店铺Key + /// + + public string AppKey { get; set; } + + /// + /// 店铺Secret + /// + + public string AppSecret { get; set; } + + /// + /// 店铺Token + /// + + public string AppToken { get; set; } + + /// + /// 店铺Key 暂定商品管理Key + /// + + public string AppKey2 { get; set; } + + /// + /// 店铺Secret 暂定商品管理Secret + /// + + public string AppSecret2 { get; set; } + + /// + /// 店铺Token + /// + + public string AppToken2 { get; set; } + + /// + /// 创建时间 + /// + [Column(DbType = "datetime")] + public DateTime CreateTime { get; set; } + + /// + /// 创建人Id + /// + [Column(StringLength = 50)] + public string CreatorId { get; set; } + + /// + /// 创建人 + /// + [Column(StringLength = 50, IsNullable = false)] + public string CreatorRealName { get; set; } + + /// + /// 0淘宝,1京东,2阿里巴巴 + /// + + public int? PlatformId { get; set; } + + /// + /// 平台名称 + /// + [Column(StringLength = 50)] + public string PlatformName { get; set; } + + + public string PurchaseAppKey { get; set; } + + + public string PurchaseAppSecret { get; set; } + + /// + /// 采购平台 + /// + [Column(StringLength = 50)] + public string PurchasePlatformId { get; set; } + + + /// + /// 商家编号 + /// + public string VenderId { get; set; } + + /// + /// 店铺ID + /// + + public string ShopId { get; set; } + + + public string ShopName { get; set; } + + /// + /// 店铺账号 + /// + + public string ShopNick { get; set; } + + /// + /// 店铺类型 + /// + + public string ShopType { get; set; } + + public string ManagePwd { get; set; } + + [Column(DbType = "decimal(11,2)")] + public decimal? PlatformCommissionRatio { get; set; } + + /// + /// SKU库存安全周转天数 + /// + public int SkuSafeTurnoverDays { get; set; } + + /// + /// 钉钉WebHook地址 + /// + [Column(StringLength = 255)] + public string DingDingWebHook { get; set; } + + /// + /// 钉钉密钥 + /// + [Column(StringLength = 100)] + public string DingDingKey { get; set; } + + + /// + /// 司南策略等级 + /// + public int SiNanPolicyLevel { get; set; } + + /// + /// 司南钉钉WebHook地址 + /// + [Column(StringLength = 255)] + public string SiNanDingDingWebHook { get; set; } + + /// + /// 司南钉钉密钥 + /// + [Column(StringLength = 100)] + public string SiNanDingDingKey { get; set; } + + /// + /// PJZS钉钉WebHook地址 + /// + [Column(StringLength = 255)] + public string PJZSDingDingWebHook { get; set; } + + /// + /// PJZS钉钉密钥 + /// + [Column(StringLength = 100)] + public string PJZSDingDingKey { get; set; } + + + + /// + /// 齐库钉钉WebHook地址 + /// + [Column(StringLength = 255)] + public string QiKuDingDingWebHook { get; set; } + + /// + /// 齐库钉钉密钥 + /// + [Column(StringLength = 100)] + public string QiKuDingDingKey { get; set; } + + [Column(DbType = "bit", IsNullable = true)] + public bool? IsEnabled { get; set; } = true; + } + +} diff --git a/SBF.Model/Db/Trusteeship/Sbf_TrusteeshipTask.cs b/SBF.Model/Db/Trusteeship/Sbf_TrusteeshipTask.cs index c093870..0f3cc8d 100644 --- a/SBF.Model/Db/Trusteeship/Sbf_TrusteeshipTask.cs +++ b/SBF.Model/Db/Trusteeship/Sbf_TrusteeshipTask.cs @@ -88,6 +88,12 @@ namespace SBF.Model.Db [Column(DbType = "datetime")] public DateTime? CreateTime { get; set; } + /// + /// 更新时间 + /// + [Column(DbType = "datetime")] + public DateTime? UpdateTime { get; set; } + /// /// 托管结束时间 /// @@ -117,6 +123,11 @@ namespace SBF.Model.Db [Column(MapType = typeof(int?))] public Enums.PolicyType? PolicyType { get; set; } = Enums.PolicyType.成长期策略包; + /// + /// 是否有效 + /// + public bool? IsEnabled { get; set; } = true; + #region Product [Column(IsIgnore = true)] public DateTime? ProductCreateTime { get; set; } diff --git a/SBF.Model/Dto/Request/TrusteeshipTaskMonitorRequest.cs b/SBF.Model/Dto/Request/TrusteeshipTaskMonitorRequest.cs new file mode 100644 index 0000000..306265e --- /dev/null +++ b/SBF.Model/Dto/Request/TrusteeshipTaskMonitorRequest.cs @@ -0,0 +1,7 @@ +namespace SBF.Model.Dto +{ + public class TrusteeshipTaskMonitorRequest + { + public long? ShopId { get; set; } + } +} diff --git a/SBF.Model/Dto/Response/TrusteeshipTaskResponse.cs b/SBF.Model/Dto/Response/TrusteeshipTaskResponse.cs index fd4891e..217ecf6 100644 --- a/SBF.Model/Dto/Response/TrusteeshipTaskResponse.cs +++ b/SBF.Model/Dto/Response/TrusteeshipTaskResponse.cs @@ -100,6 +100,11 @@ namespace SBF.Model.Dto /// public DateTime CreateTime { get; set; } + /// + /// 更新时间 + /// + public DateTime? UpdateTime { get; set; } + /// /// 托管结束时间 /// @@ -110,6 +115,11 @@ namespace SBF.Model.Dto /// public bool IsEnd { get; set; } + /// + /// 是否有效 + /// + public bool? IsEnabled { get; set; } = true; + /// /// 开始计算托管日期 ///