Compare commits

...

2 Commits

Author SHA1 Message Date
506583276@qq.com 94a2cb092b 1 2 years ago
506583276@qq.com 5047f1d47b 添加托管执行策略 2 years ago
  1. 87
      SBF.API/Controllers/ExecuteTrusteeshipPolicyController.cs
  2. 60
      SBF.API/Extentions/HostExtentions.cs
  3. 6
      SBF.API/Program.cs
  4. 1
      SBF.API/SBF.API.csproj
  5. 4
      SBF.API/appsettings.json
  6. 586
      SBF.Business/ExecuteTrusteeshipPolicyBusiness.cs
  7. 1
      SBF.Business/SBF.Business.csproj
  8. 2
      SBF.Common/Extensions/ConverterExtensions.cs
  9. 52
      SBF.Model/Db/Trusteeship/Sbf_AdjustLog.cs
  10. 18
      SBF.Model/Db/Trusteeship/Sbf_TrusteeshipTask.cs
  11. 60
      SBF.Model/Dto/Request/ExecuteTrusteeshipPolicy/BatchUpdateBidPriceRequest.cs
  12. 43
      SBF.Model/Dto/Request/ExecuteTrusteeshipPolicy/BatchUpdateBudgetRequest.cs
  13. 16
      SBF.Model/Enums.cs
  14. 1
      SBF.Model/SBF.Model.csproj

87
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
{
/// <summary>
/// 执行托管策略
/// </summary>
public class ExecuteTrusteeshipPolicyController : BaseApiController
{
private ExecuteTrusteeshipPolicyBusiness executeTrusteeshipPolicyBusiness;
public ExecuteTrusteeshipPolicyController(IHttpContextAccessor httpContextAccessor, ExecuteTrusteeshipPolicyBusiness executeTrusteeshipPolicyBusiness) : base(httpContextAccessor)
{
this.executeTrusteeshipPolicyBusiness = executeTrusteeshipPolicyBusiness;
}
/// <summary>
/// 批量上传店铺预算数据(回调地址)
/// </summary>
/// <param name="requestList"></param>
[HttpPost]
[AllowAnonymous]
public async Task BatchUpdateBudget(BatchUpdateBudgetRequest[] requestList)
{
await executeTrusteeshipPolicyBusiness.BatchUpdateBudget(requestList);
}
/// <summary>
/// 批量上传店铺单元出价数据(回调地址)
/// </summary>
/// <param name="requestList"></param>
[HttpPost]
[AllowAnonymous]
public async Task BatchUpdateBidPrice(BatchUpdateBidPriceRequest[] requestList)
{
await executeTrusteeshipPolicyBusiness.BatchUpdateBidPrice(requestList);
}
/// <summary>
/// 更新策略数据(当日预算. 出价 ,当前时间花费情况) 9:00
/// </summary>
[HttpGet]
[AllowAnonymous]
public async Task UpdateTrusteeshipPolicyData()
{
await executeTrusteeshipPolicyBusiness.UpdateTrusteeshipPolicyData();
}
/// <summary>
/// 判断 预算耗尽 更新出价 花费 预算
/// </summary>
/// <returns></returns>
[HttpGet]
[AllowAnonymous]
public async Task JudgeBudgetCostOutUpdateTrusteeshipPolicyData()
{
await executeTrusteeshipPolicyBusiness.JudgeBudgetCostOutUpdateTrusteeshipPolicyData();
}
/// <summary>
/// 运行成长期调高出价策略
/// </summary>
/// <returns></returns>
[HttpGet]
[AllowAnonymous]
public async Task RunGrowthPeriodIncreaseBidPriceTrusteeshipPolicy()
{
await executeTrusteeshipPolicyBusiness.RunGrowthPeriodIncreaseBidPriceTrusteeshipPolicy();
}
/// <summary>
/// 运行成长期降低出价策略
/// </summary>
/// <returns></returns>
[HttpGet]
[AllowAnonymous]
public async Task RunGrowthPeriodLowerBidPriceTrusteeshipPolicy()
{
await executeTrusteeshipPolicyBusiness.RunGrowthPeriodLowerBidPriceTrusteeshipPolicy();
}
}
}

60
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
{
/// <summary>
/// 使用缓存
/// </summary>
/// <param name="hostBuilder">建造者</param>
/// <returns></returns>
public static IHostBuilder UseCache(this IHostBuilder hostBuilder)
{
hostBuilder.ConfigureServices((buidlerContext, services) =>
{
var cacheOption = buidlerContext.Configuration.GetSection("Cache").Get<CacheOptions>();
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<IDistributedCache>(new CSRedisCache(RedisHelper.Instance));
}; break;
default: throw new Exception("缓存类型无效");
}
});
return hostBuilder;
}
}
internal class CacheOptions
{
public CacheType CacheType { get; set; }
public string RedisEndpoint { get; set; }
} /// <summary>
/// 缓存类型
/// </summary>
public enum CacheType
{
/// <summary>
/// 使用内存缓存(不支持分布式)
/// </summary>
Memory,
/// <summary>
/// 使用Redis缓存(支持分布式)
/// </summary>
Redis
}
}

6
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);

1
SBF.API/SBF.API.csproj

@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Caching.CSRedis" Version="3.8.800" />
<PackageReference Include="FreeSql" Version="3.2.805" />
<PackageReference Include="FreeSql.Provider.MySql" Version="3.2.805" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.25" />

4
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": {

586
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
{
/// <summary>
/// 执行托管策略
/// </summary>
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/";
/// <summary>
/// 回调出价和花费
/// </summary>
/// <param name="requestList"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task BatchUpdateBidPrice(BatchUpdateBidPriceRequest[] requestList)
{
var AdgroupIdList = requestList.Select(r => long.Parse(r.AdgroupId)).ToList();
var trusteeshipTaskList = fsql.Select<Sbf_TrusteeshipTask>().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<Sbf_TrusteeshipTask>(trusteeshipTaskList).ExecuteUpdatedAsync();
logger.Info($"回调出价和花费成功!回调消息:{JsonConvert.SerializeObject(requestList)}");
}
/// <summary>
/// 回调预算
/// </summary>
/// <param name="requestList"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task BatchUpdateBudget(BatchUpdateBudgetRequest[] requestList)
{
var CampaignIdList = requestList.Select(r => long.Parse(r.CampaignId)).ToList();
var trusteeshipTaskList = fsql.Select<Sbf_TrusteeshipTask>().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<Sbf_TrusteeshipTask>(trusteeshipTaskList).ExecuteUpdatedAsync();
logger.Info($"回调预算成功!回调消息:{JsonConvert.SerializeObject(requestList)}");
}
/// <summary>
/// 提交
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task UpdateTrusteeshipPolicyData()
{
//获取当前待执行列表的数据
var searchTrusteeshipTaskList = FirstWeekUpdateTrusteeshipPolicyData();
searchTrusteeshipTaskList.AddRange(OverFirstWeekUpdateTrusteeshipPolicyData());
await UpdateTrusteeshipPolicyData(searchTrusteeshipTaskList);
await ThreeWeekUpdateBudget();//第三周或三周以上 每天初始化预算
}
private async Task UpdateTrusteeshipPolicyData(List<Sbf_TrusteeshipTask> 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(url, content);
if (res.IsSuccessStatusCode)
{
//发送成功
logger.Info($"请求出价接口成功! 店铺id:{shopId},请求参数{postData}");
}
else
{
logger.Error($"请求出价接口失败,返回消息:{res?.Content?.ReadAsStringAsync()?.Result}, 店铺id:{shopId},请求参数{postData}");
}
Thread.Sleep(500);
}
}
/// <summary>
/// 第一周 只需更新一次
/// </summary>
/// <returns></returns>
private List<Sbf_TrusteeshipTask> FirstWeekUpdateTrusteeshipPolicyData()
{
List<DateTime> excuteDate = new List<DateTime>();
DateTime nowDate = DateTime.Now.Date;
excuteDate.Add(nowDate.AddDays(4));
excuteDate.Add(nowDate.AddDays(7));
return fsql.Select<Sbf_TrusteeshipTask>().Where(s => s.IsEnd == false && s.PolicyType == Model.Enums.PolicyType. && s.StartTrusteeshipDate != null && excuteDate.Contains(s.StartTrusteeshipDate.Value)).ToList();//
}
/// <summary>
/// 两周以上的(12:00 18:00 23:00要更新)
/// </summary>
/// <returns></returns>
private List<Sbf_TrusteeshipTask> OverFirstWeekUpdateTrusteeshipPolicyData()
{
List<DateTime> excuteDate = new List<DateTime>();
DateTime nowDate = DateTime.Now.Date;
excuteDate.Add(nowDate.AddDays(11));
excuteDate.Add(nowDate.AddDays(14));
return fsql.Select<Sbf_TrusteeshipTask>().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();
}
/// <summary>
/// 更新
/// </summary>
private async Task ThreeWeekUpdateBudget()
{
DateTime nowDate = DateTime.Now.Date;
//第三周 或者三周以上的数据
var trusteeshipTaskList = fsql.Select<Sbf_TrusteeshipTask>().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<DateTime> excuteDate = new List<DateTime>
{
nowDate.AddDays(-1),
nowDate.AddDays(-2),
nowDate.AddDays(-3)
};
var primarySkuDailyList = fsql.Select<AggregationJDPopularizeSkuDaily>().Where(a => primarySkuIdList.Contains(a.SkuId) && a.Date != null && excuteDate.Contains(a.Date.Value)).ToList();
List<Sbf_AdjustLog> AdjustLogList = new List<Sbf_AdjustLog>();
var update = fsql.Update<Sbf_TrusteeshipTask>();
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(url, 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<Sbf_AdjustLog>(AdjustLogList).ExecuteInsertedAsync();
}
/// <summary>
/// 更新第二周 4 7天 和三周以上的数据
/// </summary>
/// <returns></returns>
public async Task JudgeBudgetCostOutUpdateTrusteeshipPolicyData()
{
var searchTrusteeshipTaskList = OverFirstWeekUpdateTrusteeshipPolicyData();
await UpdateTrusteeshipPolicyData(searchTrusteeshipTaskList);
}
/// <summary>
/// 调高出价策略
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
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<DateTime> excuteDate = new List<DateTime>();
DateTime nowDate = DateTime.Now.Date;
excuteDate.Add(nowDate.AddDays(-1));
excuteDate.Add(nowDate.AddDays(-2));
excuteDate.Add(nowDate.AddDays(-3));
//获取前三天花费
var adgroupCostList = fsql.Select<AggregationJDPopularizeAdGroupDaily>().Where(s => adgroupIds.Contains(s.AdGroupId) && s.Date != null && excuteDate.Contains(s.Date.Value)).ToList();
List<Sbf_AdjustLog> AdjustLogList = new List<Sbf_AdjustLog>();
var update = fsql.Update<Sbf_TrusteeshipTask>();
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(url, 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<Sbf_AdjustLog>(AdjustLogList).ExecuteInsertedAsync();
}
/// <summary>
/// 降低出价策略
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task RunGrowthPeriodLowerBidPriceTrusteeshipPolicy()
{
var searchTrusteeshipTaskList = OverFirstWeekUpdateTrusteeshipPolicyData();//获取两周的数据
List<Sbf_AdjustLog> AdjustLogList = new List<Sbf_AdjustLog>();
var hour = DateTime.Now.Hour;
List<Sbf_AdjustLog> historyAdjustLogList = new List<Sbf_AdjustLog>();
if (hour != 12)
{
//获取当天的降低出价日志记录
historyAdjustLogList = fsql.Select<Sbf_AdjustLog>().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<Sbf_TrusteeshipTask>();
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(url, 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<Sbf_AdjustLog>(AdjustLogList).ExecuteInsertedAsync();
}
}
}

1
SBF.Business/SBF.Business.csproj

@ -10,6 +10,7 @@
<ItemGroup>
<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.Http" Version="8.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.2.6" />

2
SBF.Common/Extensions/ConverterExtensions.cs

@ -26,4 +26,6 @@
}
}
}
}

52
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; }
/// <summary>
/// 托管任务Id
/// </summary>
[Column(DbType = "bigint")]
public long TrusteeshipTaskId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[Column(DbType = "datetime")]
public DateTime? CreateTime { get; set; }
/// <summary>
/// 策略类型 成长期策略包 = 0, 冲击主力策略包 = 1, 稳定期策略包 = 2, 主力期策略包 = 3
/// </summary>
[Column(MapType = typeof(int?))]
public Enums.PolicyType? PolicyType { get; set; } = Enums.PolicyType.;
/// <summary>
/// 调整类型(出价=0,预算=1)
/// </summary>
[Column(MapType = typeof(int?))]
public Enums.AdjustType AdjustType { get; set; }
/// <summary>
/// 调整方式(调高 = 0, 降低 = 1, 指定值 = 2)
/// </summary>
[Column(MapType = typeof(int?))]
public Enums.AdjustWay AdjustWay { get; set; }
/// <summary>
/// 操作内容
/// </summary>
public string OperateContent { get; set; }
}
}

18
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;
/// <summary>
/// 当天花费
/// </summary>
[Column(DbType = "decimal(18,2)")]
public decimal? NowCost{ get; set; } = 0.00M;
/// <summary>
/// 业务类型/渠道 快车=2,智能投放=134217728
/// </summary>
@ -111,6 +117,18 @@ namespace SBF.Model.Db
[Column(MapType = typeof(int?))]
public Enums.PolicyType? PolicyType { get; set; } = Enums.PolicyType.;
/// <summary>
/// 主SkuId
/// </summary>
[Column(StringLength = 50)]
public string PrimarySkuId { get; set; }
/// <summary>
/// 锚定预算
/// </summary>
[Column(DbType = "decimal(18,2)")]
public decimal? AnchorBudget { get; set; }
#region Product
[Column(IsIgnore = true)]
public DateTime? ProductCreateTime { get; set; }

60
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}] */
/// <summary>
/// 单元Id
/// </summary>
public string AdgroupId { get; set; }
/// <summary>
/// 出价
/// </summary>
public decimal SearchFee { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime? Start { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime? End { get; set; }
/// <summary>
/// 店铺id
/// </summary>
public long ShopId { get; set; }
/// <summary>
/// 单元总花费
/// </summary>
public decimal TotalCost { get; set; }
/// <summary>
/// 人群花费
/// </summary>
public decimal? RenQunCost { get; set; }
/// <summary>
/// 关键词花费
/// </summary>
public decimal? KeyWordCost { get; set; }
/// <summary>
/// 店铺商品花费
/// </summary>
public decimal? ShopCost { get; set; }
}
}

43
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} */
/// <summary>
/// 计划Id
/// </summary>
public string CampaignId { get; set; }
/// <summary>
/// 预算
/// </summary>
public decimal? Budget { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime? Start { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime? End { get; set; }
/// <summary>
/// 店铺id
/// </summary>
public long? ShopId { get; set; }
/// <summary>
/// 计划总花费
/// </summary>
public decimal? TotalCost { get; set; }
}
}

16
SBF.Model/Enums.cs

@ -404,5 +404,21 @@
{
= 0, = 1, = 2, = 3
}
/// <summary>
/// 调整类型(出价=0,预算=1)
/// </summary>
public enum AdjustType
{
= 0, = 1
}
/// <summary>
/// 调整方式(调高 = 0, 降低 = 1, 指定值 = 2)
/// </summary>
public enum AdjustWay
{
= 0, = 1, = 2
}
}
}

1
SBF.Model/SBF.Model.csproj

@ -14,6 +14,7 @@
<ItemGroup>
<Folder Include="Db\XingXiang\" />
<Folder Include="Dto\Response\ExecuteTrusteeshipPolicy\" />
</ItemGroup>
</Project>

Loading…
Cancel
Save