Procházet zdrojové kódy

1、优化抽奖逻辑

rayson před 6 měsíci
rodič
revize
7c196d842a
16 změnil soubory, kde provedl 399 přidání a 49 odebrání
  1. 12 12
      citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/api/luck/LuckLotteryApi.java
  2. 26 0
      citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/api/luck/LuckRaffleReqDTO.java
  3. 3 0
      citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/ErrorCodeConstants.java
  4. 14 4
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/api/luck/LuckLotteryApiImpl.java
  5. 3 1
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/app/luck/AppLuckLotteryController.java
  6. 8 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/app/luck/AppLuckLotteryRecordController.java
  7. 13 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckLotteryRecordDO.java
  8. 4 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckPrizeDO.java
  9. 44 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/luck/LuckPrizeMapper.java
  10. 14 5
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryRecordService.java
  11. 65 21
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryRecordServiceImpl.java
  12. 6 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryService.java
  13. 16 3
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryServiceImpl.java
  14. 32 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckPrizeService.java
  15. 40 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckPrizeServiceImpl.java
  16. 99 3
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/handler/TradeLotteryOrderHandler.java

+ 12 - 12
citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/api/luck/LuckLotteryApi.java

@@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.Parameters;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
 
 @FeignClient(name = ApiConstants.NAME)
@@ -27,19 +28,18 @@ public interface LuckLotteryApi {
 
 
     /**
-     * spuId 用于判断商品是否符合下单抽奖条件
-     * userId 谁抽奖
-     * cityName 用户喜好城市(抽某个城市的房劵)
+     * 抽奖并锁定奖品
      **/
     @PutMapping(PREFIX + "/raffle")
     @Operation(summary = "抽奖")
-    @Parameters({
-            @Parameter(name = "spuId", description = "SPU 编号", required = true, example = "2"),
-            @Parameter(name = "userId", description = "用户iD", required = true, example = "3"),
-            @Parameter(name = "cityName", description = "城市名称(广州市)", required = true, example = "广州市"),
-    })
-    CommonResult<Boolean> raffle(
-            @RequestParam("spuId") Long spuId,
-                                 @RequestParam("userId") Long userId,
-                                 @RequestParam("cityName") String cityName);
+    CommonResult<Boolean> raffle(@RequestBody LuckRaffleReqDTO raffleReqDTO);
+
+    /**
+     * 取消订单退还奖品
+     **/
+    @PutMapping(PREFIX + "/refund")
+    @Operation(summary = "取消订单退还奖品")
+    CommonResult<Boolean> refund(@RequestBody LuckRaffleReqDTO raffleReqDTO);
+
+
 }

+ 26 - 0
citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/api/luck/LuckRaffleReqDTO.java

@@ -0,0 +1,26 @@
+package com.citu.module.promotion.api.luck;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class LuckRaffleReqDTO {
+
+    @Schema(description = "订单id")
+    private Long orderId;
+    @Schema(description = "spuId")
+    private Long spuId;
+    @Schema(description = "skuId")
+    private Long skuId;
+    @Schema(description = "用户id")
+    private Long userId;
+    @Schema(description = "城市")
+    private String cityName;
+
+}

+ 3 - 0
citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/ErrorCodeConstants.java

@@ -152,6 +152,9 @@ public interface ErrorCodeConstants {
     ErrorCode LUCK_LOTTERY_NOT_ADD_PRIZE = new ErrorCode(1_013_051_02, "抽奖活动未添加奖品");
     ErrorCode LUCK_LOTTERY_PRIZE_COUNT_EXCEED = new ErrorCode(1_013_051_03, "奖品不能超过8个");
     ErrorCode LUCK_LOTTERY_PRIZE_EXTEND_NOT_COMPLETE = new ErrorCode(1_013_051_04, "自定义奖品未填写扩展信息");
+    ErrorCode LUCK_LOTTERY_PRIZE_FREEZE_NOT_ENOUGH = new ErrorCode(1_013_051_05, "冻结奖品数量不足");
+    ErrorCode LUCK_LOTTERY_PRIZE_NOT_ENOUGH = new ErrorCode(1_013_051_06, "奖品数量不足");
+
 
     // ========== 幸运抽奖-抽奖记录 1-013-052-00 ==========
     ErrorCode LUCK_LOTTERY_RECORD_NOT_EXISTS = new ErrorCode(1_013_051_02, "幸运抽奖抽奖记录不存在");

+ 14 - 4
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/api/luck/LuckLotteryApiImpl.java

@@ -3,11 +3,14 @@ package com.citu.module.promotion.api.luck;
 import com.citu.framework.common.pojo.CommonResult;
 import com.citu.module.promotion.service.luck.LuckLotteryRecordService;
 import com.citu.module.promotion.service.luck.LuckLotteryService;
+import com.citu.module.promotion.service.luck.LuckPrizeService;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 
+import static com.citu.framework.common.pojo.CommonResult.success;
+
 /**
  * 幸运抽奖活动 Api 接口实现类
  *
@@ -15,7 +18,7 @@ import javax.annotation.Resource;
  */
 @RestController // 提供 RESTful API 接口,给 Feign 调用
 @Validated
-public class LuckLotteryApiImpl implements LuckLotteryApi{
+public class LuckLotteryApiImpl implements LuckLotteryApi {
 
     @Resource
     private LuckLotteryService luckLotteryService;
@@ -26,11 +29,18 @@ public class LuckLotteryApiImpl implements LuckLotteryApi{
     @Override
     public CommonResult<Boolean> updateUserNumIncr(Long spuId, Long userId) {
         luckLotteryService.updateUserNumIncr(spuId, userId);
-        return CommonResult.success(true);
+        return success(true);
+    }
+
+    @Override
+    public CommonResult<Boolean> raffle(LuckRaffleReqDTO raffleReqDTO) {
+        luckLotteryRecordService.raffle(raffleReqDTO);
+        return success(true);
     }
 
     @Override
-    public CommonResult<Boolean> raffle(Long spuId, Long userId, String cityName) {
-        return null;
+    public CommonResult<Boolean> refund(LuckRaffleReqDTO raffleReqDTO) {
+        luckLotteryRecordService.refund(raffleReqDTO);
+        return success(true);
     }
 }

+ 3 - 1
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/app/luck/AppLuckLotteryController.java

@@ -57,7 +57,9 @@ public class AppLuckLotteryController {
         if (null == luckLottery) {
             return success(null);
         }
-        luckLotteryService.checkTimeExpired(luckLottery);
+        if(luckLotteryService.checkTimeExpiredRet(luckLottery)) {
+            return success(null);
+        }
         return success(BeanUtils.toBean(luckLottery, LuckLotteryRespVO.class));
     }
 

+ 8 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/app/luck/AppLuckLotteryRecordController.java

@@ -63,4 +63,12 @@ public class AppLuckLotteryRecordController {
         luckLotteryRecordService.receive(reqVO, getLoginUserId());
         return success(true);
     }
+
+    @GetMapping("/get/by-order-id")
+    @PreAuthenticated
+    @Operation(summary = "根据订单id获取中奖记录")
+    public CommonResult<List<LuckLotteryRecordDetailRespVO>> getByOrderId
+            (@RequestParam("orderId") Long orderId) {
+        return success(luckLotteryRecordService.getByOrderId(orderId, getLoginUserId()));
+    }
 }

+ 13 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckLotteryRecordDO.java

@@ -76,5 +76,18 @@ public class LuckLotteryRecordDO extends BaseDO {
      * 发货单号、备注等
      */
     private String deliverInfo;
+    /**
+     * 订单id
+     */
+    private Long orderId;
+    /**
+     * spu id
+     */
+    private Long spuId;
+    /**
+     * sku id
+     */
+    private Long skuId;
+
 
 }

+ 4 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckPrizeDO.java

@@ -58,6 +58,10 @@ public class LuckPrizeDO extends BaseDO {
      * 奖品数量
      */
     private Integer total;
+    /**
+     * 冻结奖品数量
+     */
+    private Integer freeze;
     /**
      * 关联优惠券id
      */

+ 44 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/luck/LuckPrizeMapper.java

@@ -1,6 +1,7 @@
 package com.citu.module.promotion.dal.mysql.luck;
 
 
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.citu.framework.common.pojo.PageResult;
 import com.citu.framework.mybatis.core.mapper.BaseMapperX;
 import com.citu.framework.mybatis.core.query.LambdaQueryWrapperX;
@@ -44,5 +45,48 @@ public interface LuckPrizeMapper extends BaseMapperX<LuckPrizeDO> {
         );
     }
 
+    /**
+     * 冻结奖品的部分数量
+     *
+     * @param id    奖品 id
+     * @param num 冻结数量
+     */
+    default int freeze(Long id, Integer num) {
+        LambdaUpdateWrapper<LuckPrizeDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<LuckPrizeDO>()
+                .setSql(" total = total - " + num
+                        + ", freeze = freeze + " + num)
+                .eq(LuckPrizeDO::getId, id)
+                .ge(LuckPrizeDO::getTotal, num); // cas 逻辑
+        return update(null, lambdaUpdateWrapper);
+    }
+
+    /**
+     * 解冻奖品的部分数量
+     *
+     * @param id    奖品 id
+     * @param num 冻结数量
+     */
+    default int unFreeze(Long id, Integer num) {
+        LambdaUpdateWrapper<LuckPrizeDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<LuckPrizeDO>()
+                .setSql(" total = total + " + num
+                        + ", freeze = freeze - " + num)
+                .eq(LuckPrizeDO::getId, id)
+                .ge(LuckPrizeDO::getFreeze, num); // cas 逻辑
+        return update(null, lambdaUpdateWrapper);
+    }
+
+    /**
+     * 扣减奖品的部分数量(对冻结额度扣除)
+     *
+     * @param id    奖品 id
+     * @param num 扣除数量
+     */
+    default int deduct(Long id,Integer num) {
+        LambdaUpdateWrapper<LuckPrizeDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<LuckPrizeDO>()
+                .setSql( "freeze = freeze - " + num)
+                .eq(LuckPrizeDO::getId, id)
+                .ge(LuckPrizeDO::getFreeze, num); // cas 逻辑
+        return update(null, lambdaUpdateWrapper);
+    }
 
 }

+ 14 - 5
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryRecordService.java

@@ -2,6 +2,7 @@ package com.citu.module.promotion.service.luck;
 
 
 import com.citu.framework.common.pojo.PageResult;
+import com.citu.module.promotion.api.luck.LuckRaffleReqDTO;
 import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordDetailRespVO;
 import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordPageReqVO;
 import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordRespVO;
@@ -66,13 +67,14 @@ public interface LuckLotteryRecordService {
 
 
     /**
-     * 抽奖
-     * @param spuId 商品id
-     * @param userId 抽奖用户
-     * @param cityName 城市名称
+     * 系统内部-抽奖并锁定奖品
      */
-    void raffle(Long spuId, Long userId, String cityName);
+    LuckLotteryRecordRespVO raffle(LuckRaffleReqDTO raffleReqDTO);
 
+    /**
+     * 系统内部-退还奖品
+     */
+    void refund(LuckRaffleReqDTO raffleReqDTO);
 
     /**
      * 获取用户抽奖记录
@@ -101,4 +103,11 @@ public interface LuckLotteryRecordService {
      * @param userId 抽奖用户
      */
     LuckLotteryRecordDetailRespVO getLast(Long lotteryId,Long userId);
+
+    /**
+     * 根据订单id获取抽奖记录
+     * @param orderId 订单id
+     * @param userId 用户id
+     */
+    List<LuckLotteryRecordDetailRespVO> getByOrderId(Long orderId, Long userId);
 }

+ 65 - 21
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryRecordServiceImpl.java

@@ -5,8 +5,10 @@ import com.baomidou.dynamic.datasource.annotation.DSTransactional;
 import com.baomidou.lock.annotation.Lock4j;
 import com.citu.framework.common.pojo.PageResult;
 import com.citu.framework.common.util.object.BeanUtils;
+import com.citu.framework.mybatis.core.query.LambdaQueryWrapperX;
 import com.citu.module.menduner.system.api.user.MendunerUserApi;
 import com.citu.module.menduner.system.api.user.UserInfoRespDTO;
+import com.citu.module.promotion.api.luck.LuckRaffleReqDTO;
 import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordDetailRespVO;
 import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordPageReqVO;
 import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordRespVO;
@@ -17,12 +19,10 @@ import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryDO;
 import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryRecordDO;
 import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeDO;
 import com.citu.module.promotion.dal.mysql.luck.LuckLotteryRecordMapper;
-import com.citu.module.promotion.enums.luck.LuckPrizeTypeEnum;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
-import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
@@ -30,7 +30,7 @@ import java.util.concurrent.ThreadLocalRandom;
 import java.util.stream.Collectors;
 
 import static com.citu.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static com.citu.module.promotion.enums.ErrorCodeConstants.*;
+import static com.citu.module.promotion.enums.ErrorCodeConstants.LUCK_LOTTERY_RECORD_NOT_EXISTS;
 
 /**
  * 幸运抽奖-抽奖记录 Service 实现类
@@ -151,25 +151,22 @@ public class LuckLotteryRecordServiceImpl implements LuckLotteryRecordService {
 
     @Override
     @DSTransactional
-    @Lock4j(keys = {"#spuId", "#userId", "#cityName"}, acquireTimeout = 6000)
-    public void raffle(Long spuId, Long userId, String cityName) {
-        LuckLotteryDO luckLottery = luckLotteryService.getLuckLotteryBySpuId(String.valueOf(spuId));
-        // 效验活动是否过期
-        LocalDateTime now = LocalDateTime.now();
+    @Lock4j(keys = {"#raffleReqDTO.spuId", "#raffleReqDTO.userId", "#raffleReqDTO.cityName"}, acquireTimeout = 6000)
+    public LuckLotteryRecordRespVO raffle(LuckRaffleReqDTO raffleReqDTO) {
+        LuckLotteryDO luckLottery = luckLotteryService.getLuckLotteryBySpuId(String.valueOf(raffleReqDTO.getSpuId()));
+
         // 判断活动有没有开始,判断活动有没有结束
-        if (luckLottery.getStartTime().isAfter(now)||luckLottery.getEndTime().isBefore(now)) {
-           return;
+        if (luckLotteryService.checkTimeExpiredRet(luckLottery)) {
+            return null;
         }
 
         // 获取奖品
         List<LuckPrizeDO> luckPrizeList = luckPrizeService.getListByLotteryId(luckLottery.getId());
         if (CollUtil.isEmpty(luckPrizeList)) {
-            return;
+            return null;
         }
-        // 筛选出 喜爱城市
-        luckPrizeList = luckPrizeList.stream().filter(prize->
-                prize.getType().equals(LuckPrizeTypeEnum.CUSTOM.getType())
-                && prize.getExtend().getCityName().equals(cityName)).collect(Collectors.toList());
+        // 筛选出 城市
+        luckPrizeList = luckPrizeService.filterCustomTypeAndCity(luckPrizeList, raffleReqDTO.getCityName());
 
         // 计算总权重并随机选择奖品
         int totalWeight = luckPrizeList.stream().mapToInt(prize -> prize.getChance() * prize.getTotal()).sum();
@@ -181,20 +178,23 @@ public class LuckLotteryRecordServiceImpl implements LuckLotteryRecordService {
         // 扣除奖品剩余数量
         if (null == selectedPrize) {
             // 炸了
-            return ;
+            return null;
         }
 
         if (selectedPrize.getTotal() <= 0) {
             // 没数了
-            return ;
+            return null;
         }
 
-        selectedPrize.setTotal(selectedPrize.getTotal() - 1);
-        luckPrizeService.updateById(selectedPrize);
+        // 冻结奖品数量
+        luckPrizeService.freeze(selectedPrize.getId(), 1);
 
         // 插入抽奖记录
         LuckLotteryRecordDO luckLotteryRecord = LuckLotteryRecordDO.builder()
-                .userId(userId)
+                .userId(raffleReqDTO.getUserId())
+                .orderId(raffleReqDTO.getOrderId())
+                .spuId(raffleReqDTO.getSpuId())
+                .skuId(raffleReqDTO.getSkuId())
                 .lotteryId(luckLottery.getId())
                 .prizeId(selectedPrize.getId())
                 .type(selectedPrize.getType())
@@ -204,6 +204,27 @@ public class LuckLotteryRecordServiceImpl implements LuckLotteryRecordService {
                 .build();
         luckLotteryRecordMapper.insert(luckLotteryRecord);
 
+        return LuckLotteryRecordConvert.INSTANCE.convert(luckLotteryRecord);
+
+    }
+
+    @Override
+    @DSTransactional
+    public void refund(LuckRaffleReqDTO raffleReqDTO) {
+        LuckLotteryRecordDO record = luckLotteryRecordMapper.selectOne(new LambdaQueryWrapperX<LuckLotteryRecordDO>()
+                .eq(LuckLotteryRecordDO::getOrderId, raffleReqDTO.getOrderId())
+                .eq(LuckLotteryRecordDO::getSpuId, raffleReqDTO.getSpuId())
+                .eq(LuckLotteryRecordDO::getSkuId, raffleReqDTO.getSkuId())
+                .eq(LuckLotteryRecordDO::getUserId, raffleReqDTO.getUserId())
+        );
+        if (null == record) {
+            return;
+        }
+
+        // 解冻数量
+        luckPrizeService.unfreeze(record.getPrizeId(), 1);
+        // 删除抽奖记录
+        luckLotteryRecordMapper.deleteById(record.getId());
     }
 
     @Override
@@ -218,7 +239,6 @@ public class LuckLotteryRecordServiceImpl implements LuckLotteryRecordService {
         // 查询用户
         UserInfoRespDTO user = mendunerUserApi.getUser(userId).getCheckedData();
         for (LuckLotteryRecordDO record : luckLotteryRecordList) {
-
             list.add(LuckLotteryRecordConvert.INSTANCE.convertDetail(
                     LuckLotteryRecordConvert.INSTANCE.convert(record),
                     luckLotteryService.detail(record.getLotteryId()),
@@ -263,12 +283,15 @@ public class LuckLotteryRecordServiceImpl implements LuckLotteryRecordService {
     }
 
     @Override
+    @DSTransactional
     public void receive(AppLuckLotteryReceiveReqVO reqVO, Long userId) {
         LuckLotteryRecordDO luckLotteryRecord = validateLuckLotteryRecordExists(reqVO.getId());
         if (luckLotteryRecord.getUserId().equals(userId)) {
             // 是自己领取的
             luckLotteryRecord.setIsReceive(true);
             luckLotteryRecord.setReceiveInfo(reqVO.getReceiveInfo());
+            // 扣除奖品数量
+            luckPrizeService.deduct(luckLotteryRecord.getPrizeId(), 1);
             luckLotteryRecordMapper.updateById(luckLotteryRecord);
         }
     }
@@ -287,4 +310,25 @@ public class LuckLotteryRecordServiceImpl implements LuckLotteryRecordService {
                 luckPrizeService.detail(record.getPrizeId()),
                 user);
     }
+
+    @Override
+    public List<LuckLotteryRecordDetailRespVO> getByOrderId(Long orderId, Long userId) {
+        List<LuckLotteryRecordDO> list = luckLotteryRecordMapper
+                .selectList(LuckLotteryRecordDO::getOrderId, orderId);
+        if (CollUtil.isEmpty(list)) {
+            return null;
+        }
+        // 同一个订单下单的绝对只有一个用户
+        UserInfoRespDTO user =
+                mendunerUserApi.getUser(userId).getCheckedData();
+        List<LuckLotteryRecordDetailRespVO> respList = new ArrayList<>();
+        for (LuckLotteryRecordDO record : list) {
+            respList.add(LuckLotteryRecordConvert.INSTANCE.convertDetail(
+                    LuckLotteryRecordConvert.INSTANCE.convert(record),
+                    luckLotteryService.detail(record.getLotteryId()),
+                    luckPrizeService.detail(record.getPrizeId()),
+                    user));
+        }
+        return respList;
+    }
 }

+ 6 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryService.java

@@ -119,6 +119,12 @@ public interface LuckLotteryService {
      **/
     void checkTimeExpired(LuckLotteryDO luckLottery);
 
+    /**
+     * 校验抽奖活动时间是否过期
+     * @param luckLottery 抽奖活动
+     **/
+    boolean checkTimeExpiredRet(LuckLotteryDO luckLottery);
+
     /**
      * 获取用户抽奖次数
      * @param lotteryId 活动id

+ 16 - 3
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryServiceImpl.java

@@ -132,7 +132,7 @@ public class LuckLotteryServiceImpl implements LuckLotteryService {
     @Override
     public LuckLotteryDO valid(Long id) {
         LuckLotteryDO luckLottery = validateLuckLotteryExists(id);
-        checkTimeExpired(luckLottery);
+        checkTimeExpiredRet(luckLottery);
         return luckLottery;
     }
 
@@ -149,9 +149,20 @@ public class LuckLotteryServiceImpl implements LuckLotteryService {
         }
     }
 
+    @Override
+    public boolean checkTimeExpiredRet(LuckLotteryDO luckLottery) {
+        // 效验活动是否过期
+        LocalDateTime now = LocalDateTime.now();
+        // 判断活动有没有开始,判断活动有没有结束
+        if (luckLottery.getStartTime().isAfter(now) || luckLottery.getEndTime().isBefore(now)) {
+            return true;
+        }
+        return false;
+    }
+
     @Override
     public LuckLotteryDetailRespVO detail(Long id) {
-        LuckLotteryDO luckLottery = valid(id);
+        LuckLotteryDO luckLottery = validateLuckLotteryExists(id);
         LuckLotteryDetailRespVO resp = LuckLotteryConvert.INSTANCE.convert2(luckLottery);
 
         // 下单指定商品支付成功类型
@@ -209,7 +220,9 @@ public class LuckLotteryServiceImpl implements LuckLotteryService {
             return;
         }
         // 校验活动
-        checkTimeExpired(luckLottery);
+        if(checkTimeExpiredRet(luckLottery)) {
+            return;
+        }
         LuckUserDO luckUser = luckUserMapper.getByUserId(luckLottery.getId(), userId);
         if (null == luckUser) {
             // 不存在

+ 32 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckPrizeService.java

@@ -130,4 +130,36 @@ public interface LuckPrizeService {
      */
     List<LuckPrizeDetailRespVO> getByLotteryIdAndCityName(Long lotteryId,String cityName);
 
+    /**
+     * 冻结奖品数量
+     *
+     * @param id 抽奖活动id
+     * @param num 锁定奖品数量
+     */
+    void freeze(Long id,Integer num);
+
+    /**
+     * 解冻奖品数量
+     *
+     * @param id 抽奖活动id
+     * @param num 锁定奖品数量
+     */
+    void unfreeze(Long id,Integer num);
+
+    /**
+     * 扣减奖品数量(对冻结额度扣除)
+     *
+     * @param id 抽奖活动id
+     * @param num 锁定奖品数量
+     */
+    void deduct(Long id,Integer num);
+
+    /**
+     * 过滤自定义奖品(所在城市名称)
+     *
+     * @param list 奖品列表
+     * @param cityName 城市名称
+     * @return 奖品列表
+     */
+    List<LuckPrizeDO> filterCustomTypeAndCity(List<LuckPrizeDO> list, String cityName);
 }

+ 40 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckPrizeServiceImpl.java

@@ -388,4 +388,44 @@ public class LuckPrizeServiceImpl implements LuckPrizeService {
             return false;
         }).collect(Collectors.toList());
     }
+
+    @Override
+    public void freeze(Long id, Integer num) {
+        int result = luckPrizeMapper.freeze(id, num);
+        if (0 == result) {
+            throw exception(LUCK_LOTTERY_PRIZE_NOT_ENOUGH);
+        }
+    }
+
+    @Override
+    public void unfreeze(Long id, Integer num) {
+        int result = luckPrizeMapper.unFreeze(id, num);
+        if (0 == result) {
+            throw exception(LUCK_LOTTERY_PRIZE_FREEZE_NOT_ENOUGH);
+        }
+    }
+
+    @Override
+    public void deduct(Long id, Integer num) {
+        int result = luckPrizeMapper.deduct(id, num);
+        if (0 == result) {
+            throw exception(LUCK_LOTTERY_PRIZE_NOT_ENOUGH);
+        }
+    }
+
+    @Override
+    public List<LuckPrizeDO> filterCustomTypeAndCity(List<LuckPrizeDO> list, String cityName) {
+        List<LuckPrizeDO> customTypeAndCity = list.stream()
+                .filter(prize ->
+                        prize.getType().equals(LuckPrizeTypeEnum.CUSTOM.getType())
+                                && null != prize.getExtend()
+                                && null != prize.getExtend().getCityName()
+                                && prize.getExtend().getCityName().equals(cityName)
+                                && prize.getTotal() > 0
+                ).collect(Collectors.toList());
+        if (CollUtil.isEmpty(customTypeAndCity)) {
+            throw exception(LUCK_LOTTERY_PRIZE_NOT_ENOUGH);
+        }
+        return customTypeAndCity;
+    }
 }

+ 99 - 3
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/handler/TradeLotteryOrderHandler.java

@@ -1,6 +1,7 @@
 package com.citu.module.trade.service.order.handler;
 
 import com.citu.module.promotion.api.luck.LuckLotteryApi;
+import com.citu.module.promotion.api.luck.LuckRaffleReqDTO;
 import com.citu.module.trade.dal.dataobject.order.TradeOrderDO;
 import com.citu.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import org.springframework.stereotype.Component;
@@ -16,15 +17,110 @@ import java.util.List;
 @Component
 public class TradeLotteryOrderHandler implements TradeOrderHandler {
 
+    private static final String propertyName = "房劵";
     @Resource
     private LuckLotteryApi luckLotteryApi;
 
     @Override
     public void afterPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
-        // 订单支付后
-        orderItems.forEach(orderItem -> {
-            luckLotteryApi.updateUserNumIncr(orderItem.getSpuId(), orderItem.getUserId()).getCheckedData();
+        // 支付成功后
+        orderItems.forEach(item -> {
+            TradeOrderItemDO.Property property = item.getProperties().stream()
+                    .filter(c -> propertyName.equals(c.getPropertyName()))
+                    .findFirst().orElse(null);
+            if (null == property) {
+                return;
+            }
+
+            int count = item.getCount();
+            if (count > 1) {
+                // 购买一个sku*N的情况
+                for (int i = 0; i < count; i++) {
+                    performRaffle(order, item, property.getValueName());
+                }
+            } else {
+                performRaffle(order, item, property.getValueName());
+            }
         });
+    }
+
+    /**
+     * 执行抽奖
+     *
+     * @param order     订单
+     * @param item      订单项
+     * @param cityName  城市名称
+     */
+    private void performRaffle(TradeOrderDO order, TradeOrderItemDO item, String cityName) {
+        LuckRaffleReqDTO reqDTO = LuckRaffleReqDTO.builder()
+                .orderId(order.getId())
+                .spuId(item.getSpuId())
+                .skuId(item.getSkuId())
+                .userId(order.getUserId())
+                .cityName(cityName)
+                .build();
+        luckLotteryApi.raffle(reqDTO).getCheckedData();
+    }
 
+    /**
+     * 执行退款
+     *
+     * @param order     订单
+     * @param item      订单项
+     * @param cityName  城市名称
+     */
+    private void performRefund(TradeOrderDO order, TradeOrderItemDO item, String cityName) {
+        LuckRaffleReqDTO reqDTO = LuckRaffleReqDTO.builder()
+                .orderId(order.getId())
+                .spuId(item.getSpuId())
+                .skuId(item.getSkuId())
+                .userId(order.getUserId())
+                .cityName(cityName)
+                .build();
+        luckLotteryApi.refund(reqDTO).getCheckedData();
     }
+
+
+    @Override
+    public void afterCancelOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
+        // 订单取消后
+        orderItems.forEach(item -> {
+            TradeOrderItemDO.Property property = item.getProperties().stream()
+                    .filter(c -> propertyName.equals(c.getPropertyName()))
+                    .findFirst().orElse(null);
+            if (null == property) {
+                return;
+            }
+            int count = item.getCount();
+            if (count > 1) {
+                // 购买一个sku*N的情况
+                for (int i = 0; i < count; i++) {
+                    performRefund(order, item, property.getValueName());
+                }
+            } else {
+                performRefund(order, item, property.getValueName());
+            }
+        });
+    }
+
+    @Override
+    public void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) {
+        // 订单项取消后
+        TradeOrderItemDO.Property property = orderItem.getProperties()
+                .stream().filter(c -> propertyName.equals(c.getPropertyName()))
+                .findFirst().orElse(null);
+        if (null == property) {
+            return;
+        }
+        int count = orderItem.getCount();
+        if (count > 1) {
+            // 购买一个sku*N的情况
+            for (int i = 0; i < count; i++) {
+                performRefund(order, orderItem, property.getValueName());
+            }
+        } else {
+            performRefund(order, orderItem, property.getValueName());
+        }
+    }
+
 }