From 5047f1d47b89f234b7e5936598a89c5bd6fe45b1 Mon Sep 17 00:00:00 2001
From: "506583276@qq.com" <506583276@qq.com>
Date: Sun, 3 Dec 2023 09:41:00 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=89=98=E7=AE=A1=E6=89=A7?=
=?UTF-8?q?=E8=A1=8C=E7=AD=96=E7=95=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ExecuteTrusteeshipPolicyController.cs | 87 +++
SBF.API/Extentions/HostExtentions.cs | 60 ++
SBF.API/Program.cs | 6 +
SBF.API/SBF.API.csproj | 1 +
SBF.API/appsettings.json | 4 +
.../ExecuteTrusteeshipPolicyBusiness.cs | 586 ++++++++++++++++++
SBF.Business/SBF.Business.csproj | 1 +
SBF.Common/Extensions/ConverterExtensions.cs | 2 +
SBF.Model/Db/Trusteeship/Sbf_AdjustLog.cs | 52 ++
.../Db/Trusteeship/Sbf_TrusteeshipTask.cs | 18 +
.../BatchUpdateBidPriceRequest.cs | 60 ++
.../BatchUpdateBudgetRequest.cs | 43 ++
SBF.Model/Enums.cs | 16 +
SBF.Model/SBF.Model.csproj | 1 +
14 files changed, 937 insertions(+)
create mode 100644 SBF.API/Controllers/ExecuteTrusteeshipPolicyController.cs
create mode 100644 SBF.API/Extentions/HostExtentions.cs
create mode 100644 SBF.Business/ExecuteTrusteeshipPolicyBusiness.cs
create mode 100644 SBF.Model/Db/Trusteeship/Sbf_AdjustLog.cs
create mode 100644 SBF.Model/Dto/Request/ExecuteTrusteeshipPolicy/BatchUpdateBidPriceRequest.cs
create mode 100644 SBF.Model/Dto/Request/ExecuteTrusteeshipPolicy/BatchUpdateBudgetRequest.cs
diff --git a/SBF.API/Controllers/ExecuteTrusteeshipPolicyController.cs b/SBF.API/Controllers/ExecuteTrusteeshipPolicyController.cs
new file mode 100644
index 0000000..48d427b
--- /dev/null
+++ b/SBF.API/Controllers/ExecuteTrusteeshipPolicyController.cs
@@ -0,0 +1,87 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using SBF.Business;
+using SBF.Model.Dto;
+
+namespace SBF.API.Controllers
+{
+ ///
+ /// 执行托管策略
+ ///
+ public class ExecuteTrusteeshipPolicyController : BaseApiController
+ {
+
+ private ExecuteTrusteeshipPolicyBusiness executeTrusteeshipPolicyBusiness;
+
+ public ExecuteTrusteeshipPolicyController(IHttpContextAccessor httpContextAccessor, ExecuteTrusteeshipPolicyBusiness executeTrusteeshipPolicyBusiness) : base(httpContextAccessor)
+ {
+ this.executeTrusteeshipPolicyBusiness = executeTrusteeshipPolicyBusiness;
+ }
+
+ ///
+ /// 批量上传店铺预算数据(回调地址)
+ ///
+ ///
+ [HttpPost]
+ [AllowAnonymous]
+ public async Task BatchUpdateBudget(BatchUpdateBudgetRequest[] requestList)
+ {
+ await executeTrusteeshipPolicyBusiness.BatchUpdateBudget(requestList);
+ }
+
+
+ ///
+ /// 批量上传店铺单元出价数据(回调地址)
+ ///
+ ///
+ [HttpPost]
+ [AllowAnonymous]
+ public async Task BatchUpdateBidPrice(BatchUpdateBidPriceRequest[] requestList)
+ {
+ await executeTrusteeshipPolicyBusiness.BatchUpdateBidPrice(requestList);
+ }
+
+ ///
+ /// 更新策略数据(当日预算. 出价 ,当前时间花费情况) 9:00
+ ///
+ [HttpGet]
+ [AllowAnonymous]
+ public async Task UpdateTrusteeshipPolicyData()
+ {
+ await executeTrusteeshipPolicyBusiness.UpdateTrusteeshipPolicyData();
+ }
+
+ ///
+ /// 判断 预算耗尽 更新出价 花费 预算
+ ///
+ ///
+ [HttpGet]
+ [AllowAnonymous]
+ public async Task JudgeBudgetCostOutUpdateTrusteeshipPolicyData()
+ {
+ await executeTrusteeshipPolicyBusiness.JudgeBudgetCostOutUpdateTrusteeshipPolicyData();
+ }
+
+
+ ///
+ /// 运行成长期调高出价策略
+ ///
+ ///
+ [HttpGet]
+ [AllowAnonymous]
+ public async Task RunGrowthPeriodIncreaseBidPriceTrusteeshipPolicy()
+ {
+ await executeTrusteeshipPolicyBusiness.RunGrowthPeriodIncreaseBidPriceTrusteeshipPolicy();
+ }
+ ///
+ /// 运行成长期降低出价策略
+ ///
+ ///
+ [HttpGet]
+ [AllowAnonymous]
+ public async Task RunGrowthPeriodLowerBidPriceTrusteeshipPolicy()
+ {
+ await executeTrusteeshipPolicyBusiness.RunGrowthPeriodLowerBidPriceTrusteeshipPolicy();
+ }
+ }
+}
diff --git a/SBF.API/Extentions/HostExtentions.cs b/SBF.API/Extentions/HostExtentions.cs
new file mode 100644
index 0000000..ffc65e7
--- /dev/null
+++ b/SBF.API/Extentions/HostExtentions.cs
@@ -0,0 +1,60 @@
+using CSRedis;
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Caching.Redis;
+using System.Security.AccessControl;
+
+
+namespace SBF.API.Extentions
+{
+ public static class HostExtentions
+ {
+ ///
+ /// 使用缓存
+ ///
+ /// 建造者
+ ///
+ public static IHostBuilder UseCache(this IHostBuilder hostBuilder)
+ {
+
+
+ hostBuilder.ConfigureServices((buidlerContext, services) =>
+ {
+ var cacheOption = buidlerContext.Configuration.GetSection("Cache").Get();
+ switch (cacheOption.CacheType)
+ {
+ case CacheType.Memory: services.AddDistributedMemoryCache(); break;
+ case CacheType.Redis:
+ {
+ var csredis = new CSRedisClient(cacheOption.RedisEndpoint);
+ RedisHelper.Initialization(csredis);
+ services.AddSingleton(csredis);
+ services.AddSingleton(new CSRedisCache(RedisHelper.Instance));
+ }; break;
+ default: throw new Exception("缓存类型无效");
+ }
+ });
+
+ return hostBuilder;
+ }
+
+ }
+ internal class CacheOptions
+ {
+ public CacheType CacheType { get; set; }
+ public string RedisEndpoint { get; set; }
+ } ///
+ /// 缓存类型
+ ///
+ public enum CacheType
+ {
+ ///
+ /// 使用内存缓存(不支持分布式)
+ ///
+ Memory,
+
+ ///
+ /// 使用Redis缓存(支持分布式)
+ ///
+ Redis
+ }
+}
diff --git a/SBF.API/Program.cs b/SBF.API/Program.cs
index 7ee8d88..786ddac 100644
--- a/SBF.API/Program.cs
+++ b/SBF.API/Program.cs
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Serialization;
+using SBF.API.Extentions;
using SBF.API.Filters;
using SBF.API.Middlewares;
using SBF.Business;
@@ -13,9 +14,14 @@ using System.Reflection;
using Yitter.IdGenerator;
var builder = WebApplication.CreateBuilder(args);
+builder.Host.UseCache();
+
var services = builder.Services;
var configuration = builder.Configuration;
+
+
+
services.AddMemoryCache();
var idOption = new IdGeneratorOptions(1);
var idGenerator = new DefaultIdGenerator(idOption);
diff --git a/SBF.API/SBF.API.csproj b/SBF.API/SBF.API.csproj
index 0f5e3ae..663998e 100644
--- a/SBF.API/SBF.API.csproj
+++ b/SBF.API/SBF.API.csproj
@@ -8,6 +8,7 @@
+
diff --git a/SBF.API/appsettings.json b/SBF.API/appsettings.json
index 5306809..c8a7ec0 100644
--- a/SBF.API/appsettings.json
+++ b/SBF.API/appsettings.json
@@ -5,6 +5,10 @@
"Microsoft.AspNetCore": "Warning"
}
},
+ "Cache": {
+ "CacheType": "Redis",
+ "RedisEndpoint": "116.62.61.68:6379"
+ },
"AllowedHosts": "*",
"Secret": "D96BFA5B-F2AF-45BC-9342-5A55C3F9BBB0",
"ConnectionStrings": {
diff --git a/SBF.Business/ExecuteTrusteeshipPolicyBusiness.cs b/SBF.Business/ExecuteTrusteeshipPolicyBusiness.cs
new file mode 100644
index 0000000..456586a
--- /dev/null
+++ b/SBF.Business/ExecuteTrusteeshipPolicyBusiness.cs
@@ -0,0 +1,586 @@
+using Google.Protobuf.WellKnownTypes;
+using Microsoft.Extensions.Caching.Distributed;
+using Newtonsoft.Json;
+using NLog;
+using SBF.Common.Log;
+using SBF.Common.Models;
+using SBF.Model.Db;
+using SBF.Model.Db.Trusteeship;
+using SBF.Model.Dto;
+using SiNan.Business;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using Yitter.IdGenerator;
+
+namespace SBF.Business
+{
+ ///
+ /// 执行托管策略
+ ///
+ public class ExecuteTrusteeshipPolicyBusiness : BaseBusiness, IDenpendency
+ {
+
+ ILogger logger;
+ public ExecuteTrusteeshipPolicyBusiness(IFreeSql fsql, NLogManager nLogManager, IIdGenerator idGenerator, IDistributedCache cache) : base(fsql, nLogManager, idGenerator)
+ {
+ logger = nLogManager.GetLogger("执行托管策略");
+ _cache = cache;
+
+ }
+
+
+ readonly IDistributedCache _cache;
+
+ string host = "http://api.sbf.qiyue666.com/";
+
+ ///
+ /// 回调出价和花费
+ ///
+ ///
+ ///
+ ///
+ public async Task BatchUpdateBidPrice(BatchUpdateBidPriceRequest[] requestList)
+ {
+
+
+ var AdgroupIdList = requestList.Select(r => long.Parse(r.AdgroupId)).ToList();
+ var trusteeshipTaskList = fsql.Select().Where(s => s.AdGroupId != null && AdgroupIdList.Contains(s.AdGroupId.Value)).ToList();
+ foreach (var trusteeshipTask in trusteeshipTaskList)
+ {
+ var newData = requestList.FirstOrDefault(t => t.AdgroupId == trusteeshipTask.AdGroupId?.ToString());
+
+ if (newData != null)
+ {
+ trusteeshipTask.BidPrice = newData.SearchFee;//当前出价
+ trusteeshipTask.NowCost = newData.TotalCost;//当前总花费
+ continue;
+ }
+
+ }
+ if (trusteeshipTaskList.Any())
+ await fsql.Update(trusteeshipTaskList).ExecuteUpdatedAsync();
+
+
+ logger.Info($"回调出价和花费成功!回调消息:{JsonConvert.SerializeObject(requestList)}");
+
+ }
+
+ ///
+ /// 回调预算
+ ///
+ ///
+ ///
+ ///
+ public async Task BatchUpdateBudget(BatchUpdateBudgetRequest[] requestList)
+ {
+
+ var CampaignIdList = requestList.Select(r => long.Parse(r.CampaignId)).ToList();
+ var trusteeshipTaskList = fsql.Select().Where(s => s.CampaignId != null && CampaignIdList.Contains(s.CampaignId.Value)).ToList();
+
+
+ foreach (var trusteeshipTask in trusteeshipTaskList)
+ {
+ var newData = requestList.FirstOrDefault(t => t.CampaignId == trusteeshipTask.CampaignId?.ToString());
+
+ if (newData != null)
+ {
+ trusteeshipTask.Budget = newData.Budget;
+ continue;
+ }
+
+ }
+ if (trusteeshipTaskList.Any())
+ await fsql.Update(trusteeshipTaskList).ExecuteUpdatedAsync();
+
+ logger.Info($"回调预算成功!回调消息:{JsonConvert.SerializeObject(requestList)}");
+ }
+
+
+
+
+ ///
+ /// 提交
+ ///
+ ///
+ ///
+ public async Task UpdateTrusteeshipPolicyData()
+ {
+ //获取当前待执行列表的数据
+ var searchTrusteeshipTaskList = FirstWeekUpdateTrusteeshipPolicyData();
+ searchTrusteeshipTaskList.AddRange(OverFirstWeekUpdateTrusteeshipPolicyData());
+ await UpdateTrusteeshipPolicyData(searchTrusteeshipTaskList);
+
+ await ThreeWeekUpdateBudget();//第三周或三周以上 每天初始化预算
+ }
+
+
+ private async Task UpdateTrusteeshipPolicyData(List searchTrusteeshipTaskList)
+ {
+ var shopIds = searchTrusteeshipTaskList.Select(s => s.ShopId).Distinct().ToList();
+
+
+
+
+ foreach (var shopId in shopIds)
+ {
+ var CampaignIds = searchTrusteeshipTaskList.Where(s => s.ShopId == shopId).Select(s => s.CampaignId).Distinct().ToArray();
+
+
+ /*
+ {
+"UserPin": "string",
+"ShopId": "string",
+"Start": "2023-12-02T06:08:15.492Z",
+"End": "2023-12-02T06:08:15.492Z",
+"ApiUrl": "string",
+"CampaignIds": [
+"string"
+]
+}
+ */
+ string url = "http://txapi.sbf.qiyue666.com/SanBanFu/Api/SendGetBudgetByCampaignList";
+ HttpClient client = new HttpClient();
+ client.Timeout = TimeSpan.FromMinutes(1);
+
+ var postData = JsonConvert.SerializeObject(new
+ {
+ ShopId = shopId.ToString(),
+ Start = DateTime.Now.ToString(),
+ End = DateTime.Now.ToString(),
+ ApiUrl = host + "api/ExecuteTrusteeshipPolicy/BatchUpdateBudget",
+ CampaignIds = CampaignIds
+ });
+
+ HttpContent content = new StringContent(postData);
+
+ var res = await client.PostAsync(url, content);
+ if (res.IsSuccessStatusCode)
+ {
+ //发送成功
+ logger.Info($"请求预算接口成功! 店铺id:{shopId},请求参数{postData}");
+
+ //todo: redis
+ //await _cache.SetStringAsync("SBF:GetBudget:shopId", "0");//0未处理 三板斧批量获取预算
+
+ }
+ else
+ {
+ logger.Error($"请求预算接口失败,返回消息:{res?.Content?.ReadAsStringAsync()?.Result}, 店铺id:{shopId},请求参数{postData}");
+ }
+ Thread.Sleep(500);
+ /*
+ {
+ "UserPin": "string",
+ "ShopId": "string",
+ "Start": "2023-12-02T06:59:26.115Z",
+ "End": "2023-12-02T06:59:26.115Z",
+ "ApiUrl": "string",
+ "AdgroupIds": [
+ "string"
+ ]
+ }
+ */
+
+ var adgroupIds = searchTrusteeshipTaskList.Where(s => s.ShopId == shopId).Select(s => s.AdGroupId).Distinct().ToArray();
+ url = "http://txapi.sbf.qiyue666.com/SanBanFu/Api/SendGetFeeByAdgroupList";
+ postData = JsonConvert.SerializeObject(new
+ {
+ ShopId = shopId.ToString(),
+ Start = DateTime.Now.ToString(),
+ End = DateTime.Now.ToString(),
+ ApiUrl = host + "api/ExecuteTrusteeshipPolicy/BatchUpdateBudget",
+ AdgroupIds = adgroupIds
+ });
+ content = new StringContent(postData);
+ res = await client.PostAsync("https://cactus.jd.com/request_algo?g_ty=ajax", content);
+ if (res.IsSuccessStatusCode)
+ {
+ //发送成功
+ logger.Info($"请求出价接口成功! 店铺id:{shopId},请求参数{postData}");
+
+ }
+ else
+ {
+ logger.Error($"请求出价接口失败,返回消息:{res?.Content?.ReadAsStringAsync()?.Result}, 店铺id:{shopId},请求参数{postData}");
+ }
+ Thread.Sleep(500);
+ }
+ }
+
+ ///
+ /// 第一周 只需更新一次
+ ///
+ ///
+ private List FirstWeekUpdateTrusteeshipPolicyData()
+ {
+ List excuteDate = new List();
+ DateTime nowDate = DateTime.Now.Date;
+
+ excuteDate.Add(nowDate.AddDays(4));
+ excuteDate.Add(nowDate.AddDays(7));
+ return fsql.Select().Where(s => s.IsEnd == false && s.PolicyType == Model.Enums.PolicyType.成长期策略包 && s.StartTrusteeshipDate != null && excuteDate.Contains(s.StartTrusteeshipDate.Value)).ToList();//
+ }
+ ///
+ /// 两周以上的(12:00 18:00 23:00要更新)
+ ///
+ ///
+ private List OverFirstWeekUpdateTrusteeshipPolicyData()
+ {
+ List excuteDate = new List();
+ DateTime nowDate = DateTime.Now.Date;
+
+ excuteDate.Add(nowDate.AddDays(11));
+ excuteDate.Add(nowDate.AddDays(14));
+ return fsql.Select().Where(s => s.IsEnd == false && s.PolicyType == Model.Enums.PolicyType.成长期策略包 && s.StartTrusteeshipDate != null && (excuteDate.Contains(s.StartTrusteeshipDate.Value) || nowDate.AddDays(-15) >= s.StartTrusteeshipDate.Value)).ToList();
+ }
+
+ ///
+ /// 更新
+ ///
+ private async Task ThreeWeekUpdateBudget()
+ {
+ DateTime nowDate = DateTime.Now.Date;
+ //第三周 或者三周以上的数据
+ var trusteeshipTaskList = fsql.Select().Where(s => s.IsEnd == false && s.PolicyType == Model.Enums.PolicyType.成长期策略包 && s.StartTrusteeshipDate != null && (nowDate.AddDays(-15) >= s.StartTrusteeshipDate.Value)).ToList();
+ var primarySkuIdList = trusteeshipTaskList.Select(d => d.PrimarySkuId).Distinct().ToList();
+ List excuteDate = new List
+ {
+ nowDate.AddDays(-1),
+ nowDate.AddDays(-2),
+ nowDate.AddDays(-3)
+ };
+
+ var primarySkuDailyList = fsql.Select().Where(a => primarySkuIdList.Contains(a.SkuId) && a.Date != null && excuteDate.Contains(a.Date.Value)).ToList();
+ List AdjustLogList = new List();
+
+ var update = fsql.Update();
+ foreach (var trusteeshipTask in trusteeshipTaskList)
+ {
+ var primarySkuProfit = primarySkuDailyList.Where(p => p.SkuId == trusteeshipTask.PrimarySkuId).Select(p => p.ProductLevelProfit - p.Cost).Average();//3天日均盈利
+
+ if (trusteeshipTask.AnchorBudget == null)
+ {
+ //todo: 提醒设置锚定预算
+ continue;
+ }
+ decimal newBudget = primarySkuProfit.Value + trusteeshipTask.AnchorBudget.Value;
+
+
+ string adjustContent = string.Empty;
+ if (primarySkuProfit < 0)
+ {
+ newBudget = trusteeshipTask.AnchorBudget.Value;
+
+ }
+ adjustContent = $"主Sku:{trusteeshipTask.PrimarySkuId},近三天日均收益:{primarySkuProfit}";
+ decimal oldBudget = trusteeshipTask.Budget.Value;//
+
+
+ trusteeshipTask.Budget = newBudget;//更新预算
+
+ update.Where(u => u.Id == trusteeshipTask.Id).Set(u=>u.Budget, newBudget);
+
+ //修改预算
+
+ //更新快车的 出价
+ string url = "http://txapi.sbf.qiyue666.com/SanBanFu/Api/SendBudgetUpdate";
+ HttpClient client = new HttpClient();
+ client.Timeout = TimeSpan.FromMinutes(1);
+
+ var postData = JsonConvert.SerializeObject(new
+ {
+ ShopId = trusteeshipTask.ShopId?.ToString(),
+ CampaignId = trusteeshipTask.CampaignId?.ToString(),
+ DayBudget = newBudget
+
+ });
+
+ HttpContent content = new StringContent(postData);
+
+ var res = await client.PostAsync("https://cactus.jd.com/request_algo?g_ty=ajax", content);
+ if (res.IsSuccessStatusCode)
+ {
+ //发送成功
+ logger.Info($"请求变更出价接口成功! 店铺id:{trusteeshipTask.ShopId},请求参数{postData}");
+
+ AdjustLogList.Add(new Sbf_AdjustLog
+ {
+ AdjustType = Model.Enums.AdjustType.出价,
+ AdjustWay = Model.Enums.AdjustWay.调高,
+ CreateTime = DateTime.Now,
+ PolicyType = Model.Enums.PolicyType.成长期策略包,
+ TrusteeshipTaskId = trusteeshipTask.Id,
+ OperateContent = $"{adjustContent},原预算:{oldBudget},调整后预算:{newBudget}"
+ });
+
+ }
+ else
+ {
+ logger.Error($"请求变更出价接口失败,返回消息:{res?.Content?.ReadAsStringAsync()?.Result}, 店铺id:{trusteeshipTask.ShopId},请求参数{postData}");
+ }
+ Thread.Sleep(500);
+ }
+
+ await update.ExecuteUpdatedAsync();//批量更新
+
+
+ if (AdjustLogList.Any())
+ await fsql.Insert(AdjustLogList).ExecuteInsertedAsync();
+
+ }
+
+
+
+
+
+ ///
+ /// 更新第二周 4 7天 和三周以上的数据
+ ///
+ ///
+ public async Task JudgeBudgetCostOutUpdateTrusteeshipPolicyData()
+ {
+ var searchTrusteeshipTaskList = OverFirstWeekUpdateTrusteeshipPolicyData();
+ await UpdateTrusteeshipPolicyData(searchTrusteeshipTaskList);
+ }
+
+
+ ///
+ /// 调高出价策略
+ ///
+ ///
+ ///
+ public async Task RunGrowthPeriodIncreaseBidPriceTrusteeshipPolicy()
+ {
+ /*
+ 4 7 11 14 14天以上
+ */
+ //获取当前待执行列表的数据
+ var searchTrusteeshipTaskList = FirstWeekUpdateTrusteeshipPolicyData();// 4 7天
+ searchTrusteeshipTaskList.AddRange(OverFirstWeekUpdateTrusteeshipPolicyData());//满足条件的数据
+
+ var adgroupIds = searchTrusteeshipTaskList.Select(s => s.AdGroupId).Distinct().ToArray();
+
+
+
+
+ //获取满足条件的所有单元 前三天花费的数据
+
+ List excuteDate = new List();
+ DateTime nowDate = DateTime.Now.Date;
+
+ excuteDate.Add(nowDate.AddDays(-1));
+ excuteDate.Add(nowDate.AddDays(-2));
+ excuteDate.Add(nowDate.AddDays(-3));
+
+
+
+
+ //获取前三天花费
+ var adgroupCostList = fsql.Select().Where(s => adgroupIds.Contains(s.AdGroupId) && s.Date != null && excuteDate.Contains(s.Date.Value)).ToList();
+
+
+ List AdjustLogList = new List();
+ var update = fsql.Update();
+ foreach (var trusteeshipTask in searchTrusteeshipTaskList)
+ {
+ var beforeThreeDayMaxCost = adgroupCostList.Where(a => a.AdGroupId == trusteeshipTask.AdGroupId).Select(s => s.Cost).Max();//前三天花费最高
+ if (trusteeshipTask.BidPrice == null || trusteeshipTask.BidPrice == 0)
+ {
+ logger.Error($"出价未获取,或者获取的出价为0,店铺id:{trusteeshipTask.ShopId},任务Id{trusteeshipTask.Id}");
+ continue;
+ }
+ if (trusteeshipTask.Budget == null || trusteeshipTask.Budget == 0)
+ {
+ logger.Error($"预算未获取,或者获取的预算为0,店铺id:{trusteeshipTask.ShopId},任务Id{trusteeshipTask.Id}");
+ continue;
+ }
+ decimal newBidPrice = 0m;
+ string adjustContent = string.Empty;
+ if (beforeThreeDayMaxCost < trusteeshipTask.Budget.Value * 0.3m)//前三天花费最高的一天低于预算的30% 出价调高50%
+ {
+ newBidPrice = Math.Round(trusteeshipTask.BidPrice.Value * (1 + 0.5m), 2);
+ adjustContent = "出价调高50%";
+ }
+ else if (beforeThreeDayMaxCost < trusteeshipTask.Budget.Value * 0.5m)//前三天花费最高的一天低于预算的50% 出价调高35%
+ {
+ newBidPrice = Math.Round(trusteeshipTask.BidPrice.Value * (1 + 0.35m), 2);
+ adjustContent = "出价调高35%";
+ }
+ else if (beforeThreeDayMaxCost < trusteeshipTask.Budget.Value * 0.7m)//前三天花费最高的一天低于预算的70% 出价调高20%
+ {
+ newBidPrice = Math.Round(trusteeshipTask.BidPrice.Value * (1 + 0.2m), 2);
+ adjustContent = "出价调高20%";
+ }
+ else
+ {
+ logger.Info($"任务Id:{trusteeshipTask.Id},三天最高花费:{beforeThreeDayMaxCost},预算:{trusteeshipTask.BidPrice}");
+ continue;
+ }
+ decimal oldBidPrice = trusteeshipTask.BidPrice.Value;
+
+ trusteeshipTask.BidPrice = newBidPrice;//表里更新 新的出价
+ update.Where(u => u.Id == trusteeshipTask.Id).Set(u => u.BidPrice, newBidPrice);
+ //更新快车的 出价
+ string url = "http://txapi.sbf.qiyue666.com/SanBanFu/Api/SendFeeUpdate";
+ HttpClient client = new HttpClient();
+ client.Timeout = TimeSpan.FromMinutes(1);
+
+ var postData = JsonConvert.SerializeObject(new
+ {
+ ShopId = trusteeshipTask.ShopId?.ToString(),
+ AdgroupId = trusteeshipTask.AdGroupId?.ToString(),
+ SearchFee = newBidPrice
+
+ });
+
+ HttpContent content = new StringContent(postData);
+
+ var res = await client.PostAsync("https://cactus.jd.com/request_algo?g_ty=ajax", content);
+ if (res.IsSuccessStatusCode)
+ {
+ //发送成功
+ logger.Info($"请求变更出价接口成功! 店铺id:{trusteeshipTask.ShopId},请求参数{postData}");
+
+ AdjustLogList.Add(new Sbf_AdjustLog
+ {
+ AdjustType = Model.Enums.AdjustType.出价,
+ AdjustWay = Model.Enums.AdjustWay.调高,
+ CreateTime = DateTime.Now,
+ PolicyType = Model.Enums.PolicyType.成长期策略包,
+ TrusteeshipTaskId = trusteeshipTask.Id,
+ OperateContent = $"{adjustContent},原出价:{oldBidPrice},调整后出价:{newBidPrice}"
+ });
+
+ }
+ else
+ {
+ logger.Error($"请求变更出价接口失败,返回消息:{res?.Content?.ReadAsStringAsync()?.Result}, 店铺id:{trusteeshipTask.ShopId},请求参数{postData}");
+ }
+ Thread.Sleep(500);
+
+ }
+ await update.ExecuteUpdatedAsync();
+
+ if (AdjustLogList.Any())
+ await fsql.Insert(AdjustLogList).ExecuteInsertedAsync();
+
+ }
+
+ ///
+ /// 降低出价策略
+ ///
+ ///
+ ///
+ public async Task RunGrowthPeriodLowerBidPriceTrusteeshipPolicy()
+ {
+ var searchTrusteeshipTaskList = OverFirstWeekUpdateTrusteeshipPolicyData();//获取两周的数据
+
+
+
+ List AdjustLogList = new List();
+ var hour = DateTime.Now.Hour;
+
+ List historyAdjustLogList = new List();
+ if (hour != 12)
+ {
+ //获取当天的降低出价日志记录
+
+ historyAdjustLogList = fsql.Select().Where(l => l.CreateTime.Value.Date == DateTime.Now.Date && l.PolicyType == Model.Enums.PolicyType.成长期策略包
+ && l.AdjustType == Model.Enums.AdjustType.出价 && l.AdjustWay == Model.Enums.AdjustWay.降低).ToList();
+ }
+
+ var update = fsql.Update();
+ foreach (var trusteeshipTask in searchTrusteeshipTaskList)
+ {
+ if (trusteeshipTask.BidPrice == null || trusteeshipTask.BidPrice == 0)
+ {
+ logger.Error($"出价未获取,或者获取的出价为0,店铺id:{trusteeshipTask.ShopId},任务Id{trusteeshipTask.Id}");
+ continue;
+ }
+ if (trusteeshipTask.Budget == null || trusteeshipTask.Budget == 0)
+ {
+ logger.Error($"预算未获取,或者获取的预算为0,店铺id:{trusteeshipTask.ShopId},任务Id{trusteeshipTask.Id}");
+ continue;
+ }
+ if (trusteeshipTask.Budget == trusteeshipTask.NowCost)//花费耗尽
+ {
+ decimal newBidPrice = 0m;
+ string adjustContent = string.Empty;
+ if (hour == 12)//预算早于12:00前花完 降低出价30%
+ {
+ newBidPrice = Math.Round(trusteeshipTask.BidPrice.Value * (1 - 0.3m), 2);
+ adjustContent = "降低出价30%";
+ }
+ else if (hour == 18)//预算早于12:00前花完 降低出价20%
+ {
+ if (historyAdjustLogList.Any(h => h.TrusteeshipTaskId == trusteeshipTask.Id))//当天已经降低出价过
+ continue;
+
+ adjustContent = "降低出价20%";
+ newBidPrice = Math.Round(trusteeshipTask.BidPrice.Value * (1 - 0.2m), 2);
+ }
+ else if (hour == 23)//预算早于12:00前花完 降低出价10%
+ {
+ if (historyAdjustLogList.Any(h => h.TrusteeshipTaskId == trusteeshipTask.Id))//当天已经降低出价过
+ continue;
+ adjustContent = "降低出价10%";
+ newBidPrice = Math.Round(trusteeshipTask.BidPrice.Value * (1 - 0.1m), 2);
+ }
+ else
+ {//出错
+ continue;
+ }
+ decimal oldBidPrice = trusteeshipTask.BidPrice.Value;
+
+ trusteeshipTask.BidPrice = newBidPrice;//表里更新 新的出价
+ update.Where(u => u.Id == trusteeshipTask.Id).Set(u => u.BidPrice, newBidPrice);
+ //更新快车的 出价
+ string url = "http://txapi.sbf.qiyue666.com/SanBanFu/Api/SendFeeUpdate";
+ HttpClient client = new HttpClient();
+ client.Timeout = TimeSpan.FromMinutes(1);
+
+ var postData = JsonConvert.SerializeObject(new
+ {
+ ShopId = trusteeshipTask.ShopId?.ToString(),
+ AdgroupId = trusteeshipTask.AdGroupId?.ToString(),
+ SearchFee = newBidPrice
+
+ });
+
+ HttpContent content = new StringContent(postData);
+
+ var res = await client.PostAsync("https://cactus.jd.com/request_algo?g_ty=ajax", content);
+ if (res.IsSuccessStatusCode)
+ {
+ //发送成功
+ logger.Info($"请求变更出价接口成功! 店铺id:{trusteeshipTask.ShopId},请求参数{postData}");
+
+ AdjustLogList.Add(new Sbf_AdjustLog
+ {
+ AdjustType = Model.Enums.AdjustType.出价,
+ AdjustWay = Model.Enums.AdjustWay.调高,
+ CreateTime = DateTime.Now,
+ PolicyType = Model.Enums.PolicyType.成长期策略包,
+ TrusteeshipTaskId = trusteeshipTask.Id,
+ OperateContent = $"{adjustContent},原出价:{oldBidPrice},调整后出价:{newBidPrice}"
+ });
+
+ }
+ else
+ {
+ logger.Error($"请求变更出价接口失败,返回消息:{res?.Content?.ReadAsStringAsync()?.Result}, 店铺id:{trusteeshipTask.ShopId},请求参数{postData}");
+ }
+ Thread.Sleep(500);
+
+ }
+ }
+ await update.ExecuteAffrowsAsync();
+ if (AdjustLogList.Any())
+ await fsql.Insert(AdjustLogList).ExecuteInsertedAsync();
+ }
+ }
+}
diff --git a/SBF.Business/SBF.Business.csproj b/SBF.Business/SBF.Business.csproj
index baf0b83..537ad9c 100644
--- a/SBF.Business/SBF.Business.csproj
+++ b/SBF.Business/SBF.Business.csproj
@@ -10,6 +10,7 @@
+
diff --git a/SBF.Common/Extensions/ConverterExtensions.cs b/SBF.Common/Extensions/ConverterExtensions.cs
index 31df3ef..1db29f2 100644
--- a/SBF.Common/Extensions/ConverterExtensions.cs
+++ b/SBF.Common/Extensions/ConverterExtensions.cs
@@ -26,4 +26,6 @@
}
}
}
+
+
}
diff --git a/SBF.Model/Db/Trusteeship/Sbf_AdjustLog.cs b/SBF.Model/Db/Trusteeship/Sbf_AdjustLog.cs
new file mode 100644
index 0000000..cb976ac
--- /dev/null
+++ b/SBF.Model/Db/Trusteeship/Sbf_AdjustLog.cs
@@ -0,0 +1,52 @@
+using FreeSql.DataAnnotations;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SBF.Model.Db.Trusteeship
+{
+ public class Sbf_AdjustLog
+ {
+ [Column(DbType = "bigint", IsPrimary = true)]
+ public long Id { get; set; }
+
+
+ ///
+ /// 托管任务Id
+ ///
+ [Column(DbType = "bigint")]
+ public long TrusteeshipTaskId { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ [Column(DbType = "datetime")]
+ public DateTime? CreateTime { get; set; }
+
+ ///
+ /// 策略类型 成长期策略包 = 0, 冲击主力策略包 = 1, 稳定期策略包 = 2, 主力期策略包 = 3
+ ///
+ [Column(MapType = typeof(int?))]
+ public Enums.PolicyType? PolicyType { get; set; } = Enums.PolicyType.成长期策略包;
+
+ ///
+ /// 调整类型(出价=0,预算=1)
+ ///
+ [Column(MapType = typeof(int?))]
+ public Enums.AdjustType AdjustType { get; set; }
+
+ ///
+ /// 调整方式(调高 = 0, 降低 = 1, 指定值 = 2)
+ ///
+ [Column(MapType = typeof(int?))]
+ public Enums.AdjustWay AdjustWay { get; set; }
+
+
+ ///
+ /// 操作内容
+ ///
+ public string OperateContent { get; set; }
+ }
+}
diff --git a/SBF.Model/Db/Trusteeship/Sbf_TrusteeshipTask.cs b/SBF.Model/Db/Trusteeship/Sbf_TrusteeshipTask.cs
index 85456fd..c412dd8 100644
--- a/SBF.Model/Db/Trusteeship/Sbf_TrusteeshipTask.cs
+++ b/SBF.Model/Db/Trusteeship/Sbf_TrusteeshipTask.cs
@@ -52,6 +52,12 @@ namespace SBF.Model.Db
[Column(DbType = "decimal(18,2)")]
public decimal? Budget { get; set; } = 0.00M;
+ ///
+ /// 当天花费
+ ///
+ [Column(DbType = "decimal(18,2)")]
+ public decimal? NowCost{ get; set; } = 0.00M;
+
///
/// 业务类型/渠道 快车=2,智能投放=134217728
///
@@ -111,6 +117,18 @@ namespace SBF.Model.Db
[Column(MapType = typeof(int?))]
public Enums.PolicyType? PolicyType { get; set; } = Enums.PolicyType.成长期策略包;
+ ///
+ /// 主SkuId
+ ///
+ [Column(StringLength = 50)]
+ public string PrimarySkuId { get; set; }
+
+ ///
+ /// 锚定预算
+ ///
+ [Column(DbType = "decimal(18,2)")]
+ public decimal? AnchorBudget { get; set; }
+
#region Product
[Column(IsIgnore = true)]
public DateTime? ProductCreateTime { get; set; }
diff --git a/SBF.Model/Dto/Request/ExecuteTrusteeshipPolicy/BatchUpdateBidPriceRequest.cs b/SBF.Model/Dto/Request/ExecuteTrusteeshipPolicy/BatchUpdateBidPriceRequest.cs
new file mode 100644
index 0000000..df87faa
--- /dev/null
+++ b/SBF.Model/Dto/Request/ExecuteTrusteeshipPolicy/BatchUpdateBidPriceRequest.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SBF.Model.Dto
+{
+ public class BatchUpdateBidPriceRequest
+ {
+ /* [{AdgroupId:'',SearchFee:0,End:2022-01-01,Start:2022-01-01,ShopId:123,TotalCost:1,RenQunCost:1,KeyWordCost:1,ShopCost:1}] */
+
+ ///
+ /// 单元Id
+ ///
+ public string AdgroupId { get; set; }
+
+ ///
+ /// 出价
+ ///
+ public decimal SearchFee { get; set; }
+
+ ///
+ /// 开始时间
+ ///
+ public DateTime? Start { get; set; }
+ ///
+ /// 结束时间
+ ///
+ public DateTime? End { get; set; }
+
+ ///
+ /// 店铺id
+ ///
+ public long ShopId { get; set; }
+
+ ///
+ /// 单元总花费
+ ///
+ public decimal TotalCost { get; set; }
+
+
+ ///
+ /// 人群花费
+ ///
+ public decimal? RenQunCost { get; set; }
+
+
+ ///
+ /// 关键词花费
+ ///
+ public decimal? KeyWordCost { get; set; }
+
+
+ ///
+ /// 店铺商品花费
+ ///
+ public decimal? ShopCost { get; set; }
+ }
+}
diff --git a/SBF.Model/Dto/Request/ExecuteTrusteeshipPolicy/BatchUpdateBudgetRequest.cs b/SBF.Model/Dto/Request/ExecuteTrusteeshipPolicy/BatchUpdateBudgetRequest.cs
new file mode 100644
index 0000000..9638809
--- /dev/null
+++ b/SBF.Model/Dto/Request/ExecuteTrusteeshipPolicy/BatchUpdateBudgetRequest.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SBF.Model.Dto
+{
+ public class BatchUpdateBudgetRequest
+ {
+
+ /* {CampaignId:'',Budget:0,End:2022-01-01,Start:2022-01-01,ShopId:123,TotalCost:1} */
+
+ ///
+ /// 计划Id
+ ///
+ public string CampaignId { get; set; }
+
+ ///
+ /// 预算
+ ///
+ public decimal? Budget { get; set; }
+
+ ///
+ /// 开始时间
+ ///
+ public DateTime? Start { get; set; }
+ ///
+ /// 结束时间
+ ///
+ public DateTime? End { get; set; }
+
+ ///
+ /// 店铺id
+ ///
+ public long? ShopId { get; set; }
+
+ ///
+ /// 计划总花费
+ ///
+ public decimal? TotalCost { get; set; }
+ }
+}
diff --git a/SBF.Model/Enums.cs b/SBF.Model/Enums.cs
index 5c23f3a..8fe6def 100644
--- a/SBF.Model/Enums.cs
+++ b/SBF.Model/Enums.cs
@@ -404,5 +404,21 @@
{
成长期策略包 = 0, 冲击主力策略包 = 1, 稳定期策略包 = 2, 主力期策略包 = 3
}
+
+ ///
+ /// 调整类型(出价=0,预算=1)
+ ///
+ public enum AdjustType
+ {
+ 出价 = 0, 预算 = 1
+ }
+
+ ///
+ /// 调整方式(调高 = 0, 降低 = 1, 指定值 = 2)
+ ///
+ public enum AdjustWay
+ {
+ 调高 = 0, 降低 = 1, 指定值 = 2
+ }
}
}
diff --git a/SBF.Model/SBF.Model.csproj b/SBF.Model/SBF.Model.csproj
index 5d8b3da..926bb4a 100644
--- a/SBF.Model/SBF.Model.csproj
+++ b/SBF.Model/SBF.Model.csproj
@@ -14,6 +14,7 @@
+