Forráskód Böngészése

调整销售绩效核算逻辑

syh 5 éve
szülő
commit
e902f86676
19 módosított fájl, 271 hozzáadás és 265 törlés
  1. 1 0
      jeecg-boot-module-system/src/main/java/org/jeecg/config/ShiroConfig.java
  2. 25 83
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/AdvertiserController.java
  3. 10 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/VideoModelController.java
  4. 4 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/SalePerformanceDetail.java
  5. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/AdvertiserMapper.java
  6. 21 4
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/xml/AdvertiserMapper.xml
  7. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IAdvertiserService.java
  8. 11 1
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/AdvertiserServiceImpl.java
  9. 51 40
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/PerformanceSaleServiceImpl.java
  10. 2 7
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/CornerCheck.java
  11. 4 9
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/Perspective.java
  12. 71 71
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/Test.java
  13. 10 14
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/VideoProcessing.java
  14. 23 23
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/excelutil/entity/YdPlanAggregateEntity.java
  15. 10 1
      jeecg-boot-module-system/src/test/java/org/jeecg/SampleTest.java
  16. 2 2
      performance-appraisal/src/main/java/cn/com/ctop/performanceappraisal/mapper/PerformanceMapper.java
  17. 6 0
      performance-appraisal/src/main/java/cn/com/ctop/performanceappraisal/mapper/xml/PerformanceMapper.xml
  18. 3 3
      performance-appraisal/src/main/java/cn/com/ctop/performanceappraisal/service/IPerformanceService.java
  19. 7 7
      performance-appraisal/src/main/java/cn/com/ctop/performanceappraisal/service/impl/PerformanceServiceImpl.java

+ 1 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/config/ShiroConfig.java

@@ -147,6 +147,7 @@ public class ShiroConfig {
 		filterChainDefinitionMap.put("/graphql/video", "anon");
 		filterChainDefinitionMap.put("/ks/web/test", "anon");
         filterChainDefinitionMap.put("/ureport/**", "anon");
+        filterChainDefinitionMap.put("/ctop/advertiser/**", "anon");
 
 		// 添加自己的过滤器并且取名为jwt
 		Map<String, Filter> filterMap = new HashMap<String, Filter>(1);

+ 25 - 83
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/AdvertiserController.java

@@ -10,7 +10,6 @@ import cn.com.ctop.common.module.utils.StringUtils;
 import com.alibaba.excel.EasyExcelFactory;
 import com.alibaba.excel.ExcelWriter;
 import com.alibaba.excel.metadata.Sheet;
-import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -22,7 +21,6 @@ import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.aspect.annotation.AutoLog;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.util.DateUtils;
-import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.ctop.entity.Advertiser;
 import org.jeecg.modules.ctop.entity.Project;
 import org.jeecg.modules.ctop.mapper.ProjectMapper;
@@ -37,23 +35,13 @@ import org.jeecg.modules.system.entity.UserCompany;
 import org.jeecg.modules.system.mapper.UserCompanyMapper;
 import org.jeecg.modules.system.service.ISysCategoryService;
 import org.jeecg.modules.system.service.ISysUserService;
-import org.jeecgframework.poi.excel.ExcelImportUtil;
-import org.jeecgframework.poi.excel.def.NormalExcelConstants;
-import org.jeecgframework.poi.excel.entity.ExportParams;
-import org.jeecgframework.poi.excel.entity.ImportParams;
-import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.multipart.MultipartHttpServletRequest;
-import org.springframework.web.servlet.ModelAndView;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
 import java.util.*;
 
 /**
@@ -331,92 +319,46 @@ public class AdvertiserController {
     }
 
     /**
-     * 导出excel
-     *
-     * @param request
-     * @param response
-     */
-    @RequestMapping(value = "/exportXls")
-    public ModelAndView exportXls(HttpServletRequest request, HttpServletResponse response) {
-        // Step.1 组装查询条件
-        QueryWrapper<Advertiser> queryWrapper = null;
-        try {
-            String paramsStr = request.getParameter("paramsStr");
-            if (oConvertUtils.isNotEmpty(paramsStr)) {
-                String deString = URLDecoder.decode(paramsStr, "UTF-8");
-                Advertiser advertiser = JSON.parseObject(deString, Advertiser.class);
-                queryWrapper = QueryGenerator.initQueryWrapper(advertiser, request.getParameterMap());
-            }
-        } catch (UnsupportedEncodingException e) {
-            e.printStackTrace();
-        }
-
-        //Step.2 AutoPoi 导出Excel
-        ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
-        List<Advertiser> pageList = advertiserService.list(queryWrapper);
-        //导出文件名称
-        mv.addObject(NormalExcelConstants.FILE_NAME, "广告主信息表列表");
-        mv.addObject(NormalExcelConstants.CLASS, Advertiser.class);
-        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("广告主信息表列表数据", "导出人:Jeecg", "导出信息"));
-        mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
-        return mv;
-    }
-
-    /**
-     * 通过excel导入数据
+     * 导出伊对报表
      *
-     * @param request
-     * @param response
      * @return
      */
-    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
-    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
-        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
-        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
-        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
-            // 获取上传文件对象
-            MultipartFile file = entity.getValue();
-            ImportParams params = new ImportParams();
-            params.setTitleRows(2);
-            params.setHeadRows(1);
-            params.setNeedSave(true);
-            try {
-                List<Advertiser> listAdvertisers = ExcelImportUtil.importExcel(file.getInputStream(), Advertiser.class, params);
-                for (Advertiser advertiserExcel : listAdvertisers) {
-                    advertiserService.save(advertiserExcel);
-                }
-                return Result.ok("文件导入成功!数据行数:" + listAdvertisers.size());
-            } catch (Exception e) {
-                log.error(e.getMessage(), e);
-                return Result.error("文件导入失败:" + e.getMessage());
-            } finally {
-                try {
-                    file.getInputStream().close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-        return Result.ok("文件导入失败!");
+    @RequestMapping(value = "/ydWeekReportList")
+    public Map<String, Object> ydReportList(HttpServletRequest request, HttpServletResponse response, @RequestBody JSONObject data) throws Exception {
+        Map<String, Object> result = new HashMap<>();
+        Long projectId = data.getLong("projectId");
+        String startDate = data.getString("startDate");
+        String endDate = data.getString("endDate");
+        List<SheetInfoVo> vos = advertiserService.getYdStatisticInfo(projectId, startDate, endDate);
+        result.put("data", vos);
+        ResultMapUtils.setResultMap(result, StatusCode.COMMON_SUCCESS);
+        return result;
     }
 
     /**
-     * 导出伊对报表
+     * 导出报表
      *
      * @return
      */
-    @RequestMapping(value = "/ydWeekReportList")
+    @RequestMapping(value = "/exportYdDailyReport")
     @ResponseBody
-    public Map<String, Object> ydReportList(HttpServletRequest request, HttpServletResponse response, @RequestBody JSONObject data) throws Exception {
+    public void exportYdWeek(HttpServletRequest request, HttpServletResponse response, @RequestBody JSONObject data) throws Exception {
         Map<String, Object> result = new HashMap<>();
-        //查询总的消耗信息
         Long projectId = data.getLong("projectId");
         String startDate = data.getString("startDate");
         String endDate = data.getString("endDate");
         List<SheetInfoVo> vos = advertiserService.getYdStatisticInfo(projectId, startDate, endDate);
-        result.put("data", vos);
-        ResultMapUtils.setResultMap(result, StatusCode.COMMON_SUCCESS);
-        return result;
+        OutputStream outputStream = response.getOutputStream();
+        this.setResponseHeader(response, "伊对" + startDate + "至" + endDate + "周报.xls");
+        ExcelWriter excelWriter = EasyExcelFactory.getWriter(outputStream);
+        for (int i = 0; i < vos.size(); i++) {
+            Sheet sheet = new Sheet(i + 1, 0, KuaishouXxlEntity.class);
+            sheet.setSheetName(vos.get(i).getSheetName());
+            excelWriter.write(vos.get(i).getDetails(), sheet);
+        }
+        excelWriter.finish();
+        outputStream.flush();
+        outputStream.close();
     }
 
     /**

+ 10 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/VideoModelController.java

@@ -0,0 +1,10 @@
+package org.jeecg.modules.ctop.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/video/model")
+public class VideoModelController {
+
+}

+ 4 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/SalePerformanceDetail.java

@@ -56,6 +56,10 @@ public class SalePerformanceDetail {
     @Excel(name = "广告主id", width = 15)
     @ApiModelProperty(value = "广告主id")
     private String advertiserId;
+
+    @Excel(name = "户id", width = 15)
+    @ApiModelProperty(value = "户id")
+    private Long accountId;
     /**
      * 年
      */

+ 5 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/AdvertiserMapper.java

@@ -1,5 +1,6 @@
 package org.jeecg.modules.ctop.mapper;
 
+import cn.com.ctop.common.module.entity.UserAllocation;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Param;
 import org.jeecg.modules.ctop.entity.Advertiser;
@@ -22,4 +23,8 @@ public interface AdvertiserMapper extends BaseMapper<Advertiser> {
     YdWeekAggregateEntity getYdWeekStatisticInfo(@Param(value = "projectId") Long projecgId, @Param(value = "start") String lastWeekStart, @Param(value = "end") String lastWeekEnd);
 
     List<YdPlanAggregateEntity> getYdWeekPlanStatisticInfoAll(@Param(value = "start") String startDate, @Param(value = "end") String endDate, @Param(value = "accountId") Long accountId);
+
+    List<UserAllocation> getAllocationsBySaleId(@Param(value = "saleId") String saleId);
+
+    List<UserAllocation> getAllocationsByAdvertiserId(@Param(value = "adId") String adId);
 }

+ 21 - 4
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/xml/AdvertiserMapper.xml

@@ -97,13 +97,13 @@
             concat(#{start}, '至', #{end})as date,
             daily.campaign_name as planName,
             sum(daily.cost) as totalCost,
-            sum(daily.show_num) as show,
-            sum(daily.click) as click,
+            sum(daily.show_num) as showNum,
+            sum(daily.click) as clickNum,
             (case
                 when sum(daily.click)!=0 and sum(daily.show_num)!=0
                 then concat(round(sum(daily.click)/sum(daily.show_num)*100,2),'%')
                 else '0%'
-            end
+                end
             )as clickRate,
             (case
                 when sum(daily.cost)!=0 and sum(daily.click)!=0
@@ -117,7 +117,7 @@
                 else 0
                 end
             )as ctr,
-            sum(daily.convert_num) as convert,
+            sum(daily.convert_num) as convertNum,
             (case
                 when sum(daily.convert_num)!=0 and sum(daily.cost)!=0
                 then round(sum(daily.cost)/sum(daily.convert_num),2)
@@ -153,4 +153,21 @@
         and daily.stat_datetime &lt;= #{end}
         group by daily.campaign_id order by sum(daily.cost) desc
     </select>
+    <select id="getAllocationsBySaleId" resultType="cn.com.ctop.common.module.entity.UserAllocation">
+        select
+            allocation.*
+        from
+            ctop_user_allocation allocation
+         left join ctop_project project on project.id = allocation.project_id
+         left join ctop_advertiser advertiser on advertiser.id = project.advertiser_id
+        where advertiser.sale_id = #{saleId}
+    </select>
+    <select id="getAllocationsByAdvertiserId" resultType="cn.com.ctop.common.module.entity.UserAllocation">
+        select
+            allocation.*
+        from
+            ctop_user_allocation allocation
+         left join ctop_project project on project.id = allocation.project_id
+         where project.advertiser_id = #{adId}
+    </select>
 </mapper>

+ 5 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IAdvertiserService.java

@@ -1,5 +1,6 @@
 package org.jeecg.modules.ctop.service;
 
+import cn.com.ctop.common.module.entity.UserAllocation;
 import com.baomidou.mybatisplus.extension.service.IService;
 import org.jeecg.modules.ctop.entity.Advertiser;
 import org.jeecg.modules.ctop.vo.SheetInfoVo;
@@ -16,9 +17,13 @@ public interface IAdvertiserService extends IService<Advertiser> {
 
     List<Advertiser> getBySaleId(String saleId);
 
+    List<UserAllocation> getAllocationsBySaleId(String saleId);
+
     SheetInfoVo getXxlStatisticInfo(Long projectId, String systemType, Long accountId, String sheetName);
 
     List<SheetInfoVo> getSystemTypeXxlStatisticInfo(Long projectId);
 
     List<SheetInfoVo> getYdStatisticInfo(Long projectId, String startDate, String endDate);
+
+    List<UserAllocation> getAllocationsByAdvertiserId(String id);
 }

+ 11 - 1
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/AdvertiserServiceImpl.java

@@ -42,6 +42,11 @@ public class AdvertiserServiceImpl extends ServiceImpl<AdvertiserMapper, Adverti
     }
 
     @Override
+    public List<UserAllocation> getAllocationsBySaleId(String saleId) {
+        return advertiserMapper.getAllocationsBySaleId(saleId);
+    }
+
+    @Override
     public SheetInfoVo getXxlStatisticInfo(Long projectId, String systemType, Long accountId, String sheetName) {
         SheetInfoVo vo = new SheetInfoVo<KuaishouXxlEntity>();
         List<KuaishouXxlEntity> details = new ArrayList<>();
@@ -103,13 +108,18 @@ public class AdvertiserServiceImpl extends ServiceImpl<AdvertiserMapper, Adverti
             sheetInfoVos.add(secondVo);
             //3:获取每周素材统计
 
-            return null;
+            return sheetInfoVos;
         } catch (ParseException e) {
             e.printStackTrace();
         }
         return null;
     }
 
+    @Override
+    public List<UserAllocation> getAllocationsByAdvertiserId(String adId) {
+        return advertiserMapper.getAllocationsByAdvertiserId(adId);
+    }
+
     private List<YdPlanAggregateEntity> getYdPlanStatisticInfo(Long projectId, String startDate, String endDate) {
         List<YdPlanAggregateEntity> result = new ArrayList<>();
         List<UserAllocation> allocations = userAllocationService.getByProjectId(projectId, null);

+ 51 - 40
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/PerformanceSaleServiceImpl.java

@@ -1,7 +1,9 @@
 package org.jeecg.modules.ctop.service.impl;
 
+import cn.com.ctop.common.module.entity.UserAllocation;
 import cn.com.ctop.common.module.utils.CtopAdConstant;
 import cn.com.ctop.performanceappraisal.service.IPerformanceService;
+import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.util.DateUtils;
 import org.jeecg.modules.ctop.entity.Advertiser;
 import org.jeecg.modules.ctop.entity.SalePerformanceDetail;
@@ -23,6 +25,7 @@ import java.util.Date;
 import java.util.List;
 
 @Service
+@Slf4j
 public class PerformanceSaleServiceImpl implements IPerformanceSaleService {
 
     @Autowired
@@ -55,60 +58,68 @@ public class PerformanceSaleServiceImpl implements IPerformanceSaleService {
 
     public void countPerformance(SysUser user) {
 //        Date getDate = DateUtils.addDay(new Date(), -1)
-        Date getDate = DateUtils.addDay(new Date(), -15);
+        log.info("销售人员名称:{}", user.getRealname());
+        Date getDate = DateUtils.addDay(new Date(), -18);
         String startDateStr = DateUtils.getQuarterStartDate(getDate);
         String endDateStr = DateUtils.getQuarterEndDate(getDate);
         //获取用户角色信息
         SysUserRole userRole = userRoleService.getUserRoleByUserId(user.getId());
-        //1:获取快手季度总消耗
-        BigDecimal kuaishouFinishMediaTask = performanceService.getKuaishouSeasonTotalCost(startDateStr, endDateStr);
+        //1:获取快手季度总消耗 TODO 后续需要改成动态获取
+        BigDecimal kuaishouFinishMediaTask = CtopAdConstant.KUAISHOU_MEDIA_TASK_COST;
         //2:获取快手个人季度总消耗
-        BigDecimal kuaishouFinishPersonnalTask = performanceService.getKuaishouSalesSeasonTotalCostByParams(startDateStr, endDateStr, user.getId(), null);
-        //1:获取头条季度总消耗
-        BigDecimal bytedanceFinishMediaTask = performanceService.getBytedanceSeasonTotalCost(startDateStr, endDateStr);
+        BigDecimal kuaishouFinishPersonnalTask = performanceService.getKuaishouSalesSeasonTotalCostByParams(startDateStr, endDateStr, user.getId(), null, null);
+        //1:获取头条季度总消耗 TODO 后续需要改成动态获取
+        BigDecimal bytedanceFinishMediaTask = CtopAdConstant.BYTEDANCE_MEDIA_TASK_COST;
         //2:获取头条个人季度总消耗
-        BigDecimal bytedanceFinishPersonnalTask = performanceService.getBytedanceSalesSeasonTotalCostByParams(startDateStr, endDateStr, user.getId(), null);
+        BigDecimal bytedanceFinishPersonnalTask = performanceService.getBytedanceSalesSeasonTotalCostByParams(startDateStr, endDateStr, user.getId(), null, null);
         //获取销售所属的广告主信息
         List<Advertiser> advertiserList = advertiserService.getBySaleId(user.getId());
-
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date startSeasonDate = null;
+        Date endSeasonDate = null;
+        try {
+            startSeasonDate = dateFormat.parse(startDateStr);
+            endSeasonDate = dateFormat.parse(endDateStr);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
         if (null != advertiserList && advertiserList.size() > 0) {
-            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
-            Date startSeasonDate = null;
-            Date endSeasonDate = null;
-            try {
-                startSeasonDate = dateFormat.parse(startDateStr);
-                endSeasonDate = dateFormat.parse(endDateStr);
-            } catch (ParseException e) {
-                e.printStackTrace();
-            }
-
             for (Advertiser advertiser : advertiserList) {
-                Date endOldDate = DateUtils.addDay(advertiser.getCreateTime(), 90);
-                if (startSeasonDate.after(endOldDate)) {
-                    //季度开始时间大于新户结束时间(全部按照老户逻辑计算)
-                    saveSalePerformanceDetail(advertiser, user, userRole, DateUtils.getYear(getDate), DateUtils.getQuarter(getDate),
-                            startDateStr, endDateStr, bytedanceFinishMediaTask, bytedanceFinishPersonnalTask, kuaishouFinishMediaTask,
-                            kuaishouFinishPersonnalTask, 0);
-                } else if (endOldDate.after(endSeasonDate)) {
-                    saveSalePerformanceDetail(advertiser, user, userRole, DateUtils.getYear(getDate), DateUtils.getQuarter(getDate),
-                            startDateStr, endDateStr, bytedanceFinishMediaTask, bytedanceFinishPersonnalTask, kuaishouFinishMediaTask,
-                            kuaishouFinishPersonnalTask, 1);
-                } else {
-                    //新户结束时间处于本季度中间
-                    String endduring1Date = DateUtils.formatDate(endOldDate);
-                    saveSalePerformanceDetail(advertiser, user, userRole, DateUtils.getYear(getDate), DateUtils.getQuarter(getDate),
-                            startDateStr, endduring1Date, bytedanceFinishMediaTask, bytedanceFinishPersonnalTask, kuaishouFinishMediaTask,
-                            kuaishouFinishPersonnalTask, 1);
-                    saveSalePerformanceDetail(advertiser, user, userRole, DateUtils.getYear(getDate), DateUtils.getQuarter(getDate),
-                            endduring1Date, endDateStr, bytedanceFinishMediaTask, bytedanceFinishPersonnalTask, kuaishouFinishMediaTask,
-                            kuaishouFinishPersonnalTask, 0);
+                //1:根据广告主查询用户绑定信息
+                List<UserAllocation> allocations = advertiserService.getAllocationsByAdvertiserId(advertiser.getId());
+                if (null != allocations && allocations.size() > 0) {
+                    Date finalStartSeasonDate = startSeasonDate;
+                    Date finalEndSeasonDate = endSeasonDate;
+                    allocations.forEach(allocation -> {
+                        Date endOldDate = DateUtils.addDay(allocation.getCreateTime(), 90);
+                        if (finalStartSeasonDate.after(endOldDate)) {
+                            //季度开始时间大于新户结束时间(全部按照老户逻辑计算)
+                            saveSalePerformanceDetail(allocation, advertiser, user, userRole, DateUtils.getYear(getDate), DateUtils.getQuarter(getDate),
+                                    startDateStr, endDateStr, bytedanceFinishMediaTask, bytedanceFinishPersonnalTask, kuaishouFinishMediaTask,
+                                    kuaishouFinishPersonnalTask, 0);
+                        } else if (endOldDate.after(finalEndSeasonDate)) {
+                            saveSalePerformanceDetail(allocation, advertiser, user, userRole, DateUtils.getYear(getDate), DateUtils.getQuarter(getDate),
+                                    startDateStr, endDateStr, bytedanceFinishMediaTask, bytedanceFinishPersonnalTask, kuaishouFinishMediaTask,
+                                    kuaishouFinishPersonnalTask, 1);
+                        } else {
+                            //新户结束时间处于本季度中间
+                            String endduring1Date = DateUtils.formatDate(endOldDate);
+                            saveSalePerformanceDetail(allocation, advertiser, user, userRole, DateUtils.getYear(getDate), DateUtils.getQuarter(getDate),
+                                    startDateStr, endduring1Date, bytedanceFinishMediaTask, bytedanceFinishPersonnalTask, kuaishouFinishMediaTask,
+                                    kuaishouFinishPersonnalTask, 1);
+                            saveSalePerformanceDetail(allocation, advertiser, user, userRole, DateUtils.getYear(getDate), DateUtils.getQuarter(getDate),
+                                    endduring1Date, endDateStr, bytedanceFinishMediaTask, bytedanceFinishPersonnalTask, kuaishouFinishMediaTask,
+                                    kuaishouFinishPersonnalTask, 0);
+                        }
+                    });
                 }
             }
         }
     }
 
-    private void saveSalePerformanceDetail(Advertiser advertiser, SysUser user, SysUserRole userRole, int year, int quarter, String startDate, String endDate, BigDecimal bytedanceFinishMediaTask, BigDecimal bytedanceFinishPersonnalTask, BigDecimal kuaishouFinishMediaTask, BigDecimal kuaishouFinishPersonnalTask, Integer brandNew) {
+    private void saveSalePerformanceDetail(UserAllocation allocation, Advertiser advertiser, SysUser user, SysUserRole userRole, int year, int quarter, String startDate, String endDate, BigDecimal bytedanceFinishMediaTask, BigDecimal bytedanceFinishPersonnalTask, BigDecimal kuaishouFinishMediaTask, BigDecimal kuaishouFinishPersonnalTask, Integer brandNew) {
         SalePerformanceDetail detail = new SalePerformanceDetail();
+        detail.setAccountId(allocation.getAccountId());
         detail.setAdvertiserId(advertiser.getId());
         detail.setSaleId(user.getId());
         detail.setRoleId(userRole.getRoleId());
@@ -120,7 +131,7 @@ public class PerformanceSaleServiceImpl implements IPerformanceSaleService {
         detail.setBrandNew(brandNew);
         if (user.getOrgCode().startsWith(CtopAdConstant.HB_BYTEDANCE_SALE_ORG_CODE)) {
             detail.setMediaType(CtopAdConstant.PLATFORM_TYPE_BYTEDANCE);
-            BigDecimal totalCost = performanceService.getSalesSeasonTotalCostByParams(startDate, endDate, null, advertiser.getId(), CtopAdConstant.PLATFORM_TYPE_BYTEDANCE);
+            BigDecimal totalCost = performanceService.getSalesSeasonTotalCostByParams(startDate, endDate, null, null, allocation.getAccountId(), CtopAdConstant.PLATFORM_TYPE_BYTEDANCE);
             if (null == totalCost) {
                 totalCost = BigDecimal.ZERO;
             }
@@ -134,7 +145,7 @@ public class PerformanceSaleServiceImpl implements IPerformanceSaleService {
             salePerformanceDetailService.save(detail);
         } else if (user.getOrgCode().startsWith(CtopAdConstant.HB_KUAISHOU_SALE_ORG_CODE)) {
             detail.setMediaType(CtopAdConstant.PLATFORM_TYPE_KUAISHOU);
-            BigDecimal totalCost = performanceService.getSalesSeasonTotalCostByParams(startDate, endDate, null, advertiser.getId(), CtopAdConstant.PLATFORM_TYPE_KUAISHOU);
+            BigDecimal totalCost = performanceService.getSalesSeasonTotalCostByParams(startDate, endDate, null, null, allocation.getAccountId(), CtopAdConstant.PLATFORM_TYPE_KUAISHOU);
             if (null == totalCost) {
                 totalCost = BigDecimal.ZERO;
             }

+ 2 - 7
jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/CornerCheck.java

@@ -1,4 +1,4 @@
-/*
+
 package org.jeecg.modules.demo.opencv;
 
 import cn.com.ctop.common.module.utils.ResultMapUtils;
@@ -9,11 +9,9 @@ import org.opencv.imgproc.Imgproc;
 
 import java.util.*;
 
-*/
 /**
  * 角点检测
- *//*
-
+ */
 public class CornerCheck {
     static {
         System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
@@ -21,8 +19,6 @@ public class CornerCheck {
 
     private static int EXPAND_SIZE = 3;
     public static void main(String[] args) {
-//        harris();
-//        detectConers();
         channelSplit();
     }
 
@@ -228,4 +224,3 @@ public class CornerCheck {
         }
     }
 }
-*/

+ 4 - 9
jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/Perspective.java

@@ -1,4 +1,3 @@
-/*
 package org.jeecg.modules.demo.opencv;
 
 
@@ -9,11 +8,9 @@ import org.opencv.utils.Converters;
 
 import java.util.List;
 
-*/
 /**
  * 透视变换
- *//*
-
+ */
 public class Perspective {
     public static void main(String[] args) {
 
@@ -111,15 +108,14 @@ public class Perspective {
         return (iSum % 2) != 0;
     }
 
-    */
-/**
+
+    /**
      * 判断点是否在多边形内,如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
      *
      * @param point   检测点
      * @param polygon 多边形的顶点
      * @return 点在多边形内返回true, 否则返回false
-     *//*
-
+     */
     public static boolean isPtInPoly(Point point, List<Point> polygon) {
 
         int N = polygon.size();
@@ -212,4 +208,3 @@ public class Perspective {
         }
     }
 }
-*/

+ 71 - 71
jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/Test.java

@@ -1,72 +1,72 @@
-//package org.jeecg.modules.demo.opencv;
-//
-//import org.opencv.core.Core;
-//import org.opencv.core.Mat;
-//import org.opencv.core.Size;
-//import org.opencv.imgcodecs.Imgcodecs;
-//import org.opencv.imgproc.Imgproc;
-//
-//public class Test {
-//    public static void initVideo(){
-//        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
-//        String srcPath = "D:\\data\\images\\";
-//        String fillPath = "D:\\data\\fill\\";
-//        String targetPath = "D:\\data\\video\\";
-//        //1:切分视频
-////        VideoProcessing.grabberVideoFramer("D://data//video.mp4",srcPath);
-////        VideoProcessing.grabberVideoFramer("D://data//fill.mp4",fillPath);
-//        //2:合并图片
-//        int srcPhoneFrameNumFrom = 163;
-//        int changeSenceFrameNumFrom = 234;
-//        //2.1 复制原始视频无变化图片
-////        for(int i=1;i<srcPhoneFrameNumFrom;i++){
-////            Mat srcNoChangeImage = Imgcodecs.imread(srcPath+i+".jpg");
-////            Imgcodecs.imwrite(targetPath+i+".jpg",srcNoChangeImage);
-////        }
-//        String getImageName = "";
-//        //2.2 填充手机内部图片画面
-//        for (int i = 163; i < changeSenceFrameNumFrom; i++) {
-//            String backImg = srcPath + (i) + ".jpg";
-//            String phoneImg = fillPath + (i - 162) + ".jpg";
-//            String targetImg = targetPath + i + ".jpg";
-//            Perspective.perpectiveImg(backImg, phoneImg, targetImg);
-//            getImageName = targetImg;
+package org.jeecg.modules.demo.opencv;
+
+import org.opencv.core.Core;
+import org.opencv.core.Mat;
+import org.opencv.core.Size;
+import org.opencv.imgcodecs.Imgcodecs;
+import org.opencv.imgproc.Imgproc;
+
+public class Test {
+    public static void initVideo() {
+        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
+        String srcPath = "D:\\data\\images\\";
+        String fillPath = "D:\\data\\fill\\";
+        String targetPath = "D:\\data\\video\\";
+        //1:切分视频
+//        VideoProcessing.grabberVideoFramer("D://data//video.mp4",srcPath);
+//        VideoProcessing.grabberVideoFramer("D://data//fill.mp4",fillPath);
+        //2:合并图片
+        int srcPhoneFrameNumFrom = 163;
+        int changeSenceFrameNumFrom = 234;
+        //2.1 复制原始视频无变化图片
+//        for(int i=1;i<srcPhoneFrameNumFrom;i++){
+//            Mat srcNoChangeImage = Imgcodecs.imread(srcPath+i+".jpg");
+//            Imgcodecs.imwrite(targetPath+i+".jpg",srcNoChangeImage);
 //        }
-//        //2.3 转场动画
-//        Mat image = Imgcodecs.imread(getImageName, Imgcodecs.IMREAD_COLOR);
-//        //(1)径向模糊图片
-//        Mat radialBlur = ImageUtils.radialBlur(image);
-//        Imgcodecs.imwrite(targetPath + changeSenceFrameNumFrom + ".jpg", radialBlur);
-//        changeSenceFrameNumFrom++;
-//        //(2)放大后径向模糊图片
-//        Mat bigImamge = new Mat();
-//        Imgproc.resize(image, bigImamge, new Size(image.cols() * 1.25, image.rows() * 1.25));
-//        Mat destBigImamge = ImageUtils.cutFromCenter(bigImamge, image.width(), image.height());
-//        Mat radialBlurDestBigImamge = ImageUtils.radialBlur(destBigImamge);
-//        Imgcodecs.imwrite(targetPath + changeSenceFrameNumFrom + ".jpg", radialBlurDestBigImamge);
-//        changeSenceFrameNumFrom++;
-//        //(3)缩小之后重复平铺加径向模糊
-//        Mat smallImage = new Mat();
-//        Mat halfImage = new Mat();
-//        Mat wholeImage = new Mat();
-//        Imgproc.resize(image, smallImage, new Size(image.cols() / 2, image.rows() / 2));
-//        ImageUtils.hconcat(smallImage, smallImage, halfImage);
-//        ImageUtils.vconcat(halfImage, halfImage, wholeImage);
-//        wholeImage = ImageUtils.radialBlur(wholeImage);
-//        Imgcodecs.imwrite(targetPath + changeSenceFrameNumFrom + ".jpg", wholeImage);
-//        changeSenceFrameNumFrom++;
-//        //复制填充视频无变化图片
-////        for(int i=changeSenceFrameNumFrom;i<100000;i++){
-////            int checkNum = i-3-srcPhoneFrameNumFrom+1;
-////            String fillImagePath = fillPath+checkNum+".jpg";
-////            File file = new File(fillImagePath);
-////            if(file.exists()){
-////                Mat srcMat = Imgcodecs.imread(fillImagePath);
-////                Imgcodecs.imwrite(targetPath+i+".jpg",srcMat);
-////            }else{
-////                break;
-////            }
-////        }
-//    }
-//
-//}
+        String getImageName = "";
+        //2.2 填充手机内部图片画面
+        for (int i = 163; i < changeSenceFrameNumFrom; i++) {
+            String backImg = srcPath + (i) + ".jpg";
+            String phoneImg = fillPath + (i - 162) + ".jpg";
+            String targetImg = targetPath + i + ".jpg";
+            Perspective.perpectiveImg(backImg, phoneImg, targetImg);
+            getImageName = targetImg;
+        }
+        //2.3 转场动画
+        Mat image = Imgcodecs.imread(getImageName, Imgcodecs.IMREAD_COLOR);
+        //(1)径向模糊图片
+        Mat radialBlur = ImageUtils.radialBlur(image);
+        Imgcodecs.imwrite(targetPath + changeSenceFrameNumFrom + ".jpg", radialBlur);
+        changeSenceFrameNumFrom++;
+        //(2)放大后径向模糊图片
+        Mat bigImamge = new Mat();
+        Imgproc.resize(image, bigImamge, new Size(image.cols() * 1.25, image.rows() * 1.25));
+        Mat destBigImamge = ImageUtils.cutFromCenter(bigImamge, image.width(), image.height());
+        Mat radialBlurDestBigImamge = ImageUtils.radialBlur(destBigImamge);
+        Imgcodecs.imwrite(targetPath + changeSenceFrameNumFrom + ".jpg", radialBlurDestBigImamge);
+        changeSenceFrameNumFrom++;
+        //(3)缩小之后重复平铺加径向模糊
+        Mat smallImage = new Mat();
+        Mat halfImage = new Mat();
+        Mat wholeImage = new Mat();
+        Imgproc.resize(image, smallImage, new Size(image.cols() / 2, image.rows() / 2));
+        ImageUtils.hconcat(smallImage, smallImage, halfImage);
+        ImageUtils.vconcat(halfImage, halfImage, wholeImage);
+        wholeImage = ImageUtils.radialBlur(wholeImage);
+        Imgcodecs.imwrite(targetPath + changeSenceFrameNumFrom + ".jpg", wholeImage);
+        changeSenceFrameNumFrom++;
+        //复制填充视频无变化图片
+//        for(int i=changeSenceFrameNumFrom;i<100000;i++){
+//            int checkNum = i-3-srcPhoneFrameNumFrom+1;
+//            String fillImagePath = fillPath+checkNum+".jpg";
+//            File file = new File(fillImagePath);
+//            if(file.exists()){
+//                Mat srcMat = Imgcodecs.imread(fillImagePath);
+//                Imgcodecs.imwrite(targetPath+i+".jpg",srcMat);
+//            }else{
+//                break;
+//            }
+//        }
+    }
+
+}

+ 10 - 14
jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/VideoProcessing.java

@@ -1,4 +1,4 @@
-/*
+
 package org.jeecg.modules.demo.opencv;
 
 import org.bytedeco.javacv.FFmpegFrameGrabber;
@@ -9,24 +9,21 @@ import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
 import java.io.File;
 
-*/
 /**
  * 视频截帧处理
- *//*
-
+ */
 public class VideoProcessing {
     public static String videoPath = "D:/data";
 
     //存放截取视频某一帧的图片
     public static String videoFramesPath = "D:/data/images/";
 
-    */
-/**
+    /**
      * 将视频文件帧处理并以“jpg”格式进行存储。
      * 依赖FrameToBufferedImage方法:将frame转换为bufferedImage对象
      *
      * @param videoFileName
-     *//*
+     */
 
     public static String grabberVideoFramer(String videoFileName) {
         //最后获取到的视频的图片的路径
@@ -36,10 +33,10 @@ public class VideoProcessing {
         //标识
         int flag = 0;
         try {
-			 */
-/*
+
+            /*
             获取视频文件
-            *//*
+            */
 
             FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(videoPath + "/" + videoFileName);
             fFmpegFrameGrabber.start();
@@ -49,10 +46,10 @@ public class VideoProcessing {
 
             while (flag <= ftp) {
                 frame = fFmpegFrameGrabber.grabImage();
-				*/
-/*
+
+                /*
 				对视频的第五帧进行处理
-				 *//*
+				 */
 
                 if (frame != null) {
                     //文件绝对路径+名字
@@ -84,4 +81,3 @@ public class VideoProcessing {
         grabberVideoFramer(videoFileName);
     }
 }
-*/

+ 23 - 23
jeecg-boot-module-system/src/main/java/org/jeecg/modules/excelutil/entity/YdPlanAggregateEntity.java

@@ -37,13 +37,13 @@ public class YdPlanAggregateEntity extends BaseRowModel {
      * 展示
      */
     @ExcelProperty(index = 5, value = "展示")
-    private String show;
+    private String showNum;
 
     /**
      * 点击
      */
     @ExcelProperty(index = 6, value = "点击")
-    private String click;
+    private String clickNum;
 
     /**
      * 点击率(%)
@@ -67,7 +67,7 @@ public class YdPlanAggregateEntity extends BaseRowModel {
      * 转化数
      */
     @ExcelProperty(index = 10, value = "转化数")
-    private String convert;
+    private String convertNum;
 
     /**
      * 转化成本
@@ -125,22 +125,6 @@ public class YdPlanAggregateEntity extends BaseRowModel {
         this.totalCost = totalCost;
     }
 
-    public String getShow() {
-        return show;
-    }
-
-    public void setShow(String show) {
-        this.show = show;
-    }
-
-    public String getClick() {
-        return click;
-    }
-
-    public void setClick(String click) {
-        this.click = click;
-    }
-
     public String getClickRate() {
         return clickRate;
     }
@@ -165,12 +149,28 @@ public class YdPlanAggregateEntity extends BaseRowModel {
         this.ctr = ctr;
     }
 
-    public String getConvert() {
-        return convert;
+    public String getShowNum() {
+        return showNum;
+    }
+
+    public void setShowNum(String showNum) {
+        this.showNum = showNum;
+    }
+
+    public String getClickNum() {
+        return clickNum;
+    }
+
+    public void setClickNum(String clickNum) {
+        this.clickNum = clickNum;
+    }
+
+    public String getConvertNum() {
+        return convertNum;
     }
 
-    public void setConvert(String convert) {
-        this.convert = convert;
+    public void setConvertNum(String convertNum) {
+        this.convertNum = convertNum;
     }
 
     public String getConvertPrice() {

+ 10 - 1
jeecg-boot-module-system/src/test/java/org/jeecg/SampleTest.java

@@ -278,11 +278,20 @@ public class SampleTest {
     @Autowired
     private IPerformanceSaleService performanceSaleService;
 
+    @Autowired
+    private IKuaiShouHistoryReportTaskService historyReportTaskService;
 
     @Test
-    public void suZhao() {
+    public void testLoadData() throws Exception {
+        CtopOauthToken token = tokenService.getTokenByAccountId(5473041L);
+        String endDateStr = DateUtils.getDate("yyyy-MM-dd");
+        String startDate = DateUtils.addMonth(endDateStr, -6);
 
+        historyReportTaskService.createTask(token.getAccountId(), token.getAccessToken(), startDate, endDateStr, CtopAdConstant.KUAISHOU_LOAD_JOB_TYPE_HISTORY);
+    }
 
+    @Test
+    public void suZhao() {
         Long accountId = 3917130L;
         String token = "0a42e23921e486108105263e75561404";
         kuaishouInterfaceService.getVideoList("e91c778d7de1bd0e9d8f3213d1e0e57c",3820093L, null,null,1);

+ 2 - 2
performance-appraisal/src/main/java/cn/com/ctop/performanceappraisal/mapper/PerformanceMapper.java

@@ -42,7 +42,7 @@ public interface PerformanceMapper extends BaseMapper<Performance> {
 
     BigDecimal getKuaishouSeasonTotalCost(@Param(value = "startDate") String startDate, @Param(value = "endDate") String endDate);
 
-    BigDecimal getKuaishouSalesSeasonTotalCostByParams(@Param(value = "startDate") String startDate, @Param(value = "endDate") String endDate, @Param(value = "saleId") String saleId, @Param(value = "advertiserId") String advertiserId);
+    BigDecimal getKuaishouSalesSeasonTotalCostByParams(@Param(value = "startDate") String startDate, @Param(value = "endDate") String endDate, @Param(value = "saleId") String saleId, @Param(value = "advertiserId") String advertiserId, @Param(value = "accountId") Long accountId);
 
-    BigDecimal getBytedanceSalesSeasonTotalCostByParams(@Param(value = "startDate") String startDate, @Param(value = "endDate") String endDate, @Param(value = "saleId") String saleId, @Param(value = "advertiserId") String advertiserId);
+    BigDecimal getBytedanceSalesSeasonTotalCostByParams(@Param(value = "startDate") String startDate, @Param(value = "endDate") String endDate, @Param(value = "saleId") String saleId, @Param(value = "advertiserId") String advertiserId, @Param(value = "accountId") Long accountId);
 }

+ 6 - 0
performance-appraisal/src/main/java/cn/com/ctop/performanceappraisal/mapper/xml/PerformanceMapper.xml

@@ -347,6 +347,9 @@
         <if test="advertiserId != null">
             and advertiser.id = #{advertiserId}
         </if>
+        <if test="accountId != null">
+            and allocation.account_id = #{accountId}
+        </if>
         AND
         daily.stat_datetime &gt;= #{startDate}
         AND
@@ -369,6 +372,9 @@
         <if test="advertiserId != null">
             and advertiser.id = #{advertiserId}
         </if>
+        <if test="accountId != null">
+            and allocation.account_id = #{accountId}
+        </if>
         AND
         daily.stat_date &gt;= #{startDate}
         AND

+ 3 - 3
performance-appraisal/src/main/java/cn/com/ctop/performanceappraisal/service/IPerformanceService.java

@@ -40,9 +40,9 @@ public interface IPerformanceService extends IService<Performance> {
 
     BigDecimal getKuaishouSeasonTotalCost(String startDate, String endDate);
 
-    BigDecimal getKuaishouSalesSeasonTotalCostByParams(String startDate, String endDate, String salesId, String advertiserId);
+    BigDecimal getKuaishouSalesSeasonTotalCostByParams(String startDate, String endDate, String salesId, String advertiserId, Long accountId);
 
-    BigDecimal getBytedanceSalesSeasonTotalCostByParams(String startDate, String endDate, String saledId, String advertiserId);
+    BigDecimal getBytedanceSalesSeasonTotalCostByParams(String startDate, String endDate, String saledId, String advertiserId, Long accountId);
 
-    BigDecimal getSalesSeasonTotalCostByParams(String startDate, String endDate, String saledId, String advertiserId, String mediaType);
+    BigDecimal getSalesSeasonTotalCostByParams(String startDate, String endDate, String saledId, String advertiserId, Long accountId, String mediaType);
 }

+ 7 - 7
performance-appraisal/src/main/java/cn/com/ctop/performanceappraisal/service/impl/PerformanceServiceImpl.java

@@ -184,8 +184,8 @@ public class PerformanceServiceImpl extends ServiceImpl<PerformanceMapper, Perfo
     }
 
     @Override
-    public BigDecimal getKuaishouSalesSeasonTotalCostByParams(String startDate, String endDate, String salesId, String advertiserId) {
-        BigDecimal cost = performanceMapper.getKuaishouSalesSeasonTotalCostByParams(startDate, endDate, salesId, advertiserId);
+    public BigDecimal getKuaishouSalesSeasonTotalCostByParams(String startDate, String endDate, String salesId, String advertiserId, Long accountId) {
+        BigDecimal cost = performanceMapper.getKuaishouSalesSeasonTotalCostByParams(startDate, endDate, salesId, advertiserId, accountId);
         if (null == cost) {
             return BigDecimal.ZERO;
         } else {
@@ -194,8 +194,8 @@ public class PerformanceServiceImpl extends ServiceImpl<PerformanceMapper, Perfo
     }
 
     @Override
-    public BigDecimal getBytedanceSalesSeasonTotalCostByParams(String startDate, String endDate, String salesId, String advertiserId) {
-        BigDecimal cost = performanceMapper.getBytedanceSalesSeasonTotalCostByParams(startDate, endDate, salesId, advertiserId);
+    public BigDecimal getBytedanceSalesSeasonTotalCostByParams(String startDate, String endDate, String salesId, String advertiserId, Long accountId) {
+        BigDecimal cost = performanceMapper.getBytedanceSalesSeasonTotalCostByParams(startDate, endDate, salesId, advertiserId, accountId);
         if (null == cost) {
             return BigDecimal.ZERO;
         } else {
@@ -204,12 +204,12 @@ public class PerformanceServiceImpl extends ServiceImpl<PerformanceMapper, Perfo
     }
 
     @Override
-    public BigDecimal getSalesSeasonTotalCostByParams(String startDate, String endDate, String saledId, String advertiserId, String mediaType) {
+    public BigDecimal getSalesSeasonTotalCostByParams(String startDate, String endDate, String saledId, String advertiserId, Long accountId, String mediaType) {
         BigDecimal cost;
         if (null != mediaType && mediaType.equals(CtopAdConstant.PLATFORM_TYPE_BYTEDANCE)) {
-            cost = performanceMapper.getKuaishouSalesSeasonTotalCostByParams(startDate, endDate, saledId, advertiserId);
+            cost = performanceMapper.getBytedanceSalesSeasonTotalCostByParams(startDate, endDate, saledId, advertiserId, accountId);
         } else {
-            cost = performanceMapper.getBytedanceSalesSeasonTotalCostByParams(startDate, endDate, saledId, advertiserId);
+            cost = performanceMapper.getKuaishouSalesSeasonTotalCostByParams(startDate, endDate, saledId, advertiserId, accountId);
         }
         if (null == cost) {
             return BigDecimal.ZERO;