|
|
@@ -0,0 +1,644 @@
|
|
|
+package cn.com.ctop.job.bytedance.data.service.impl;
|
|
|
+
|
|
|
+import cn.com.ctop.job.bytedance.data.constants.ReportsConstants;
|
|
|
+import cn.com.ctop.job.bytedance.data.entity.*;
|
|
|
+import cn.com.ctop.job.bytedance.data.mapper.ReportsAdPushMapper;
|
|
|
+import cn.com.ctop.job.bytedance.data.mapper.ZtPolicyMapper;
|
|
|
+import cn.com.ctop.job.bytedance.data.service.IBytedanceBudgetStatusService;
|
|
|
+import cn.com.ctop.job.bytedance.data.service.IZtPolicyRunService;
|
|
|
+import cn.com.ctop.job.bytedance.data.utils.DateUtils;
|
|
|
+import cn.com.ctop.job.bytedance.utils.FeishuRobotUtil;
|
|
|
+import cn.com.ctop.job.bytedance.utils.FsTimeBitmapChecker;
|
|
|
+import cn.com.ctop.job.bytedance.utils.RedisUtil;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import org.redisson.Redisson;
|
|
|
+import org.redisson.api.RAtomicLong;
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.io.IOException;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.time.*;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class ZtPolicyRunServiceImpl implements IZtPolicyRunService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ ZtPolicyMapper ztPolicyConfigMapper;
|
|
|
+ @Autowired
|
|
|
+ RedissonClient redissonClient;
|
|
|
+ @Autowired
|
|
|
+ IBytedanceBudgetStatusService bytedanceBudgetStatusService;
|
|
|
+ @Resource
|
|
|
+ ReportsAdPushMapper reportsAdPushMapper;
|
|
|
+ public static final String ERROR_HOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/a0fcfb57-c053-47bd-b1e7-b826f44841e4";
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void test() {
|
|
|
+ run(15L);
|
|
|
+ };
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void run(Long policyId) {
|
|
|
+ final String runId = UUID.randomUUID().toString().replace("-", "").substring(0,16);
|
|
|
+ ZtPolicy policy = getConfig(policyId);
|
|
|
+ /**已完成扫描
|
|
|
+ //指标选择- 获取indicator信息
|
|
|
+ //指标分类
|
|
|
+ //ID按500个一组,分别获取普通指标/项目信息/余额的数据
|
|
|
+ //在程序中处理判断
|
|
|
+ */
|
|
|
+ if (policy == null){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (policy.getTargetResIds() == null || policy.getTargetResIds().isEmpty()){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ZtPolicyRunInfo ztPolicyRunInfo = new ZtPolicyRunInfo();
|
|
|
+ ztPolicyRunInfo.setRunId(runId);
|
|
|
+ ztPolicyRunInfo.setPolicyConfigId(policyId);
|
|
|
+ ztPolicyRunInfo.setScheduledTime(new Date());
|
|
|
+ ztPolicyRunInfo.setStartTime(new Date());
|
|
|
+ ztPolicyRunInfo.setConfigSnapshotJson(JSONObject.toJSONString(policy));
|
|
|
+ ztPolicyConfigMapper.insertPolicyRunRecord(ztPolicyRunInfo);
|
|
|
+
|
|
|
+ List<ZtPolicyCondition> conditions = policy.getConditions();
|
|
|
+ List<Long> indicatorIds = conditions.stream().map(ZtPolicyCondition::getIndicatorId).collect(Collectors.toList());
|
|
|
+
|
|
|
+
|
|
|
+ List<JSONObject> indicatorList = ztPolicyConfigMapper.indicatorList(indicatorIds);
|
|
|
+ Map<Long, JSONObject> indicatorMap = indicatorList.stream().collect(Collectors.toMap(o -> o.getLong("indicator_id"), o -> o));
|
|
|
+
|
|
|
+
|
|
|
+ /**---------------------------------------获取指标数据----------------------------------------------------*/
|
|
|
+
|
|
|
+ Map<String, ZtTargetRunInfo> runRecordMap = new HashMap<>();
|
|
|
+ for (ZtPolicyCondition condition : conditions) {
|
|
|
+ Long indicatorId = condition.getIndicatorId();
|
|
|
+ JSONObject indicator = indicatorMap.get(indicatorId);
|
|
|
+ String indicatorName = indicator.getString("indicator_name");
|
|
|
+ String indicatorCode = indicator.getString("indicator_code");
|
|
|
+ String dataSource = indicator.getString("data_source");
|
|
|
+ String formula = indicator.getString("formula");
|
|
|
+
|
|
|
+ //批量查询过程
|
|
|
+ Map<String, JSONObject> matchConditionExtraRecordInfo = new HashMap<>();//记录的额外信息
|
|
|
+ Map<String, Object> dataResMap = new HashMap<>();//id -> 查询结果
|
|
|
+ if ("bytedance".equals(dataSource)){//几个特殊字段获取
|
|
|
+ for (int index = 0; index < policy.getTargetResIds().size(); ) {
|
|
|
+ List<String> subResIds = policy.getTargetResIds().subList(index, Math.min(index+500, policy.getTargetResIds().size()));
|
|
|
+ List<JSONObject> data = null;
|
|
|
+ if ("bytedance_project_status".equals(indicatorCode)){
|
|
|
+ data = ztPolicyConfigMapper.promotionGroupToProjectData(subResIds);
|
|
|
+ }else if ("bytedance_promote_status".equals(indicatorCode)){
|
|
|
+ data = ztPolicyConfigMapper.promotionData(subResIds);
|
|
|
+ data.forEach(o -> dataResMap.put(o.getString("project_id"), o.get(indicatorCode)));
|
|
|
+ }else if ("bytedance_advertiser_balance".equals(indicatorCode)){
|
|
|
+ data = ztPolicyConfigMapper.balanceData(subResIds);
|
|
|
+ }else {
|
|
|
+ data = ztPolicyConfigMapper.projectData(subResIds);
|
|
|
+ }
|
|
|
+ data.forEach(o -> dataResMap.put(o.getString("project_id"), o.get(indicatorCode)));
|
|
|
+ index += 500;
|
|
|
+ }
|
|
|
+ }else {//自定义指标通用字段
|
|
|
+ JSONObject requestParams = new JSONObject();
|
|
|
+ Integer timeType = policy.getScheduleType() == 3 ? 1: 2;
|
|
|
+ requestParams.put("timeType", timeType);
|
|
|
+ requestParams.put("mediaAdColumns", ReportsConstants.mediaSelectStr);
|
|
|
+ requestParams.put("userDataColumns", ReportsConstants.userSelectStr);
|
|
|
+ requestParams.put("selectIndicator", formula);
|
|
|
+ requestParams.put("managedDimension", policy.getManagedDimension());
|
|
|
+ Integer taskTimeType = condition.getTimeType();
|
|
|
+ String today = DateUtils.getNowDate("yyyy-MM-dd");
|
|
|
+ Long todayLong = Long.parseLong(today.replaceAll("-", ""));
|
|
|
+ if (timeType == 1){
|
|
|
+ if (taskTimeType == 1){
|
|
|
+ requestParams.put("startDate", todayLong);
|
|
|
+ requestParams.put("endDate", todayLong);
|
|
|
+ }else if (taskTimeType == 2){
|
|
|
+ String startDate = DateUtils.getNowAddDate("yyyy-MM-dd", -1);
|
|
|
+ Long startDateLong = Long.parseLong(startDate.replaceAll("-", ""));
|
|
|
+ requestParams.put("startDate", startDateLong);
|
|
|
+ requestParams.put("endDate", startDateLong);
|
|
|
+ }else if (taskTimeType == 3){
|
|
|
+ String startDate = DateUtils.getNowAddDate("yyyy-MM-dd", -2);
|
|
|
+ Long startDateLong = Long.parseLong(startDate.replaceAll("-", ""));
|
|
|
+ requestParams.put("startDate", startDateLong);
|
|
|
+ requestParams.put("endDate", todayLong);
|
|
|
+ }else if (taskTimeType == 4){
|
|
|
+ String startDate = DateUtils.getNowAddDate("yyyy-MM-dd", -6);
|
|
|
+ Long startDateLong = Long.parseLong(startDate.replaceAll("-", ""));
|
|
|
+ requestParams.put("startDate", startDateLong);
|
|
|
+ requestParams.put("endDate", startDateLong);
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ if (taskTimeType == 11){
|
|
|
+ requestParams.put("date", todayLong);
|
|
|
+ }else if (taskTimeType == 12){
|
|
|
+ ZoneId zone = ZoneId.systemDefault();
|
|
|
+ LocalDateTime lastHour = LocalDateTime.now(zone).minusHours(1);
|
|
|
+ String yyyyMMdd = lastHour.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
|
|
+ Long date = Long.parseLong(yyyyMMdd);
|
|
|
+ int H = lastHour.getHour(); // 0-23,不补零
|
|
|
+ requestParams.put("date", date);
|
|
|
+ requestParams.put("hour", H);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (int index = 0; index < policy.getTargetResIds().size(); ) {
|
|
|
+ List<String> subResIds = policy.getTargetResIds().subList(index, Math.min(index+500, policy.getTargetResIds().size()));
|
|
|
+ requestParams.put("idList", subResIds);
|
|
|
+ List<JSONObject> data = ztPolicyConfigMapper.adData(requestParams);
|
|
|
+ data.forEach(o -> dataResMap.put(o.getString("target_id"), o.get(indicatorCode)));
|
|
|
+ index += 500;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**--------------------------------------指标数据判断阈值-----------------------------------------------------*/
|
|
|
+ //处理dataResMap,和condition条件做 比较,顺便做记录
|
|
|
+ for (String targetId : policy.getTargetResIds()){
|
|
|
+ ZtTargetRunInfo runInfo = new ZtTargetRunInfo();
|
|
|
+ final String recordId = UUID.randomUUID().toString().replace("-", "").substring(0,16); //记录,runId
|
|
|
+ runInfo.setPolicyId(policyId);
|
|
|
+ runInfo.setRunId(runId);
|
|
|
+ runInfo.setUuid(recordId);
|
|
|
+ runInfo.setManagedDimension(policy.getManagedDimension());
|
|
|
+ runInfo.setTargetId(targetId);
|
|
|
+ runInfo.setIndicatorInfo(indicator);
|
|
|
+ runInfo.setCondition(condition);
|
|
|
+ Object indValueObj = dataResMap.get(targetId);
|
|
|
+ String indValue = indValueObj == null ? "0" : String.valueOf(indValueObj);
|
|
|
+ runInfo.setCurrentValue(indValue);
|
|
|
+ //判断是否触发操作
|
|
|
+ boolean isExecute = false;
|
|
|
+ String operator = condition.getOperator();
|
|
|
+ if (operator.equals("BETWEEN")){
|
|
|
+ Double value = Double.parseDouble(indValue);
|
|
|
+ Double compareValueMin = condition.getCompareValueJsonObject().getDoubleValue("min");
|
|
|
+ Double compareValueMax = condition.getCompareValueJsonObject().getDoubleValue("max");
|
|
|
+ if (value >= compareValueMin && value <= compareValueMax){
|
|
|
+ isExecute = true;
|
|
|
+ }
|
|
|
+ String matchedConditionDesc = indicatorName + ": "+value + "介于"+compareValueMin+", "+compareValueMax;
|
|
|
+ runInfo.setMatchedConditionDesc(matchedConditionDesc);
|
|
|
+ }else if (operator.equals("EQ")){
|
|
|
+ String value = indValue;
|
|
|
+ String compareValue = condition.getCompareValueJsonObject().getString("value");
|
|
|
+ if (Objects.equals(value, compareValue)){
|
|
|
+ isExecute = true;
|
|
|
+ }
|
|
|
+ String matchedConditionDesc = indicatorName + ": "+ value+" 等于 "+value;
|
|
|
+ runInfo.setMatchedConditionDesc(matchedConditionDesc);
|
|
|
+ }else if (operator.equals("NEQ")){
|
|
|
+ String value = indValue;
|
|
|
+ String compareValue = condition.getCompareValueJsonObject().getString("value");
|
|
|
+ if (!Objects.equals(value, compareValue)){
|
|
|
+ isExecute = true;
|
|
|
+ }
|
|
|
+ String matchedConditionDesc = indicatorName + ": "+ value+" 不等于 "+value;
|
|
|
+ runInfo.setMatchedConditionDesc(matchedConditionDesc);
|
|
|
+ }else {
|
|
|
+ Double value = Double.parseDouble(indValue);
|
|
|
+ Double compareValue = condition.getCompareValueJsonObject().getDoubleValue("value");
|
|
|
+ if (operator.equals("GT")){
|
|
|
+ isExecute = value > compareValue;
|
|
|
+ String matchedConditionDesc = indicatorName + ": "+ value + " > "+compareValue;
|
|
|
+ runInfo.setMatchedConditionDesc(matchedConditionDesc);
|
|
|
+ }else if (operator.equals("LT")){
|
|
|
+ isExecute = value < compareValue;
|
|
|
+ String matchedConditionDesc = indicatorName + ": "+ value + " < "+compareValue;
|
|
|
+ runInfo.setMatchedConditionDesc(matchedConditionDesc);
|
|
|
+ }else if (operator.equals("GE")){
|
|
|
+ isExecute = value >= compareValue;
|
|
|
+ String matchedConditionDesc = indicatorName + ": "+ value + " >= "+compareValue;
|
|
|
+ runInfo.setMatchedConditionDesc(matchedConditionDesc);
|
|
|
+ }else {
|
|
|
+ FeishuRobotUtil.sendTextToWebhook("智投助手任务报错-判断符号无效,任务中止。任务ID:"+policyId+"条件ID:"+condition.getId(), ERROR_HOOK_URL);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ runInfo.setIsExecute(isExecute);
|
|
|
+ runInfo.setTriggerTime(new Date());
|
|
|
+
|
|
|
+ JSONObject matchedConditionJson = new JSONObject();
|
|
|
+ matchedConditionJson.put("indicatorCode", indicatorCode);
|
|
|
+ matchedConditionJson.put("operator", operator);
|
|
|
+ matchedConditionJson.put("compareValue", condition.getCompareValueJson());
|
|
|
+ matchedConditionJson.put("currentValue", indValue);
|
|
|
+ runInfo.setMatchedConditionJson(matchedConditionJson);
|
|
|
+ runInfo.setMatchedConditionJsonStr(matchedConditionJson.toJSONString());
|
|
|
+ runInfo.setConditionId(runInfo.getCondition().getId());
|
|
|
+ if (policy.getManagedDimension() == 1){
|
|
|
+ runInfo.setAdvertiserId(Long.valueOf(targetId));
|
|
|
+ }else {
|
|
|
+ String advId = policy.getTargetFromAdvertiserId().get(targetId);
|
|
|
+ runInfo.setAdvertiserId(Long.valueOf(advId));
|
|
|
+ }
|
|
|
+
|
|
|
+ runRecordMap.put(targetId+"_"+condition.getId(), runInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //condition结束
|
|
|
+ // 存储condition的记录
|
|
|
+ List<ZtTargetRunInfo> runInfoList = new ArrayList<>(runRecordMap.values());
|
|
|
+ ztPolicyConfigMapper.insertRunRecords(runInfoList);
|
|
|
+
|
|
|
+
|
|
|
+ /**---------------------------------------所有指标做且/或判断----------------------------------------------------*/
|
|
|
+ //挑拣出达到阈值的,走执行
|
|
|
+ Integer conditionLogic = policy.getConditionLogic();//1且2或
|
|
|
+ List<String> executeTargetList = new ArrayList<>();//执行列表
|
|
|
+ for (String targetId : policy.getTargetResIds()){
|
|
|
+ if (conditionLogic == 1){//且
|
|
|
+ boolean notMatched = false;
|
|
|
+ for (ZtPolicyCondition c : policy.getConditions()){
|
|
|
+ ZtTargetRunInfo runInfo = runRecordMap.get(targetId+"_"+c.getId());
|
|
|
+ if (!runInfo.getIsExecute()) {
|
|
|
+ notMatched = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!notMatched){
|
|
|
+ executeTargetList.add(targetId);
|
|
|
+ }
|
|
|
+ }else {//或
|
|
|
+ boolean isExecute = false;
|
|
|
+ for (ZtPolicyCondition c : policy.getConditions()){
|
|
|
+ ZtTargetRunInfo runInfo = runRecordMap.get(targetId+"_"+c.getId());
|
|
|
+ if (runInfo.getIsExecute()){
|
|
|
+ isExecute = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (isExecute){
|
|
|
+ executeTargetList.add(targetId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ System.out.println(">>>>>执行列表");
|
|
|
+ System.out.println(JSON.toJSONString(executeTargetList));
|
|
|
+ //没有要执行的,记录一下然后结束
|
|
|
+ if (executeTargetList.isEmpty()){
|
|
|
+ ztPolicyRunInfo.setEndTime(new Date());
|
|
|
+ ztPolicyRunInfo.setTriggered(0);
|
|
|
+ ztPolicyRunInfo.setResultStatus(1);
|
|
|
+ ztPolicyRunInfo.setErrorMessage("成功");
|
|
|
+ ztPolicyConfigMapper.updatePolicyRunRecord(ztPolicyRunInfo);
|
|
|
+ return;
|
|
|
+ }else {
|
|
|
+ ztPolicyRunInfo.setTriggered(0);
|
|
|
+ ztPolicyConfigMapper.updatePolicyRunRecord(ztPolicyRunInfo);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**-------------------------------------执行------------------------------------------------------*/
|
|
|
+ //根据executeTargetList来执行
|
|
|
+
|
|
|
+ List<ZtPolicyAction> actions = policy.getActions();
|
|
|
+ for (ZtPolicyAction action : actions){
|
|
|
+ ZtActionLog actionLog = new ZtActionLog();
|
|
|
+ actionLog.setActionId(action.getId());
|
|
|
+ actionLog.setId(UUID.randomUUID().toString().replace("-","").substring(0,16));
|
|
|
+ actionLog.setRunId(runId);
|
|
|
+ actionLog.setPolicyId(policyId);
|
|
|
+ actionLog.setTargetType(policy.getManagedDimension());
|
|
|
+ actionLog.setActionType(action.getActionType());
|
|
|
+
|
|
|
+ String operateFreqCircle = action.getActionRuleJsonObject().getString("operateFreqCircle");
|
|
|
+ Integer operateFreqLimit = action.getActionRuleJsonObject().getInteger("operateFreqLimit");
|
|
|
+
|
|
|
+ if (action.getActionType() == 10){//feishu
|
|
|
+ actionLog.setTargetId("0");
|
|
|
+ Integer fsTimeType = action.getActionRuleJsonObject().getInteger("fsTimeType");
|
|
|
+ if (fsTimeType == 2){
|
|
|
+ List<String> fsTimeBitmap = action.getActionRuleJsonObject().getJSONArray("fsTimeBitmap").toJavaList(String.class);
|
|
|
+ if (!isInFeishuTime(fsTimeBitmap)){//不在时间段,留一条记录直接退出
|
|
|
+ recordActionSkip(actionLog, 1);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //因为所有的广告账号一起发飞书,就不单独记录targetId了
|
|
|
+ boolean isOperation = isOperation(policyId, "0", action.getId(), operateFreqLimit);
|
|
|
+ if (!isOperation){
|
|
|
+ recordActionSkip(actionLog, 2);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ //飞书通知所有的一起发送,但是记录可以分开记录
|
|
|
+ StringBuffer feishuMessageTextSb = new StringBuffer();
|
|
|
+ feishuMessageTextSb.append("智投助手触发预警\n");
|
|
|
+ feishuMessageTextSb.append("触发策略名称:").append(policy.getName()).append("\n");
|
|
|
+ feishuMessageTextSb.append("触发预警广告账号:\n");
|
|
|
+ for (String executeTarget : executeTargetList){
|
|
|
+ feishuMessageTextSb.append(executeTarget+"\n");
|
|
|
+ }
|
|
|
+ String fsMessage = feishuMessageTextSb.toString();
|
|
|
+ Integer fsSendType = action.getActionRuleJsonObject().getInteger("fsSendType");//1飞书应用单发 2群机器人
|
|
|
+
|
|
|
+ recordOperation(policyId, "0", action.getId(), operateFreqCircle);//频控记录
|
|
|
+ if (fsSendType == 1){//单发,发给策略的创建人
|
|
|
+ Long userId = policy.getCreateUserId();
|
|
|
+ List<JSONObject> users = reportsAdPushMapper.selectUserList();
|
|
|
+ List<String> phonenumbers = new ArrayList<>();
|
|
|
+ for (JSONObject u : users){
|
|
|
+ Long us = u.getLong("user_id");
|
|
|
+ if (Objects.equals(us, userId)){
|
|
|
+ String phone = u.getString("phonenumber");
|
|
|
+ phonenumbers.add(phone);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (!phonenumbers.isEmpty()){
|
|
|
+ Map<String, String> phoneUseridMap = FeishuRobotUtil.getFsUserIds(FeishuRobotUtil.getFsZtTenantToken(), phonenumbers);
|
|
|
+ if (phoneUseridMap != null) {
|
|
|
+ FeishuRobotUtil.sendTextToDt(fsMessage, new ArrayList<>(phoneUseridMap.values()));
|
|
|
+ recordActionSuccess(actionLog);
|
|
|
+ }else {
|
|
|
+ recordActionError(actionLog, "未找到飞书用户ID信息");
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ recordActionError(actionLog, "未找到用户电话号码信息");
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ String message = e.getMessage();
|
|
|
+ if (message.length()>500){
|
|
|
+ message=message.substring(0,500);
|
|
|
+ }
|
|
|
+ recordActionError(actionLog, message);
|
|
|
+ }
|
|
|
+ // 整理这里可能遇到的错误点,写入action_log
|
|
|
+
|
|
|
+ }else {
|
|
|
+ // 频次、时间段拦截, 频次拦截key: policyId_targetId
|
|
|
+ List<String> fsHookUrls = action.getActionRuleJsonObject().getJSONArray("fsHookUrls").toJavaList(String.class);
|
|
|
+ for (String hookUrl : fsHookUrls){
|
|
|
+ try {
|
|
|
+ FeishuRobotUtil.sendTextToWebhook(fsMessage, hookUrl);
|
|
|
+ recordActionSuccess(actionLog);
|
|
|
+ }catch (Exception e){
|
|
|
+ String message = e.getMessage();
|
|
|
+ if (message.length()>500){
|
|
|
+ message=message.substring(0,500);
|
|
|
+ }
|
|
|
+ recordActionError(actionLog, message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }else if (action.getActionType() == 1 || action.getActionType() == 2 || action.getActionType() == 3){//调账号预算
|
|
|
+
|
|
|
+ for (String executeTarget : executeTargetList){
|
|
|
+ actionLog.setTargetId(executeTarget);
|
|
|
+ if (!isOperation(policyId, executeTarget, action.getId(), operateFreqLimit)){
|
|
|
+ //达到频控,不执行
|
|
|
+ recordActionSkip(actionLog, 2);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Integer changeForward = action.getActionRuleJsonObject().getInteger("changeForward");
|
|
|
+ BigDecimal changeRate = action.getActionRuleJsonObject().getBigDecimal("changeRate");
|
|
|
+ BigDecimal changeAmountLimit = action.getActionRuleJsonObject().getBigDecimal("changeAmountLimit");
|
|
|
+ JSONObject budgetInfo;
|
|
|
+ if (action.getActionType() == 1){
|
|
|
+ budgetInfo = bytedanceBudgetStatusService.getAdvertiserBudget(Long.valueOf(executeTarget));
|
|
|
+ }else if (action.getActionType() == 2){
|
|
|
+ String advertiserId = policy.getTargetFromAdvertiserId().get(executeTarget);
|
|
|
+ budgetInfo = bytedanceBudgetStatusService.getProjectBudget(Long.valueOf(advertiserId), Long.valueOf(executeTarget));
|
|
|
+ }else{
|
|
|
+ String advertiserId = policy.getTargetFromAdvertiserId().get(executeTarget);
|
|
|
+ budgetInfo = bytedanceBudgetStatusService.getPromotionBudget(Long.valueOf(advertiserId), Long.valueOf(executeTarget));
|
|
|
+ }
|
|
|
+ if (budgetInfo != null){
|
|
|
+ String budget_mode = budgetInfo.getString("budget_mode");
|
|
|
+ BigDecimal budget = budgetInfo.getBigDecimal("budget");
|
|
|
+ //计算调整之后的预算
|
|
|
+ BigDecimal change;
|
|
|
+ change = budget.multiply(changeRate).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
|
|
|
+ if (changeAmountLimit != null && change.compareTo(changeAmountLimit) > 0){
|
|
|
+ change = changeAmountLimit;
|
|
|
+ }
|
|
|
+ BigDecimal budgetChange;
|
|
|
+ if (changeForward == 1){
|
|
|
+ budgetChange = budget.add(change);
|
|
|
+ }else {
|
|
|
+ budgetChange = budget.subtract(change);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ JSONObject operationResult = null;
|
|
|
+ if (action.getActionType() == 1){
|
|
|
+ operationResult = bytedanceBudgetStatusService.updateAdvertiserBudget(Long.valueOf(executeTarget), budget_mode, budgetChange);
|
|
|
+ }else if (action.getActionType() == 2){
|
|
|
+ String advertiserId = policy.getTargetFromAdvertiserId().get(executeTarget);
|
|
|
+ operationResult = bytedanceBudgetStatusService.updateProjectBudget(Long.valueOf(advertiserId), Long.valueOf(executeTarget), budget_mode, budgetChange);
|
|
|
+ }else{
|
|
|
+ String advertiserId = policy.getTargetFromAdvertiserId().get(executeTarget);
|
|
|
+ operationResult = bytedanceBudgetStatusService.updatePromotionBudget(Long.valueOf(advertiserId), Long.valueOf(executeTarget), budget_mode, budgetChange);
|
|
|
+ }
|
|
|
+ recordOperation(policyId, executeTarget, action.getId(), operateFreqCircle);
|
|
|
+ if (operationResult == null){
|
|
|
+ recordActionError(actionLog, "调整预算失败,调整值:"+budgetChange);
|
|
|
+ }else {
|
|
|
+ Integer code = operationResult.getInteger("code");
|
|
|
+ if (code == null){
|
|
|
+ recordActionError(actionLog, "获取调整预算接口结果失败,调整值:"+budgetChange);
|
|
|
+ }else if (code != 0){
|
|
|
+ recordActionError(actionLog, "调整预算接口错误, message:"+operationResult.getString("message")+", 调整值:"+budgetChange);
|
|
|
+ }else {
|
|
|
+ recordActionSuccess(actionLog);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ recordActionSuccess(actionLog);
|
|
|
+ }catch (Exception e){
|
|
|
+ String message = e.getMessage();
|
|
|
+ if (message.length()>500){
|
|
|
+ message=message.substring(0,500);
|
|
|
+ }
|
|
|
+ recordActionError(actionLog, "调整预算出现错误:"+message);
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ recordActionError(actionLog, "未找到目标的预算信息");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //end for
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private void recordActionSkip(ZtActionLog log, Integer skipReason){
|
|
|
+ recordActionInfo(log, 0, skipReason, 1, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void recordActionError(ZtActionLog log, String errorMessage){
|
|
|
+ recordActionInfo(log, 1, null, 2, errorMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void recordActionSuccess(ZtActionLog log){
|
|
|
+ recordActionInfo(log, 1, null, 1, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void recordActionInfo(ZtActionLog log, Integer executed, Integer skipReason, Integer resultStatus, String errorMessage){
|
|
|
+ log.setExecuted(executed);
|
|
|
+ log.setSkipReason(skipReason);
|
|
|
+ log.setResultStatus(resultStatus);
|
|
|
+ log.setErrorMessage(errorMessage);
|
|
|
+ ztPolicyConfigMapper.insertActionLog(Collections.singletonList(log));
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isInFeishuTime(List<String> feishuBitMap){
|
|
|
+ if (feishuBitMap != null){//判断是否在发送时段内
|
|
|
+ return FsTimeBitmapChecker.hit(feishuBitMap, LocalDateTime.now());
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isOperation(Long policyId, String targetId, Long actionId, Integer operateFreqLimit){
|
|
|
+ if (operateFreqLimit == null || operateFreqLimit == 0){
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ String rkey = "zt:"+policyId+":"+actionId+":"+targetId;
|
|
|
+ RAtomicLong rAtomicLong = redissonClient.getAtomicLong(rkey);
|
|
|
+ if (!rAtomicLong.isExists()){
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ long value = rAtomicLong.get();
|
|
|
+ return value < operateFreqLimit;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void recordOperation(Long policyId, String targetId, Long actionId, String operateFreqCircle){
|
|
|
+ String rkey = "zt:"+policyId+":"+actionId+":"+targetId;
|
|
|
+ RAtomicLong rAtomicLong = redissonClient.getAtomicLong(rkey);
|
|
|
+ if (!rAtomicLong.isExists()){
|
|
|
+ if ("HOUR".equals(operateFreqCircle)){
|
|
|
+ rAtomicLong.set(0);
|
|
|
+ ZoneId zone = ZoneId.systemDefault();
|
|
|
+ Instant hourEnd = ZonedDateTime.now(zone)
|
|
|
+ .truncatedTo(ChronoUnit.HOURS)
|
|
|
+ .plusHours(1)
|
|
|
+ .toInstant();
|
|
|
+ rAtomicLong.expire(hourEnd);
|
|
|
+ }else {//DAY
|
|
|
+ rAtomicLong.set(0);
|
|
|
+ ZoneId zone = ZoneId.systemDefault();
|
|
|
+ Instant dayEnd = LocalDate.now(zone)
|
|
|
+ .plusDays(1)
|
|
|
+ .atStartOfDay(zone)
|
|
|
+ .toInstant();
|
|
|
+ rAtomicLong.expire(dayEnd);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ long nowCount = rAtomicLong.incrementAndGet();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ private ZtPolicy getConfig(Long policyId){
|
|
|
+ ZtPolicy policy = null;
|
|
|
+ if (policyId != null){
|
|
|
+ policy = ztPolicyConfigMapper.getPolicyDetail(policyId);
|
|
|
+ if (policy.getManagedDimension()==1 && policy.getTargetScope()==1){
|
|
|
+ List<ZtPolicyTargetFilter> filterList = ztPolicyConfigMapper.getTargetFilters(policyId);
|
|
|
+ Map<Integer, List<ZtPolicyTargetFilter>> scopeFilterMap =
|
|
|
+ filterList.stream().collect(Collectors.groupingBy(ZtPolicyTargetFilter::getFilterKey));
|
|
|
+ for (Map.Entry<Integer, List<ZtPolicyTargetFilter>> entry : scopeFilterMap.entrySet()) {
|
|
|
+ Integer key = entry.getKey();
|
|
|
+ List<ZtPolicyTargetFilter> value = entry.getValue();
|
|
|
+ if (key == 1){
|
|
|
+ policy.setAppId(value.stream().map(ZtPolicyTargetFilter::getFilterValue).collect(Collectors.toList()));
|
|
|
+ }else if (key == 2){
|
|
|
+ Integer businessLine = Integer.parseInt(value.get(0).getFilterValue());
|
|
|
+ policy.setBusinessLine(businessLine);
|
|
|
+ }else if (key == 3){
|
|
|
+ policy.setBusinessMethod(value.stream().map(ZtPolicyTargetFilter::getFilterValue).collect(Collectors.toList()));
|
|
|
+ }else if (key == 4){
|
|
|
+ List<String> optimizerIdStringList = value.stream().map(ZtPolicyTargetFilter::getFilterValue).collect(Collectors.toList());
|
|
|
+ List<Long> optimizerIdList = optimizerIdStringList.stream().map(Long::parseLong).collect(Collectors.toList());
|
|
|
+ policy.setOptimizerId(optimizerIdList);
|
|
|
+ }else if (key == 5){
|
|
|
+ List<String> deptIdStringList = value.stream().map(ZtPolicyTargetFilter::getFilterValue).collect(Collectors.toList());
|
|
|
+ List<Long> deptIdList = deptIdStringList.stream().map(Long::parseLong).collect(Collectors.toList());
|
|
|
+ policy.setDeptId(deptIdList);
|
|
|
+ }else if (key == 6){
|
|
|
+ policy.setMovieId(value.stream().map(ZtPolicyTargetFilter::getFilterValue).collect(Collectors.toList()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<String> resIds = ztPolicyConfigMapper.advFilterList(policy.getAppId(), policy.getBusinessLine(),
|
|
|
+ policy.getBusinessMethod(), policy.getOptimizerId(), policy.getDeptId(), policy.getMovieId());
|
|
|
+ policy.setTargetResIds(resIds);
|
|
|
+ }else {
|
|
|
+ List<ZtPolicyTargetIds> ids = ztPolicyConfigMapper.getTargetIds(policyId);
|
|
|
+ policy.setTargetScopeIds(ids.stream().map(ZtPolicyTargetIds::getTargetId).collect(Collectors.toList()));
|
|
|
+
|
|
|
+ if (policy.getManagedDimension() == 1 && policy.getTargetScope() == 2){
|
|
|
+ List<String> resIds = ztPolicyConfigMapper.advListFromAdvIds(policyId);
|
|
|
+ policy.setTargetResIds(resIds);
|
|
|
+ }else if (policy.getManagedDimension() == 2 && policy.getTargetScope() == 2){
|
|
|
+ List<JSONObject> resIds = ztPolicyConfigMapper.projectListFromAdvIds(policyId);
|
|
|
+ List<String> rList = new ArrayList<>();
|
|
|
+ Map<String, String> targetFromAdvertiserId = new HashMap<>();
|
|
|
+ for (JSONObject resId : resIds) {
|
|
|
+ rList.add(resId.getString("a_id"));
|
|
|
+ targetFromAdvertiserId.put(resId.getString("a_id"), resId.getString("advertiser_id"));
|
|
|
+ }
|
|
|
+ policy.setTargetResIds(rList);
|
|
|
+ policy.setTargetFromAdvertiserId(targetFromAdvertiserId);
|
|
|
+ }else if (policy.getManagedDimension() == 2 && policy.getTargetScope() == 3){
|
|
|
+ List<JSONObject> resIds = ztPolicyConfigMapper.projectListFromProjIds(policyId);
|
|
|
+ List<String> rList = new ArrayList<>();
|
|
|
+ Map<String, String> targetFromAdvertiserId = new HashMap<>();
|
|
|
+ for (JSONObject resId : resIds) {
|
|
|
+ rList.add(resId.getString("a_id"));
|
|
|
+ targetFromAdvertiserId.put(resId.getString("a_id"), resId.getString("advertiser_id"));
|
|
|
+ }
|
|
|
+ policy.setTargetResIds(rList);
|
|
|
+ policy.setTargetFromAdvertiserId(targetFromAdvertiserId);
|
|
|
+ }else if (policy.getManagedDimension() == 3 && policy.getTargetScope() == 2){
|
|
|
+ List<JSONObject> resIds = ztPolicyConfigMapper.adListFromAdvIds(policyId);
|
|
|
+ List<String> rList = new ArrayList<>();
|
|
|
+ Map<String, String> targetFromAdvertiserId = new HashMap<>();
|
|
|
+ for (JSONObject resId : resIds) {
|
|
|
+ rList.add(resId.getString("ad_id"));
|
|
|
+ targetFromAdvertiserId.put(resId.getString("ad_id"), resId.getString("advertiser_id"));
|
|
|
+ }
|
|
|
+ policy.setTargetResIds(rList);
|
|
|
+ policy.setTargetFromAdvertiserId(targetFromAdvertiserId);
|
|
|
+ }else if (policy.getManagedDimension() == 3 && policy.getTargetScope() == 4){
|
|
|
+ List<JSONObject> resIds = ztPolicyConfigMapper.adListFromAdIds(policyId);
|
|
|
+ List<String> rList = new ArrayList<>();
|
|
|
+ Map<String, String> targetFromAdvertiserId = new HashMap<>();
|
|
|
+ for (JSONObject resId : resIds) {
|
|
|
+ rList.add(resId.getString("ad_id"));
|
|
|
+ targetFromAdvertiserId.put(resId.getString("ad_id"), resId.getString("advertiser_id"));
|
|
|
+ }
|
|
|
+ policy.setTargetResIds(rList);
|
|
|
+ policy.setTargetFromAdvertiserId(targetFromAdvertiserId);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ for (ZtPolicyCondition condition : policy.getConditions()){
|
|
|
+ condition.setCompareValueJsonObject(JSON.parseObject(condition.getCompareValueJson()));
|
|
|
+ }
|
|
|
+ for (ZtPolicyAction action : policy.getActions()){
|
|
|
+ action.setActionRuleJsonObject(JSON.parseObject(action.getActionRuleJson()));
|
|
|
+ }
|
|
|
+ return policy;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|