peng
23 小时以前 6c3c5f3fb28cc65684e065b60a09768cf8a77429
framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeServiceImpl.java
@@ -5,25 +5,36 @@
import cn.lili.common.properties.RocketmqCustomProperties;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.BeanUtil;
import cn.lili.common.utils.StringUtils;
import cn.lili.modules.lmk.domain.entity.*;
import cn.lili.modules.lmk.domain.form.AddPrizeNumForm;
import cn.lili.modules.lmk.domain.query.PrizeRecordTimeQuery;
import cn.lili.modules.lmk.domain.vo.PrizeDetailVO;
import cn.lili.modules.lmk.domain.vo.PrizeProbabilityVO;
import cn.lili.modules.lmk.domain.vo.PrizeRecordTimeVO;
import cn.lili.modules.lmk.domain.vo.PrizeResultVO;
import cn.lili.modules.lmk.enums.general.*;
import cn.lili.modules.lmk.service.*;
import cn.lili.modules.order.order.entity.dos.Order;
import cn.lili.modules.order.order.service.OrderService;
import cn.lili.modules.promotion.entity.dos.Coupon;
import cn.lili.modules.promotion.service.CouponService;
import cn.lili.mybatis.BaseEntity;
import cn.lili.rocketmq.RocketmqSendCallbackBuilder;
import cn.lili.rocketmq.tags.CommentTagsEnum;
import cn.lili.utils.COSUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -37,10 +48,10 @@
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class PrizeServiceImpl implements PrizeService {
@@ -51,10 +62,19 @@
    private final PrizeRecordService prizeRecordService;
    private static final String PRIZE_PREFIX = "prize_draw:";
    private static final String PRIZE_NUMBER = "prize_number:";
    private static final String PRIZE_ADD_NUM = "prize_add_num:";
    private final RedisTemplate<String, String> redisTemplate;
    private final RedissonClient redissonClient;
    private final RocketmqCustomProperties rocketmqCustomProperties;
    private final RocketMQTemplate rocketMQTemplate;
    private final COSUtil cosUtil;
    private final CouponService couponService;
    private final AddPrizeRuleService addPrizeRuleService;
    private final ActionRecordService actionRecordService;
    private final ShareActionService shareActionService;
    private final AddNumCheekService addNumCheekService;
    private final OrderService orderService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result prize(String prizeId) {
@@ -167,20 +187,20 @@
        refPrizes = activityRefPrizeService.list(prizeRefQuery);
        canPrizeMap = refPrizes.stream().filter(item -> {
            return item.getRemainNum() > 0;
        }).collect(Collectors.toMap(ActivityRefPrize::getPrizeId, Function.identity()));
        }).collect(Collectors.toMap(ActivityRefPrize::getId, Function.identity()));
        prizeRecordTimeQuery = new PrizeRecordTimeQuery();
        prizeRecordTimeQuery.setStartTime(beginTime);
        prizeRecordTimeQuery.setEndTime(endTime);
        prizeRecordTimeQuery.setRecordActivityId(prizeId);
        prizeRecordListByTime = prizeRecordService.getPrizeRecordListByTime(prizeRecordTimeQuery);
        prizeRecordListByTime.stream().filter(item->{
            return item.getPrizeId() != null;
        prizeRecordListByTime.stream().filter(item -> {
            return item.getActivityPrizeRefId() != null;
        }).forEach(item -> {
            ActivityRefPrize activityRefPrize = canPrizeMap.get(Long.parseLong(item.getPrizeId()));
            ActivityRefPrize activityRefPrize = canPrizeMap.get(item.getActivityPrizeRefId());
            if (activityRefPrize != null) {
                //移除当日上限的奖品并且添加到不能抽奖商品中去
                if (activityRefPrize.getMaxPreDay() <= item.getTotal()) {
                    canPrizeMap.remove(Long.parseLong(item.getPrizeId()));
                    canPrizeMap.remove(item.getActivityPrizeRefId());
                }
            }
        });
@@ -204,7 +224,7 @@
        BigDecimal probabilityBegin = BigDecimal.ZERO;
        for (ActivityRefPrize item : refPrizeList) {
            PrizeProbabilityVO prizeProbabilityVO = new PrizeProbabilityVO();
            prizeProbabilityVO.setPrizeId(item.getPrizeId());
            prizeProbabilityVO.setActivityPrizeRefId(item.getId());
            BigDecimal multiply = item.getPrizeProbability().multiply(BigDecimal.valueOf(100));
            BigDecimal[][] position = {{probabilityBegin, multiply.add(probabilityBegin)}};
            prizeProbabilityVO.setProbability(position);
@@ -213,13 +233,44 @@
        }
        BigDecimal max = currentProbability.multiply(BigDecimal.valueOf(100));
        BigDecimal bigDecimal = generateRandom(BigDecimal.ONE, max);
        try {
            log.info("抽奖号码为---------------------------->{}", bigDecimal);
            log.info("抽奖概率集合为------------------------->{}", JSONObject.toJSONString(prizeProbabilityList));
        } catch (Exception e) {
            log.error("打印抽奖信息报错----------------------->", e);
        }
        for (PrizeProbabilityVO prizeProbabilityVO : prizeProbabilityList) {
            BigDecimal minP = prizeProbabilityVO.getProbability()[0][0];
            BigDecimal maxP = prizeProbabilityVO.getProbability()[0][1];
            if (bigDecimal.compareTo(minP) > 0 && bigDecimal.compareTo(maxP) <= 0) {
                prizeWon = prizeProbabilityVO.getPrizeId();
                prizeWon = prizeProbabilityVO.getActivityPrizeRefId();
                break;
            }
        }
        Coupon coupon = null;
        //校验优惠卷是否允许用户多领不允许当未中奖处理
        if (prizeWon != null) {
            ActivityRefPrize activityRefPrize = canPrizeMap.get(prizeWon);
            String prizeDrawId = activityRefPrize.getPrizeId();
            PrizeDraw prizeDraw = prizeDrawService.getById(prizeDrawId);
            String couponId = prizeDraw.getCouponId();
            coupon = couponService.getById(couponId);
            if (coupon == null) {
                prizeWon = null;
            } else {
                Integer couponLimitNum = coupon.getCouponLimitNum();
                //获取用户这个优惠卷的中奖情况
                LambdaQueryWrapper<PrizeRecord> eq = Wrappers.<PrizeRecord>lambdaQuery()
                        .eq(PrizeRecord::getUserId, userId)
                        .eq(PrizeRecord::getPrizeActivityId, prizeId)
                        .eq(PrizeRecord::getPrizeId, prizeDrawId);
                int size = prizeRecordService.list(eq).size();
                if ( couponLimitNum>0 && size >= couponLimitNum) {
                    log.info("触发优惠卷领取限制---------->{}",prizeWon);
                    prizeWon = null;
                }
            }
        }
        //未中奖的情况
        if (prizeWon == null) {
@@ -263,7 +314,7 @@
        if (!update) {
            throw new ServiceException("当前活动太火爆了请稍后再试");
        }
        PrizeDraw prizeDraw = prizeDrawService.getById(prizeWon);
        PrizeDraw prizeDraw = prizeDrawService.getById(activityRefPrize.getPrizeId());
        //写入抽奖记录
        PrizeRecord prizeRecord = new PrizeRecord();
        prizeRecord.setUserId(Long.parseLong(userId));
@@ -277,7 +328,7 @@
        prizeRecord.setPrizeNumId(Long.parseLong(waitUserPrize.getId()));
        prizeRecord.setActivityPrizeRefId(Long.parseLong(activityRefPrize.getId()));
        prizeRecord.setDistributeStatus(PrizeDistributeStatusEnum.WAIT.name());
        prizeRecord.setPrizeId(prizeWon);
        prizeRecord.setPrizeId(activityRefPrize.getPrizeId());
        prizeRecord.setPrizeName(prizeDraw.getPrizeName());
        prizeRecord.setPrizeActivityCover(prizeActivity.getActivityCover());
        prizeRecord.setPrizeImg(prizeDraw.getPrizeImg());
@@ -287,6 +338,7 @@
//        if (!lock.equals(nowLock)) {
//            throw new RuntimeException("当前活动太火爆了请稍后再试");
//        }
        String couponId = coupon.getId();
        // 走mq异步处理
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
@@ -295,7 +347,10 @@
                rocketMQTemplate.asyncSend(destination, JSON.toJSONString(prizeRecord), RocketmqSendCallbackBuilder.commonCallback());
            }
        });
        return Result.ok().data(activityRefPrize);
        PrizeResultVO prizeResultVO = new PrizeResultVO();
        BeanUtils.copyProperties(activityRefPrize, prizeResultVO);
        prizeResultVO.setCouponId(couponId);
        return Result.ok().data(prizeResultVO);
    }
    public static BigDecimal generateRandom(BigDecimal min, BigDecimal max) {
@@ -329,6 +384,13 @@
        if (activity == null) {
            throw new RuntimeException("当前活动不存在");
        }
        Date activityEndtime = activity.getEndTime();
        if (new Date().after(activityEndtime)) {
            throw new ServiceException("当前活动已经结束");
        }
        if (!PrizeActivityStatusEnum.ON.name().equals(activity.getEnableStatus())) {
            throw new ServiceException("活动还没有启用");
        }
        //获取用户抽奖次数
        Integer prizeNum = activity.getPrizeNum();
        //加锁判断添加系统赠送次数
@@ -336,13 +398,26 @@
        try {
            lock.lock();
            prizeNumberList = getPrizeNumberList(prizeId, userId);
            //默认生成
            boolean needGenerate = true;
            for (PrizeNumber prizeNumber : prizeNumberList) {
                String userAction = prizeNumber.getUserAction();
                if (PrizeUserActionEnum.SYSTEM.name().equals(userAction)) {
                    needGenerate = false;
                    break;
                }
            }
            // 当前用户没有初始化抽奖数据需要初始化当天抽奖数据
            if (prizeNumberList == null || prizeNumberList.isEmpty()) {
                //没有默认抽奖次数直接返回0次
            if (prizeNumberList.isEmpty() || needGenerate) {
                //没有默认抽奖次数不生成抽奖次数
                int size = prizeNumberList.size();
                if (prizeNum == null || prizeNum <= 0) {
                    return Result.ok().data(0);
                    return Result.ok().data(size);
                }
                prizeNumberList = new ArrayList<>();
                if (size+prizeNum>activity.getMaxPrize()){
                    prizeNum =  activity.getMaxPrize()-size;
                }
                //设置默认抽奖次数并返回默认抽奖次数
                for (int i = 0; i < prizeNum; i++) {
                    PrizeNumber prizeNumber = new PrizeNumber();
@@ -354,13 +429,9 @@
                }
                //添加抽奖次数并返回
                prizeNumberService.saveBatch(prizeNumberList);
                return Result.ok().data(prizeNumberList.size());
                return Result.ok().data(prizeNumberList.size()+size);
            }
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        Integer maxPrize = activity.getMaxPrize();
        //其他情况
        int useNum = 0;
@@ -376,7 +447,25 @@
        if (useNum >= maxPrize) {
            return Result.ok().data(0);
        } else {
            return Result.ok().data(userPrizeNum>maxPrize?maxPrize-useNum:notUseNum);
            return Result.ok().data(userPrizeNum > maxPrize ? maxPrize - useNum : notUseNum);
        }
        } finally {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    if (lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
                @Override
                public void afterCompletion(int status) {
                    if (lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            });
        }
    }
@@ -408,6 +497,253 @@
    @Override
    public Result prizeInfo(String prizeActivityId) {
        return null;
        if (StringUtils.isBlank(prizeActivityId)) {
            return Result.ok().data(0);
        }
        PrizeDetailVO data = prizeActivityService.prizeInfo(prizeActivityId);
        String activityCover = data.getActivityCover();
        if (StringUtils.isNotBlank(activityCover) && !activityCover.contains("http")) {
            data.setActivityCover(cosUtil.getPreviewUrl(activityCover));
        }
        data.getPrizeInfoVOS().forEach(info -> {
            String prizeImg = info.getPrizeImg();
            String prizeCover = info.getPrizeCover();
            if (StringUtils.isNotBlank(prizeImg) && !prizeImg.contains("http")) {
                info.setPrizeImg(cosUtil.getPreviewUrl(prizeImg));
            }
            if (StringUtils.isNotBlank(prizeCover) && !prizeCover.contains("http")) {
                info.setPrizeCover(cosUtil.getPreviewUrl(prizeCover));
            }
        });
        return Result.ok().data(data);
    }
    @Override
    public Result grantRecord(String prizeActivityId) {
        return prizeDrawService.grantRecord(prizeActivityId);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result addPrizeNum(AddPrizeNumForm addPrizeNumForm) {
        //指定活动给指定活动添加没指定活动给默认活动添加
        String prizeActivityId = addPrizeNumForm.getPrizeActivityId();
        if (StringUtils.isBlank(prizeActivityId)) {
            LambdaQueryWrapper<PrizeActivity> pop = Wrappers.<PrizeActivity>lambdaQuery()
                    .eq(PrizeActivity::getEnableStatus, PrizeActivityStatusEnum.ON.name())
                    .eq(PrizeActivity::getPopup, true);
            PrizeActivity one = prizeActivityService.getOne(pop);
            if (one == null) {
                return Result.ok().data(0);
            }
            addPrizeNumForm.setPrizeActivityId(one.getId());
        }
        AuthUser currentUser = UserContext.getCurrentUser();
        if (currentUser == null) {
            return Result.ok().data(0);
        }
        //指定用户给指定用户添加没指定活动给当前登录用户添加
        if (StringUtils.isBlank(addPrizeNumForm.getUserId())) {
            addPrizeNumForm.setUserId(currentUser.getId());
        }
        String userId = addPrizeNumForm.getUserId();
        RLock lock = redissonClient.getLock(PRIZE_ADD_NUM + userId);
        try {
            lock.lock();
            PrizeActivity activity = prizeActivityService.getById(addPrizeNumForm.getPrizeActivityId());
            if (activity == null) {
                throw new ServiceException("当前活动不存在");
            }
            if (!PrizeActivityStatusEnum.ON.name().equals(activity.getEnableStatus())) {
                throw new ServiceException("当前活动没开启");
            }
            Date date = new Date();
            //活动结束不需要添加
            if (date.after(activity.getEndTime())) {
                throw new ServiceException("当前活动已结束");
            }
            Integer maxPrize = activity.getMaxPrize();
            List<PrizeNumber> prizeNumberList = getPrizeNumberList(activity.getId(), userId);
            if (prizeNumberList.size() >= maxPrize) {
                throw new ServiceException("抽奖次数已达到上限了");
            }
            PrizeUserActionEnum actionEnum = PrizeUserActionEnum.select(addPrizeNumForm.getAddType());
            if (actionEnum == null) {
                throw new ServiceException("当前类型不存在");
            }
            AddPrizeRule addPrizeRule = getAddPrizeRule(actionEnum.name());
            if (addPrizeRule == null) {
                return Result.ok().data(0);
            }
            List<PrizeNumber> needAdd = new ArrayList<>();
            Integer addNum = addPrizeRule.getAddNum();
            if (addNum == null) {
                return Result.ok().data(0);
            }
            //判读添加后是否大于最大次数
            if (prizeNumberList.size() + addNum >= maxPrize) {
                addNum = maxPrize - prizeNumberList.size();
            }
            boolean addFlag = false;
            //判断该类型当天是否添加过了
            for (PrizeNumber prizeNumber : prizeNumberList) {
                if (actionEnum.name().equals(prizeNumber.getUserAction())) {
                    addFlag = true;
                    break;
                }
            }
            String extend = addPrizeNumForm.getExtend();
            JSONObject jsonObject = JSONObject.parseObject(extend);
            LambdaQueryWrapper<AddNumCheek> query = Wrappers.lambdaQuery();
            AddNumCheek addNumCheek = null;
            String orderSn = null;
            Order order = null;
            String ruleValue = null;
            switch (actionEnum) {
                case SHARE_GOODS_VIDEO:
                    String shareId = jsonObject.getString("shareId");
                    ShareAction shareAction = shareActionService.getById(shareId);
                    if (shareAction == null) {
                        return Result.ok().data(0);
                    }
                    if (addFlag) {
                        log.info("当前用户当天已经添加过了分享添加次数了-------->{}", userId);
                        return Result.ok().data(0);
                    }
                    break;
                case SHARE_USER_REGISTRY:
                    String memberId = jsonObject.getString("memberId");
                    query.eq(AddNumCheek::getType, PrizeUserActionEnum.SHARE_USER_REGISTRY.name())
                            .eq(AddNumCheek::getCheckNo, memberId);
                    if (addNumCheekService.getOne(query) != null) {
                        log.info("当前用户已经被邀请过了----------------->{}", memberId);
                        return Result.ok().data(0);
                    }
                    addNumCheek = new AddNumCheek();
                    addNumCheek.setType(PrizeUserActionEnum.SHARE_USER_REGISTRY.name());
                    addNumCheek.setUserId(userId);
                    addNumCheek.setCheckNo(memberId);
                    addNumCheekService.save(addNumCheek);
                    break;
                case SHARE_USER_SHOPPING:
                    orderSn = jsonObject.getString("orderSn");
                    //校验订单是否存在
                    order = orderService.getBySn(orderSn);
                    if (order == null) {
                        log.info("分享用户购物订单不存在{}", orderSn);
                        return Result.ok().data(0);
                    }
                    query.eq(AddNumCheek::getType, PrizeUserActionEnum.SHARE_USER_SHOPPING.name())
                            .eq(AddNumCheek::getCheckNo, orderSn);
                    if (addNumCheekService.getOne(query) != null) {
                        log.info("当前邀请订单已经被领取过了----------------->{}", orderSn);
                        return Result.ok().data(0);
                    }
                    addNumCheek = new AddNumCheek();
                    addNumCheek.setType(PrizeUserActionEnum.SHARE_USER_SHOPPING.name());
                    addNumCheek.setUserId(userId);
                    addNumCheek.setCheckNo(orderSn);
                    addNumCheekService.save(addNumCheek);
                    break;
                case USER_STAY_TIME:
                    //todo 通过用户行为分析获取数据进行判断
                    ruleValue = addPrizeRule.getRuleValue();
                    if (addFlag) {
                        log.info("当前用户当天已经添加过了停留时间添加次数了-------->{}", userId);
                        return Result.ok().data(0);
                    }
                    break;
                case USER_BUY_SUM_PRICE:
                    orderSn = jsonObject.getString("orderSn");
                    //校验订单是否存在
                    order = orderService.getBySn(orderSn);
                    if (order == null) {
                        log.info("用户购物订单不存在{}", orderSn);
                        return Result.ok().data(0);
                    }
                    ruleValue = addPrizeRule.getRuleValue();
                    double price = Double.parseDouble(ruleValue);
                    Double flowPrice = order.getFlowPrice();
                    if (flowPrice < price) {
                        log.info("当前购物订单金额小于添加要求----------------->{}", orderSn);
                        return Result.ok().data(0);
                    }
                    query.eq(AddNumCheek::getType, PrizeUserActionEnum.USER_BUY_SUM_PRICE.name())
                            .eq(AddNumCheek::getCheckNo, orderSn);
                    if (addNumCheekService.getOne(query) != null) {
                        log.info("当前购物订单已经被领取过了----------------->{}", orderSn);
                        return Result.ok().data(0);
                    }
                    addNumCheek = new AddNumCheek();
                    addNumCheek.setType(PrizeUserActionEnum.USER_BUY_SUM_PRICE.name());
                    addNumCheek.setUserId(userId);
                    addNumCheek.setCheckNo(orderSn);
                    addNumCheekService.save(addNumCheek);
                    break;
                case USER_BUY_ORDER_NUM:
                    orderSn = jsonObject.getString("orderSn");
                    //校验订单是否存在
                    order = orderService.getBySn(orderSn);
                    if (order == null) {
                        log.info("用户购物数量订单不存在{}", orderSn);
                        return Result.ok().data(0);
                    }
                    query.eq(AddNumCheek::getType, PrizeUserActionEnum.USER_BUY_ORDER_NUM.name())
                            .eq(AddNumCheek::getCheckNo, orderSn);
                    if (addNumCheekService.getOne(query) != null) {
                        log.info("当前购物订单数量已经被领取过了----------------->{}", orderSn);
                        return Result.ok().data(0);
                    }
                    addNumCheek = new AddNumCheek();
                    addNumCheek.setType(PrizeUserActionEnum.USER_BUY_ORDER_NUM.name());
                    addNumCheek.setUserId(userId);
                    addNumCheek.setCheckNo(orderSn);
                    addNumCheekService.save(addNumCheek);
                    break;
                case USER_SCAN_STORE:
                    break;
                case USER_PUBLISH_EXAMINE:
                    break;
                default:
                    return Result.ok().data(0);
            }
            //设置默认抽奖次数并返回默认抽奖次数
            for (int i = 0; i < addNum; i++) {
                PrizeNumber prizeNumber = new PrizeNumber();
                prizeNumber.setActivityPrizeId(Long.parseLong(addPrizeNumForm.getPrizeActivityId()));
                prizeNumber.setUserId(Long.parseLong(userId));
                prizeNumber.setUserAction(actionEnum.name());
                prizeNumber.setUseStatus(PrizeNumberUseEnum.WAIT.name());
                needAdd.add(prizeNumber);
            }
            prizeNumberService.saveBatch(needAdd);
            return Result.ok().data(0);
        } finally {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    if (lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
                @Override
                public void afterCompletion(int status) {
                    if (lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            });
        }
    }
    public AddPrizeRule getAddPrizeRule(String ruleCode) {
        LambdaQueryWrapper<AddPrizeRule> one = Wrappers.<AddPrizeRule>lambdaQuery().eq(AddPrizeRule::getRuleCode, ruleCode);
        return addPrizeRuleService.getOne(one);
    }
}