Bladeren bron

筛选僵尸创意功能2

zhaoxian 4 jaren geleden
bovenliggende
commit
4fbffe1d23

+ 30 - 14
jeecg-boot-module-system/src/test/java/org/jeecg/SampleTest.java

@@ -7,11 +7,16 @@ import cn.com.ctop.common.module.entity.BindAccountLogin;
 import cn.com.ctop.common.module.entity.CtopOauthToken;
 import cn.com.ctop.common.module.entity.UserAllocation;
 import cn.com.ctop.common.module.message.handle.impl.EmailSendMsgHandle;
-import cn.com.ctop.common.module.service.*;
+import cn.com.ctop.common.module.service.IBindAccountLoginService;
+import cn.com.ctop.common.module.service.ICtopOauthTokenService;
+import cn.com.ctop.common.module.service.IUReportExportService;
+import cn.com.ctop.common.module.service.IUReportService;
+import cn.com.ctop.common.module.service.IUserAllocationService;
 import cn.com.ctop.common.module.utils.CtopAdConstant;
 import cn.com.ctop.kuaishou.modules.batch.service.IKuaiShouHistoryReportTaskService;
 import cn.com.ctop.kuaishou.modules.graphql.service.IKuaishouWebInterfaceService;
 import cn.com.ctop.kuaishou.modules.report.service.IKuaishouReportDailyAgentService;
+import cn.com.ctop.kuaishou.modules.report.service.IKuaishouZombieCreativeService;
 import cn.com.ctop.toutiao.modules.material.service.IByteDanceAdvertiserDataService;
 import cn.com.ctop.toutiao.modules.report.service.IByteDanceVideoReportDailyService;
 import cn.com.ctop.toutiao.modules.report.service.IBytedanceReportService;
@@ -173,11 +178,11 @@ public class SampleTest {
     public void loadAccountData() {
 //        List<UserAllocation> allocations = allocationService.getByParams(776L,null,0);
 //        for (UserAllocation allocation:allocations) {
-            CtopOauthToken token = tokenService.getTokenByAccountId(93238965516L);
-            for(int i=92;i<100;i++){
-                Date getDate = DateUtils.addDay(new Date(),-i);
-                reportService.getAdvertiserReport(token, getDate, getDate, CtopAdConstant.BYTEDANCE_REPORT_TYPE_DAILY);
-            }
+        CtopOauthToken token = tokenService.getTokenByAccountId(93238965516L);
+        for (int i = 92; i < 100; i++) {
+            Date getDate = DateUtils.addDay(new Date(), -i);
+            reportService.getAdvertiserReport(token, getDate, getDate, CtopAdConstant.BYTEDANCE_REPORT_TYPE_DAILY);
+        }
 //        }
     }
 
@@ -189,23 +194,23 @@ public class SampleTest {
     IUReportService uReportService;
 
     @Test
-    public void loadBytedanceData(){
+    public void loadBytedanceData() {
         String strings = "1672894840372238_1674183267750990_1673076203257870_1650079154438157_1670286873337870_1648709018451972_1661556811389966_1676540488471559";
         String[] tokens = strings.split("_");
-        for (int i=0;i<tokens.length;i++) {
+        for (int i = 0; i < tokens.length; i++) {
             Long accountId = Long.parseLong(tokens[i]);
             CtopOauthToken token = tokenService.getTokenByAccountId(accountId);
-            for(int j=10;j<110;j++){
+            for (int j = 10; j < 110; j++) {
                 Date getDate = DateUtils.addDay(new Date(), -j);
-                reportService.getAdvertiserReport(token, getDate, getDate,CtopAdConstant.BYTEDANCE_REPORT_TYPE_DAILY);
+                reportService.getAdvertiserReport(token, getDate, getDate, CtopAdConstant.BYTEDANCE_REPORT_TYPE_DAILY);
             }
 
         }
     }
 
     @Test
-    public void loaddata(){
-        for(int i=0;i<30;i++){
+    public void loaddata() {
+        for (int i = 0; i < 30; i++) {
             Date getDate = DateUtils.addDay(new Date(), -i);
             String date = DateUtils.formatDate(getDate);
             videoReportDailyService.videoInfoList(date, date);
@@ -217,9 +222,10 @@ public class SampleTest {
 
     @Autowired
     private IByteDanceVideoReportDailyService videoReportDailyService;
+
     @Test
-    public void loadMatData(){
-        List<UserAllocation> allocations = allocationService.getByParams(320L,null,0);
+    public void loadMatData() {
+        List<UserAllocation> allocations = allocationService.getByParams(320L, null, 0);
         countDownLatch = new CountDownLatch(allocations.size());
         executorService = Executors.newFixedThreadPool(2);
         allocations.forEach(allocation -> {
@@ -245,4 +251,14 @@ public class SampleTest {
         }
         XxlJobLogger.log("物料数据同步完成");
     }
+
+
+    @Autowired
+    private IKuaishouZombieCreativeService kuaishouZombieCreativeService;
+
+    @Test
+    public void checkZombieProject() {
+        kuaishouZombieCreativeService.checkZombieProject();
+    }
+
 }

+ 14 - 2
module-common/src/main/java/cn/com/ctop/common/module/service/IMessageTemplate.java

@@ -1,5 +1,7 @@
 package cn.com.ctop.common.module.service;
 
+import com.alibaba.fastjson.JSONObject;
+
 public interface IMessageTemplate {
 
     String getMaterialSyncTemplate(String projectName, String accountId, String accountName, String materialName, String reason);
@@ -27,12 +29,22 @@ public interface IMessageTemplate {
     String getCreativeOverRunMessage(Long accountId, Integer creativeCount, String authName);
 
     /**
-     * 获取僵尸创意提醒模板
+     * 获取僵尸创意提醒通知模板
+     *
+     * @param
+     * @return java.lang.String
+     * @throws
+     * @author ZHAOXA
+     */
+    String getZombieCreativeRemindTemplate(JSONObject obj);
+
+    /**
+     * 获取僵尸创意关停通知模板
      *
      * @param
      * @return java.lang.String
      * @throws
      * @author ZHAOXA
      */
-    String getZombieCreativeRemindTemplate(long accountId, String creativeName);
+    String getZombieCreativeShutDownTemplate(JSONObject obj);
 }

+ 32 - 6
module-common/src/main/java/cn/com/ctop/common/module/service/impl/MessageTemplateImpl.java

@@ -2,6 +2,7 @@ package cn.com.ctop.common.module.service.impl;
 
 import cn.com.ctop.common.module.service.IMessageTemplate;
 import cn.com.ctop.common.module.utils.Check;
+import com.alibaba.fastjson.JSONObject;
 import org.springframework.stereotype.Service;
 
 @Service
@@ -110,13 +111,38 @@ public class MessageTemplateImpl implements IMessageTemplate {
     }
 
     @Override
-    public String getZombieCreativeRemindTemplate(long accountId, String creativeName) {
+    public String getZombieCreativeRemindTemplate(JSONObject obj) {
         StringBuilder text = new StringBuilder();
-        text.append("创意超限通知:").append("<br/>")
-                .append("您的快手账户:").append(accountId + ",").append("<br/>")
-                .append("授权名称为:" + creativeName).append("<br/>")
-                .append("创意api创建超限。").append("<br/>")
-                .append("如有疑问,请联系产品:吴永前。");
+        text.append("即将成为僵尸创意预警").append("<br/>")
+                .append("您的项目:").append(obj.getString("projectName"))
+                .append("(").append(obj.getString("projectId")).append(")").append("<br/>")
+                .append("广告计划:").append(obj.getString("campaignName"))
+                .append("(").append(obj.getString("campaignId")).append(")").append("<br/>")
+                .append("广告组:").append(obj.getString("unitName"))
+                .append("(").append(obj.getString("unitId")).append(")").append("<br/>")
+                .append("广告创意:").append(obj.getString("creativeName"))
+                .append("(").append(obj.getString("creativeId")).append(")").append("<br/>")
+                .append("当前创意0消耗即将超过5天").append("<br/>")
+                .append("即将变为僵尸创意").append("<br/>")
+                .append("请您及时查看!");
+        return text.toString();
+    }
+
+    @Override
+    public String getZombieCreativeShutDownTemplate(JSONObject obj) {
+        StringBuilder text = new StringBuilder();
+        text.append("已经成为僵尸创意预警").append("<br/>")
+                .append("您的项目:").append(obj.getString("projectName"))
+                .append("(").append(obj.getString("projectId")).append(")").append("<br/>")
+                .append("广告计划:").append(obj.getString("campaignName"))
+                .append("(").append(obj.getString("campaignId")).append(")").append("<br/>")
+                .append("广告组:").append(obj.getString("unitName"))
+                .append("(").append(obj.getString("unitId")).append(")").append("<br/>")
+                .append("广告创意:").append(obj.getString("creativeName"))
+                .append("(").append(obj.getString("creativeId")).append(")").append("<br/>")
+                .append("当前创意0消耗已经超过5天").append("<br/>")
+                .append("已经变为僵尸创意,且已被关停").append("<br/>")
+                .append("请您及时查看!");
         return text.toString();
     }
 }

+ 1 - 1
module-kuaishou/src/main/java/cn/com/ctop/kuaishou/modules/report/entity/KuaishouZombieCreative.java

@@ -45,7 +45,7 @@ public class KuaishouZombieCreative {
      */
     @Excel(name = "创意ID", width = 15)
     @ApiModelProperty(value = "创意ID")
-    private Integer creativeId;
+    private Long creativeId;
     /**
      * 创意名称
      */

+ 20 - 7
module-kuaishou/src/main/java/cn/com/ctop/kuaishou/modules/report/mapper/xml/KuaishouReportDailyCreativeMapper.xml

@@ -283,13 +283,26 @@
 
 
     <select id="checkZombieProject" resultType="com.alibaba.fastjson.JSONObject">
-      SELECT * FROM
-        (SELECT
-        count(stat_date) as dates ,sum(charge) as charge, account_id as accountId,
-        creative_id as creativeId,creative_name as creativeName
-        FROM ctop_kuaishou_report_daily_creative
+      SELECT *FROM
+		(SELECT
+			count(t1.stat_date) AS dates,
+			sum(t1.charge) AS charge,
+			t1.account_id AS accountId,
+			t1.creative_id AS creativeId,
+			t1.creative_name AS creativeName,
+			t1.campaign_id AS campaignId,
+			t1.campaign_name AS campaignName,
+			t1.unit_id AS unitId,
+			t1.unit_name AS unitName,
+			t3.id AS projectId,
+			t3.project_name AS projectName,
+			t2.user_id as userId
+		FROM
+			ctop_kuaishou_report_daily_creative t1
+		LEFT JOIN ctop_user_allocation t2 ON t1.account_id = t2.account_id
+		LEFT JOIN ctop_project t3 ON t2.project_id = t3.id
         where stat_date >= #{date}
-        GROUP BY account_id,creative_id) as t
-    where t.dates = 5 and t.charge = 0
+        GROUP BY t1.account_id,t1.creative_id) as t
+      WHERE t.dates = 5 and t.charge = 0
     </select>
 </mapper>

+ 95 - 15
module-kuaishou/src/main/java/cn/com/ctop/kuaishou/modules/report/service/impl/KuaishouZombieCreativeServiceImpl.java

@@ -1,13 +1,20 @@
 package cn.com.ctop.kuaishou.modules.report.service.impl;
 
+import cn.com.ctop.common.module.entity.CtopOauthToken;
 import cn.com.ctop.common.module.mapper.UserAllocationMapper;
+import cn.com.ctop.common.module.service.ICtopOauthTokenService;
 import cn.com.ctop.common.module.service.IMessageTemplate;
 import cn.com.ctop.common.module.service.ISendMessageService;
 import cn.com.ctop.common.module.utils.Check;
+import cn.com.ctop.common.module.utils.HttpUtils;
+import cn.com.ctop.common.module.utils.KuaishouInterfaceConstant;
+import cn.com.ctop.common.module.utils.PropertiesUtils;
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaiShouUpdateService;
 import cn.com.ctop.kuaishou.modules.report.entity.KuaishouZombieCreative;
 import cn.com.ctop.kuaishou.modules.report.mapper.KuaishouReportDailyCreativeMapper;
 import cn.com.ctop.kuaishou.modules.report.mapper.KuaishouZombieCreativeMapper;
 import cn.com.ctop.kuaishou.modules.report.service.IKuaishouZombieCreativeService;
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -41,6 +48,10 @@ public class KuaishouZombieCreativeServiceImpl extends ServiceImpl<KuaishouZombi
     private IMessageTemplate messageTemplate;
     @Autowired
     private UserAllocationMapper userAllocationMapper;
+    @Autowired
+    private ICtopOauthTokenService oauthTokenService;
+    @Autowired
+    private IKuaiShouUpdateService kuaiShouUpdateService;
 
     /**
      * 筛选僵尸计划
@@ -48,7 +59,7 @@ public class KuaishouZombieCreativeServiceImpl extends ServiceImpl<KuaishouZombi
      * 1、以当天时间为节点,往前取五天的数据,若创意消耗(花费)都为0,则获取其数据,并insert为待确认状态的僵尸创意。
      * 2、获取前一天存储的待确认僵尸计划
      * 3、步骤二和步骤一的数据作比对筛选,若两组数据都含有该创意时,并且为了保证数据的准确性,还需调用API接口获取当天实时消耗明细,
-     * 若消耗不为0,则表明为真正的僵尸创意,3.1更新其状态;3.2同时关停创意;3.3最后发送“关停通知”消息
+     * 若消耗不为0,则表明为真正的僵尸创意,3.1关停创意;3.2然后发送“关停通知”消息;3.3最后更新其状态
      * 4、步骤二存在,步骤一不存在说明创意已经活跃,更新其状态为“2”已活跃、反之则是新的待确认僵尸创意,作insert操作
      * 5、insert操作时,考虑到数据重复的问题,需先查询全部僵尸计划,作筛选比对,已有则更新,否则就新增。
      * **凡insert数据皆为状态0,待确认僵尸创意,且要发送“提醒通知”。
@@ -82,14 +93,24 @@ public class KuaishouZombieCreativeServiceImpl extends ServiceImpl<KuaishouZombi
                     if (zombie.getAccountId() - obj.getInteger("accountId") == 0 && zombie.getCreativeId() - obj.getInteger("creativeId") == 0) {
                         QueryWrapper<KuaishouZombieCreative> wrapper = new QueryWrapper<>();
                         wrapper.eq("id", zombie.getId());
-                        zombie.setStatus(NoEn.NO1.valueStr());
-                        //3.1更新状态
+                        CtopOauthToken token = oauthTokenService.getTokenByAccountId(zombie.getAccountId());
+                        //校验当天是不是依旧不活跃,是则关停,否则更新激活状态
+                        if (isActivation(token, zombie.getCreativeId())) {
+                            //3.1关停创意
+                            Map<String, Object> updateMap = kuaiShouUpdateService.updateCreativeStatus(token.getAccessToken(), zombie.getAccountId(), zombie.getCreativeId(), NoEn.NO2.valueInt(), obj.getString("userId"));
+                            if (!Check.isNull(updateMap) && (boolean) updateMap.get("success")) {
+                                //3.2发送创意关停通知
+                                sendMsg(NoEn.NO2.valueStr(), obj);
+                            }
+                            zombie.setStatus(NoEn.NO1.valueStr());
+                            //记录已确认的僵尸计划集
+                            zombiePlans.add(zombie);
+                            zombieList.add(obj);
+                        } else {
+                            zombie.setStatus(NoEn.NO2.valueStr());
+                        }
+                        //3.3更新状态
                         KuaishouZombieCreativeMapper.update(zombie, wrapper);
-                        //已确认的僵尸计划集
-                        zombiePlans.add(zombie);
-                        zombieList.add(obj);
-                        //TODO 3.3发送创意关停通知
-                        sendMsg(NoEn.NO1.valueStr(), obj.getLong("accountId"), obj.getString("creativeName"));
                     }
                 });
             });
@@ -165,14 +186,13 @@ public class KuaishouZombieCreativeServiceImpl extends ServiceImpl<KuaishouZombi
         list.forEach(obj -> {
             KuaishouZombieCreative create = new KuaishouZombieCreative();
             create.setAccountId(obj.getLong("accountId"));
-            create.setCreativeId(obj.getInteger("creativeId"));
+            create.setCreativeId(obj.getLong("creativeId"));
             create.setCreativeName(obj.getString("creativeName"));
             create.setRecordTime(DateUtils.getNowDate(DateUtils.WEB_FORMAT));
             //状态 0-待确认,1-是僵尸计划,2-已活跃,不是僵尸计划
             create.setStatus(NoEn.NO0.valueStr());
             KuaishouZombieCreativeMapper.insert(create);
-            //TODO 发送待确认通知
-            sendMsg(NoEn.NO1.valueStr(), obj.getLong("accountId"), obj.getString("creativeName"));
+            sendMsg(NoEn.NO1.valueStr(), obj);
         });
     }
 
@@ -184,16 +204,76 @@ public class KuaishouZombieCreativeServiceImpl extends ServiceImpl<KuaishouZombi
      * @throws
      * @author ZHAOXA
      */
-    private void sendMsg(String type, long accountId, String creativeName) {
-        String userId = userAllocationMapper.queryUserIdByAccountId(accountId);
+    private void sendMsg(String type, JSONObject obj) {
+        String userId = userAllocationMapper.queryUserIdByAccountId(obj.getLong("accountId"));
         String message = "";
         if (NoEn.NO1.valueStr().equals(type)) {
             //提醒通知
-            message = messageTemplate.getZombieCreativeRemindTemplate(accountId, creativeName);
+            message = messageTemplate.getZombieCreativeRemindTemplate(obj);
         } else {
             //关停通知
-            message = messageTemplate.getZombieCreativeRemindTemplate(accountId, creativeName);
+            message = messageTemplate.getZombieCreativeShutDownTemplate(obj);
         }
         sendMessageService.sendMessage(userId, message);
     }
+
+    /**
+     * 检查创意是否激活
+     *
+     * @param
+     * @return boolean
+     * @throws
+     * @author ZHAOXA
+     */
+    private boolean isActivation(CtopOauthToken oauthToken, long creativeId) {
+        boolean flag = true;
+        try {
+            JSONArray creativeIds = new JSONArray();
+            creativeIds.add(creativeId);
+            JSONObject info = getAdvertiserCreativeReportDailyInfo(oauthToken, new Date(), new Date(), creativeIds);
+            if (!Check.isNull(info) && !Check.isNull(info.getBigDecimal("charge"))) {
+                flag = false;
+            }
+        } catch (Exception e) {
+            log.error("校验创意是否激活,异常", e);
+            //异常时,默认为激活状态
+            flag = false;
+        }
+        return flag;
+    }
+
+    private JSONObject getAdvertiserCreativeReportDailyInfo(CtopOauthToken token, Date startDate, Date endDate, JSONArray creativeIds) throws Exception {
+        String url = PropertiesUtils.getConfig("kuaishou_api_url") + KuaishouInterfaceConstant.CREATIVE_REPORT;
+        Map<String, String> headers = new HashMap<String, String>();
+        headers.put("Content-Type", "application/json");
+        headers.put("Access-Token", token.getAccessToken());
+        Map<String, Object> param = new HashMap<String, Object>();
+        if (!Check.isNull(startDate)) {
+            param.put("start_date", DateUtils.formatDate(startDate));
+        }
+        if (!Check.isNull(endDate)) {
+            param.put("end_date", DateUtils.formatDate(endDate));
+        }
+        if (!Check.isNull(creativeIds) && creativeIds.size() > 0) {
+            param.put("creative_ids", creativeIds);
+
+        }
+        param.put("advertiser_id", token.getAccountId());
+        param.put("temporal_granularity", "DAILY");
+
+        String result = HttpUtils.httpPostRequest(url, param, headers);
+        JSONObject resultJson = JSONObject.parseObject(result);
+        Integer code = resultJson.getInteger("code");
+        String message = resultJson.getString("message");
+        if (null == code || code != 0) {
+            throw new Exception("获取快手广告创意分天报表异常:" + message + ",accountId:" + token.getAccountId());
+        }
+        JSONArray details = resultJson.getJSONObject("data").getJSONArray("details");
+        if (null == details || details.size() <= 0) {
+            return null;
+        }
+        return (JSONObject) details.get(0);
+    }
+
+
 }