peng
2 天以前 d68eaea2f5e4a0d655b9e393c104cf35987b99f4
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,230 @@
    @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
    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());
        }
        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();
        String userId = addPrizeNumForm.getUserId();
        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);
    }
    public  AddPrizeRule getAddPrizeRule(String ruleCode) {
        LambdaQueryWrapper<AddPrizeRule> one = Wrappers.<AddPrizeRule>lambdaQuery().eq(AddPrizeRule::getRuleCode, ruleCode);
       return addPrizeRuleService.getOne(one);
    }
}