Răsfoiți Sursa

票组中奖率检查

chunping 3 ani în urmă
părinte
comite
228752e93a

+ 10 - 0
mp-admin/src/test/java/com/qs/mp/service/ServiceImplTest.java

@@ -3,6 +3,7 @@ package com.qs.mp.service;
 import com.qs.mp.MpApplication;
 import com.qs.mp.admin.service.ITicketBoxSerialService;
 import com.qs.mp.framework.service.IWxUrlLinkService;
+import com.qs.mp.quartz.task.TicketBoxTask;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -30,6 +31,9 @@ public class ServiceImplTest {
   @Autowired
   private ITicketBoxSerialService ticketBoxSerialService;
 
+  @Autowired
+  private TicketBoxTask ticketBoxTask;
+
   @Test
   public void testGenerateQrCode() {
     System.out.println(wxUrlLinkService.generateCode("pages/index/index", "id=1", "wx8533800e393dbd6b"));
@@ -55,6 +59,12 @@ public class ServiceImplTest {
   }
 
 
+  @Test
+  public void testCheckTicketBox() {
+    ticketBoxTask.checkPrize("954112676047486977");
+
+  }
+
 
   public static void main(String[] args) {
     /*int n = 500;

+ 164 - 0
mp-quartz/src/main/java/com/qs/mp/quartz/task/TicketBoxTask.java

@@ -0,0 +1,164 @@
+package com.qs.mp.quartz.task;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qs.mp.admin.domain.Ticket;
+import com.qs.mp.admin.domain.TicketAwards;
+import com.qs.mp.admin.domain.TicketBox;
+import com.qs.mp.admin.service.ITicketAwardsService;
+import com.qs.mp.admin.service.ITicketBoxService;
+import com.qs.mp.admin.service.ITicketService;
+import com.qs.mp.common.annotation.Log;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.enums.TicketTypeEnum;
+import com.qs.mp.common.enums.UserTicketOrderStatusEnum;
+import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.common.utils.RSAUtil;
+import com.qs.mp.user.domain.UserTicketOrder;
+import com.qs.mp.user.service.IUserTicketOrderService;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+
+/**
+ * 检查票组出奖率
+ * @author zhongcp
+ * @Date 2022/3/17
+ */
+@Component("ticketBoxTask")
+public class TicketBoxTask {
+
+  protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
+  @Autowired
+  private ITicketService ticketService;
+
+  @Autowired
+  private ITicketAwardsService ticketAwardsService;
+
+  @Autowired
+  private ITicketBoxService ticketBoxService;
+
+  private final int PAGE_SIZE = 100;
+
+  /**
+   * 检查票组中奖分布任务
+   */
+  public void checkPrize(String boxId) {
+    LogUtil.info(logger, "...票组奖品分布检测任务开始...");
+
+    TicketBox ticketBox = ticketBoxService.getById(boxId);
+    List<TicketAwards> ticketAwardsList = ticketAwardsService.list(new LambdaQueryWrapper<TicketAwards>().eq(TicketAwards::getBoxId, boxId));
+    Map<String, TicketAwards> ticketAwardsMap = new HashMap<>();
+    for (TicketAwards ticketAward : ticketAwardsList) {
+      ticketAwardsMap.put(ticketAward.getName(), ticketAward);
+    }
+
+    List<Ticket> listAll = new ArrayList<Ticket>();
+    // 首先查询要导出的数据总数
+    LambdaQueryWrapper<Ticket> queryWrapper = new LambdaQueryWrapper<Ticket>();
+    queryWrapper.eq(Ticket::getBoxId, boxId);
+    int totalSize = ticketService.count(queryWrapper);
+    if (totalSize == 0) {
+      LogUtil.info(logger, "票组票数为0,boxId:{0}", boxId);
+    }
+
+    if(totalSize > PAGE_SIZE) {
+      int totalPage = totalSize%PAGE_SIZE == 0 ? totalSize/PAGE_SIZE : totalSize/PAGE_SIZE+1;
+      for (int i = 0; i < totalPage; i++) {
+        LambdaQueryWrapper<Ticket> pageQueryWrapper = new LambdaQueryWrapper<Ticket>();
+        pageQueryWrapper.select(Ticket::getSerialNo, Ticket::getDrawNum, Ticket::getCipherLuckyNum, Ticket::getPkgId);
+        pageQueryWrapper.eq(Ticket::getBoxId, boxId);
+        pageQueryWrapper.last("limit "+ (i*PAGE_SIZE) +", " + PAGE_SIZE);
+        List<Ticket> list = ticketService.list(pageQueryWrapper);
+        if(null != list && list.size() > 0 ) {
+          listAll.addAll(list);
+        }
+      }
+    }else {
+      listAll = ticketService.list(queryWrapper);
+    }
+
+    HashMap<String, HashMap<String, Integer>> pkgAwardsMap = new HashMap<>();
+    if(null != listAll && listAll.size() > 0 ) {
+      listAll.sort(Comparator.comparing(Ticket::getSerialNo));
+      for (Ticket ticket : listAll) {
+        JSONArray jsonArray = JSONArray.parseArray(ticket.getDrawNum());
+        for (int i = 0; i < jsonArray.size(); i++) {
+          JSONObject jo = jsonArray.getJSONObject(i);
+          String luckyNum = RSAUtil.decrypt(ticket.getCipherLuckyNum());
+//          LogUtil.info(logger, "num:{0},luckyNum:{1}", new Object[]{jo.get("num"), luckyNum});
+          if (jo.get("num") == Integer.valueOf(luckyNum)) {
+            HashMap<String, Integer> awardsMap = pkgAwardsMap.get(ticket.getPkgId());
+            if (awardsMap == null) {
+              awardsMap = new HashMap<>();
+              pkgAwardsMap.put(ticket.getPkgId(), awardsMap);
+            }
+            Integer awardsNum = awardsMap.get(jo.getString("name"));
+            if (null == awardsNum) {
+              awardsNum = 0;
+            }
+            awardsNum += 1;
+            awardsMap.put(jo.getString("name"), awardsNum);
+          }
+        }
+      }
+    }
+    LogUtil.info(logger, "票包奖品分布:{0}", JSONObject.toJSONString(pkgAwardsMap));
+    // 奖级累计中奖数量
+    Map<String, Integer> totalAwardsMap = new HashMap<>();
+    for (String key : pkgAwardsMap.keySet()) {
+      HashMap<String, Integer> awardsMap = pkgAwardsMap.get(key);
+
+      int sumAwardsNum = 0;
+      for (String subKey : awardsMap.keySet()) {
+        sumAwardsNum += awardsMap.get(subKey);
+        Integer totalAwardsNum = totalAwardsMap.get(subKey);
+        if (totalAwardsNum == null) {
+          totalAwardsNum = 0;
+        }
+        totalAwardsNum += awardsMap.get(subKey);
+        totalAwardsMap.put(subKey, totalAwardsNum);
+      }
+      Assert.isTrue(sumAwardsNum == ticketBox.getPkgUnit(), "票包的中奖数和票包张数不匹配。总中奖数:" + sumAwardsNum + ",票包张数:" + ticketBox.getPkgUnit());
+      // 检查票包每个奖项的中奖率是否和整体票组中奖率一致
+      for (String subKey : awardsMap.keySet()) {
+        BigDecimal hitRate = new BigDecimal(awardsMap.get(subKey) * 100).divide(new BigDecimal(sumAwardsNum), 4, RoundingMode.DOWN);
+        // 误差率
+        BigDecimal misRate = ticketAwardsMap.get(subKey).getHitRate().subtract(hitRate).divide(hitRate, 2, RoundingMode.HALF_UP);
+        if (misRate.abs().compareTo(new BigDecimal(0.01)) > 0) {
+          LogUtil.error(logger, "中奖率与整个票组的中奖率误差大于0.01,pkgId:{0},票包奖项:{1},数量:{2},票包中奖率:{3},票组中奖率:{4}",
+              new Object[]{key, subKey, awardsMap.get(subKey), hitRate, ticketAwardsMap.get(subKey).getHitRate()});
+        }
+      }
+      Map<String, Integer> treeMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2));
+      treeMap.putAll(awardsMap);
+      LogUtil.info(logger, "票包{0}奖级分布情况:{1}", new Object[]{key, treeMap});
+    }
+    // 排序
+    Map<String, Integer> resultMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2));
+    resultMap.putAll(totalAwardsMap);
+    for (String key : resultMap.keySet()) {
+      int realNum = resultMap.get(key);
+      LogUtil.info(logger, "奖级{0}数量为{1}", new Object[]{key, realNum});
+      if(realNum != ticketAwardsMap.get(key).getQuantity()) {
+        LogUtil.error(logger, "实际中奖数(" + realNum + ")和票组中奖数(" + ticketAwardsMap.get(key).getQuantity() + ")不等" );
+      }
+    }
+    LogUtil.info(logger, "...票组奖品分布检测任务结束...");
+  }
+}