|
@@ -1,11 +1,15 @@
|
|
|
package com.qs.mp.admin.service.impl;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.qs.mp.admin.domain.Coupon;
|
|
|
import com.qs.mp.admin.domain.Goods;
|
|
|
+import com.qs.mp.admin.domain.Ticket;
|
|
|
import com.qs.mp.admin.domain.TicketAwards;
|
|
|
import com.qs.mp.admin.domain.TicketAwardsPrize;
|
|
|
import com.qs.mp.admin.domain.TicketBox;
|
|
|
+import com.qs.mp.admin.domain.TicketPackage;
|
|
|
+import com.qs.mp.admin.domain.dto.TicketDrawNumDTO;
|
|
|
import com.qs.mp.admin.domain.param.TicketAwardsParam;
|
|
|
import com.qs.mp.admin.domain.param.TicketAwardsPrizeParam;
|
|
|
import com.qs.mp.admin.domain.param.TicketBoxCreateParam;
|
|
@@ -16,22 +20,31 @@ import com.qs.mp.admin.service.ITicketAwardsPrizeService;
|
|
|
import com.qs.mp.admin.service.ITicketAwardsService;
|
|
|
import com.qs.mp.admin.service.ITicketBoxSerialService;
|
|
|
import com.qs.mp.admin.service.ITicketBoxService;
|
|
|
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.qs.mp.admin.service.ITicketPackageService;
|
|
|
+import com.qs.mp.admin.service.ITicketService;
|
|
|
import com.qs.mp.common.enums.TicketBoxStatusEnum;
|
|
|
+import com.qs.mp.common.enums.TicketPkgStatusEnum;
|
|
|
import com.qs.mp.common.enums.TicketPrizeTypeEnum;
|
|
|
+import com.qs.mp.common.enums.TicketStatusEnum;
|
|
|
import com.qs.mp.common.enums.TicketTypeEnum;
|
|
|
-import com.qs.mp.common.utils.LogUtil;
|
|
|
import com.qs.mp.system.service.id.BizIdGenerator;
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
+import java.text.DecimalFormat;
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Iterator;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Random;
|
|
|
+import lombok.Data;
|
|
|
import ma.glasnost.orika.MapperFacade;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.util.Assert;
|
|
|
|
|
|
/**
|
|
|
* <p>
|
|
@@ -42,7 +55,8 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
* @since 2022-03-02
|
|
|
*/
|
|
|
@Service
|
|
|
-public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox> implements ITicketBoxService {
|
|
|
+public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox> implements
|
|
|
+ ITicketBoxService {
|
|
|
|
|
|
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
|
|
|
|
@@ -67,6 +81,12 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
|
|
|
@Autowired
|
|
|
private ITicketBoxSerialService ticketBoxSerialService;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private ITicketService ticketService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ITicketPackageService ticketPackageService;
|
|
|
+
|
|
|
@Override
|
|
|
@Transactional
|
|
|
public boolean createTicketBox(TicketBoxCreateParam param) {
|
|
@@ -87,7 +107,8 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
|
|
|
TicketAwards ticketAwards = mapperFacade.map(awardsParam, TicketAwards.class);
|
|
|
ticketAwards.setAwardsId(bizIdGenerator.newId());
|
|
|
ticketAwards.setBoxId(ticketBox.getBoxId());
|
|
|
- BigDecimal hitRate = new BigDecimal(awardsParam.getQuantity()).divide(new BigDecimal(ticketBox.getQuantity()), 4, RoundingMode.DOWN);
|
|
|
+ BigDecimal hitRate = new BigDecimal(awardsParam.getQuantity()).divide(
|
|
|
+ new BigDecimal(ticketBox.getQuantity()), 4, RoundingMode.DOWN);
|
|
|
ticketAwards.setHitRate(hitRate);
|
|
|
ticketAwardsList.add(ticketAwards);
|
|
|
|
|
@@ -118,8 +139,204 @@ public class TicketBoxServiceImpl extends ServiceImpl<TicketBoxMapper, TicketBox
|
|
|
ticketAwardsService.saveBatch(ticketAwardsList);
|
|
|
ticketAwardsPrizeService.saveBatch(awardsPrizeList);
|
|
|
|
|
|
- // TODO 分包,生成券
|
|
|
+ // 线下票要分包
|
|
|
+ if (ticketBox.getType() == TicketTypeEnum.OFFLINE) {
|
|
|
+ int pkgNum = ticketBox.getPkgQty();
|
|
|
+ int pkgUnit = ticketBox.getPkgUnit();
|
|
|
+ // 1.把各奖级的中奖数量分摊到每包上
|
|
|
+ Map<Integer, List<PkgAwards>> pkgAwardsMap = new HashMap<>();
|
|
|
+ for (int k = 0; k < ticketAwardsList.size(); k++) {
|
|
|
+ TicketAwards ticketAwards = ticketAwardsList.get(k);
|
|
|
+ if (ticketAwards.getQuantity() < pkgNum) {
|
|
|
+ // 奖级数量少于包数的,随机不重复分配,随机数从1开始
|
|
|
+ List<Integer> randomList = getRandomList(ticketAwards.getQuantity(), pkgNum);
|
|
|
+ for (Integer pkgId : randomList) {
|
|
|
+ if (null == pkgAwardsMap.get(pkgId)) {
|
|
|
+ pkgAwardsMap.put(pkgId, new ArrayList<PkgAwards>());
|
|
|
+ }
|
|
|
+ pkgAwardsMap.get(pkgId).add(
|
|
|
+ new PkgAwards(ticketAwards.getAwardsId(), ticketAwards.getName(),
|
|
|
+ ticketAwards.getSort(), ticketAwards.getQuantity()));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 奖级数量大于包数的,平均分配,四舍五入
|
|
|
+ int remainQty = ticketAwards.getQuantity();
|
|
|
+ for (int i = 1; i <= pkgNum; i++) {
|
|
|
+ int quantity;
|
|
|
+ if (null == pkgAwardsMap.get(i)) {
|
|
|
+ pkgAwardsMap.put(i, new ArrayList<PkgAwards>());
|
|
|
+ }
|
|
|
+ if (k == ticketAwardsList.size() - 1) {
|
|
|
+ // 最后一个奖项直接分配奖级数量差额即可
|
|
|
+ int hasQty = pkgAwardsMap.get(i).stream().mapToInt(PkgAwards::getQuantity).sum();
|
|
|
+ quantity = pkgUnit - hasQty;
|
|
|
+ } else {
|
|
|
+ if (i == pkgNum) {
|
|
|
+ quantity = remainQty;
|
|
|
+ } else {
|
|
|
+ quantity = new BigDecimal(remainQty).divide(new BigDecimal(pkgNum - i + 1), 0,
|
|
|
+ RoundingMode.HALF_UP).intValue();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ remainQty -= quantity;
|
|
|
+ Assert.isTrue(remainQty >= 0, "剩余奖级数量不足分配。boxId:" + ticketBox.getBoxId());
|
|
|
+ pkgAwardsMap.get(i).add(
|
|
|
+ new PkgAwards(ticketAwards.getAwardsId(), ticketAwards.getName(),
|
|
|
+ ticketAwards.getSort(), quantity));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ // 生成票包记录和盲票记录
|
|
|
+ int pkgCnt = 0;
|
|
|
+ int ticketCnt = 0;
|
|
|
+ List<TicketPackage> ticketPackageList = new ArrayList<>();
|
|
|
+ for (Integer key : pkgAwardsMap.keySet()) {
|
|
|
+ pkgCnt += 1;
|
|
|
+ TicketPackage ticketPackage = new TicketPackage();
|
|
|
+ ticketPackage.setPkgId(bizIdGenerator.newId());
|
|
|
+ ticketPackage.setBoxId(ticketBox.getBoxId());
|
|
|
+ ticketPackage.setPkgNo(ticketBox.getBoxNo() + "-" + String.format("%1$04d", pkgCnt));
|
|
|
+ ticketPackage.setStartSn(
|
|
|
+ ticketPackage.getPkgNo() + "-" + String.format("%1$07d", ticketCnt + 1));
|
|
|
+ ticketPackage.setEndSn(
|
|
|
+ ticketPackage.getPkgNo() + "-" + String.format("%1$07d", ticketCnt + 200));
|
|
|
+ ticketPackage.setStatus(TicketPkgStatusEnum.FOR_SALE);
|
|
|
+ ticketPackageList.add(ticketPackage);
|
|
|
+
|
|
|
+ List<PkgAwards> pkgAwardsList = pkgAwardsMap.get(key);
|
|
|
+ List<Ticket> ticketList = new ArrayList<>();
|
|
|
+ for (int j = 1; j <= pkgUnit; j++) {
|
|
|
+ ticketCnt += 1;
|
|
|
+ Iterator<PkgAwards> iterator = pkgAwardsList.iterator();
|
|
|
+ while (iterator.hasNext()) {
|
|
|
+ PkgAwards next = iterator.next();
|
|
|
+ if (next.getQuantity() == 0) {
|
|
|
+ iterator.remove();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ int random = getPrizeIndex(pkgAwardsList);
|
|
|
+ PkgAwards pkgAwards = pkgAwardsList.get(random);
|
|
|
+ pkgAwards.setQuantity(pkgAwards.getQuantity() - 1);
|
|
|
+
|
|
|
+ Ticket ticket = new Ticket();
|
|
|
+ ticket.setTicketId(bizIdGenerator.newId());
|
|
|
+ ticket.setBoxId(ticketBox.getBoxId());
|
|
|
+ ticket.setPkgId(ticketPackage.getPkgId());
|
|
|
+ ticket.setTitle(ticketBox.getTitle());
|
|
|
+ ticket.setSerialNo(ticketPackage.getPkgNo() + "-" + String.format("%1$07d", ticketCnt));
|
|
|
+ ticket.setFacePrice(ticketBox.getFacePrice());
|
|
|
+ int luckyNum = new Random().nextInt(18);
|
|
|
+ ticket.setCipherLuckyNum(String.valueOf(luckyNum));
|
|
|
+ List<TicketDrawNumDTO> drawNumDTOList = new ArrayList<>();
|
|
|
+ for (int i = 1; i <= 18; i++) {
|
|
|
+ if (i == luckyNum) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ TicketDrawNumDTO drawNumDTO = new TicketDrawNumDTO(pkgAwards.getName(), i);
|
|
|
+ drawNumDTOList.add(drawNumDTO);
|
|
|
+ }
|
|
|
+ ticket.setDrawNum(JSONObject.toJSONString(drawNumDTOList));
|
|
|
+ ticket.setIsPhysical(1);
|
|
|
+ ticket.setStatus(TicketStatusEnum.NOT_PAY);
|
|
|
+ ticketList.add(ticket);
|
|
|
+ }
|
|
|
+ ticketService.saveBatch(ticketList);
|
|
|
+ }
|
|
|
+ ticketPackageService.saveBatch(ticketPackageList);
|
|
|
+ } else {
|
|
|
+ // TODO 线上票,不用分包
|
|
|
+
|
|
|
+ }
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据Math.random()产生一个double型的随机数,判断每个奖品出现的概率
|
|
|
+ *
|
|
|
+ * @param prizes
|
|
|
+ * @return random:奖品列表prizes中的序列(prizes中的第random个就是抽中的奖品)
|
|
|
+ */
|
|
|
+ public int getPrizeIndex(List<PkgAwards> prizes) {
|
|
|
+ DecimalFormat df = new DecimalFormat("######0.00");
|
|
|
+ int random = -1;
|
|
|
+
|
|
|
+ //计算总权重
|
|
|
+ double sumWeight = 0;
|
|
|
+ for (PkgAwards p : prizes) {
|
|
|
+ sumWeight += p.getQuantity();
|
|
|
+ }
|
|
|
+
|
|
|
+ //产生随机数
|
|
|
+ double randomNumber;
|
|
|
+ randomNumber = Math.random();
|
|
|
+
|
|
|
+ //根据随机数在所有奖品分布的区域并确定所抽奖品
|
|
|
+ double d1 = 0;
|
|
|
+ double d2 = 0;
|
|
|
+ for (int i = 0; i < prizes.size(); i++) {
|
|
|
+ d2 += Double.parseDouble(String.valueOf(prizes.get(i).getQuantity())) / sumWeight;
|
|
|
+ if (i == 0) {
|
|
|
+ d1 = 0;
|
|
|
+ } else {
|
|
|
+ d1 += Double.parseDouble(String.valueOf(prizes.get(i - 1).getQuantity())) / sumWeight;
|
|
|
+ }
|
|
|
+ if (randomNumber > d1 && randomNumber <= d2) {
|
|
|
+ random = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return random;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从total中随机取n个不重复的数
|
|
|
+ *
|
|
|
+ * @param n
|
|
|
+ * @param total
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<Integer> getRandomList(int n, int total) {
|
|
|
+ List<Integer> randomList = new ArrayList<>();
|
|
|
+ Random rand = new Random();
|
|
|
+ boolean[] bool = new boolean[total];
|
|
|
+ int randInt = 0;
|
|
|
+ for (int i = 0; i < n; i++) {
|
|
|
+ do {
|
|
|
+ randInt = rand.nextInt(total);
|
|
|
+ } while (bool[randInt]);
|
|
|
+ bool[randInt] = true;
|
|
|
+ randomList.add(randInt);
|
|
|
+ }
|
|
|
+ return randomList;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Data
|
|
|
+ private class PkgAwards {
|
|
|
+
|
|
|
+ private String awardsId;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 奖项名
|
|
|
+ */
|
|
|
+ private String name;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 奖项顺序
|
|
|
+ */
|
|
|
+ private String sort;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 奖项数量
|
|
|
+ */
|
|
|
+ private Integer quantity;
|
|
|
+
|
|
|
+ PkgAwards(String awardsId, String name, String sort, Integer quantity) {
|
|
|
+ this.awardsId = awardsId;
|
|
|
+ this.name = name;
|
|
|
+ this.sort = sort;
|
|
|
+ this.quantity = quantity;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|