Commit 383439f9029df85733fc7391670cadd98aaa0722

Authored by owen
2 parents 4f33a0c9 a76760c4

Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product

Showing 36 changed files with 612 additions and 245 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
1 package cn.iocoder.yudao.module.promotion.api.combination; 1 package cn.iocoder.yudao.module.promotion.api.combination;
2 2
3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
  4 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO;
4 5
5 import javax.validation.Valid; 6 import javax.validation.Valid;
6 import java.time.LocalDateTime; 7 import java.time.LocalDateTime;
@@ -65,4 +66,17 @@ public interface CombinationRecordApi { @@ -65,4 +66,17 @@ public interface CombinationRecordApi {
65 */ 66 */
66 void updateRecordStatusToInProgress(Long userId, Long orderId, LocalDateTime startTime); 67 void updateRecordStatusToInProgress(Long userId, Long orderId, LocalDateTime startTime);
67 68
  69 + /**
  70 + * 【下单前】校验是否满足拼团活动条件
  71 + *
  72 + * 如果校验失败,则抛出业务异常
  73 + *
  74 + * @param activityId 活动编号
  75 + * @param userId 用户编号
  76 + * @param skuId sku 编号
  77 + * @param count 数量
  78 + * @return 拼团信息
  79 + */
  80 + CombinationValidateJoinRespDTO validateJoinCombination(Long activityId, Long userId, Long skuId, Integer count);
  81 +
68 } 82 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordRespDTO.java renamed to yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationValidateJoinRespDTO.java
1 package cn.iocoder.yudao.module.promotion.api.combination.dto; 1 package cn.iocoder.yudao.module.promotion.api.combination.dto;
2 2
3 -import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;  
4 import lombok.Data; 3 import lombok.Data;
5 4
6 /** 5 /**
7 - * 拼团记录 Response DTO 6 + * 校验参与拼团 Response DTO
8 * 7 *
9 * @author HUIHUI 8 * @author HUIHUI
10 */ 9 */
11 @Data 10 @Data
12 -public class CombinationRecordRespDTO { 11 +public class CombinationValidateJoinRespDTO {
13 12
14 /** 13 /**
15 - * 拼团活动编号 14 + * 砍价活动编号
16 */ 15 */
17 private Long activityId; 16 private Long activityId;
18 /** 17 /**
19 - * SPU 编号 18 + * 砍价活动名称
20 */ 19 */
21 - private Long spuId;  
22 - /**  
23 - * SKU 编号  
24 - */  
25 - private Long skuId;  
26 - /**  
27 - * 用户编号  
28 - */  
29 - private Long userId;  
30 - /**  
31 - * 订单编号  
32 - */  
33 - private Long orderId; 20 + private String name;
  21 +
34 /** 22 /**
35 - * 开团状态  
36 - *  
37 - * 枚举 {@link CombinationRecordStatusEnum} 23 + * 拼团金额
38 */ 24 */
39 - private Integer status; 25 + private Integer combinationPrice;
40 26
41 } 27 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
@@ -55,7 +55,7 @@ public interface ErrorCodeConstants { @@ -55,7 +55,7 @@ public interface ErrorCodeConstants {
55 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_003, "秒杀活动已关闭,不能修改"); 55 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_003, "秒杀活动已关闭,不能修改");
56 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_008_004, "秒杀活动未关闭或未结束,不能删除"); 56 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_008_004, "秒杀活动未关闭或未结束,不能删除");
57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_005, "秒杀活动已关闭,不能重复关闭"); 57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_005, "秒杀活动已关闭,不能重复关闭");
58 - ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_008_006, "秒杀失败,原因秒杀库存不足"); 58 + ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_008_006, "秒杀失败,原因:秒杀库存不足");
59 ErrorCode SECKILL_JOIN_ACTIVITY_TIME_ERROR = new ErrorCode(1_013_008_007, "秒杀失败,原因:不在活动时间范围内"); 59 ErrorCode SECKILL_JOIN_ACTIVITY_TIME_ERROR = new ErrorCode(1_013_008_007, "秒杀失败,原因:不在活动时间范围内");
60 ErrorCode SECKILL_JOIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_008_008, "秒杀失败,原因:秒杀活动已关闭"); 60 ErrorCode SECKILL_JOIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_008_008, "秒杀失败,原因:秒杀活动已关闭");
61 ErrorCode SECKILL_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_008_009, "秒杀失败,原因:单次限购超出"); 61 ErrorCode SECKILL_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_008_009, "秒杀失败,原因:单次限购超出");
@@ -72,6 +72,8 @@ public interface ErrorCodeConstants { @@ -72,6 +72,8 @@ public interface ErrorCodeConstants {
72 ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1_013_010_002, "拼团活动已关闭不能修改"); 72 ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1_013_010_002, "拼团活动已关闭不能修改");
73 ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_010_003, "拼团活动未关闭或未结束,不能删除"); 73 ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_010_003, "拼团活动未关闭或未结束,不能删除");
74 ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1_013_010_004, "拼团失败,原因:拼团活动已关闭"); 74 ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1_013_010_004, "拼团失败,原因:拼团活动已关闭");
  75 + ErrorCode COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS = new ErrorCode(1_013_010_005, "拼团失败,原因:拼团活动商品不存在");
  76 + ErrorCode COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_010_006, "拼团失败,原因:拼团活动商品库存不足");
75 77
76 // ========== 拼团记录 1-013-011-000 ========== 78 // ========== 拼团记录 1-013-011-000 ==========
77 ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1_013_011_000, "拼团不存在"); 79 ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1_013_011_000, "拼团不存在");
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
1 package cn.iocoder.yudao.module.promotion.api.combination; 1 package cn.iocoder.yudao.module.promotion.api.combination;
2 2
3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
  4 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO;
4 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; 5 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
5 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; 6 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
6 import org.springframework.stereotype.Service; 7 import org.springframework.stereotype.Service;
@@ -50,4 +51,9 @@ public class CombinationRecordApiImpl implements CombinationRecordApi { @@ -50,4 +51,9 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
50 userId, orderId, startTime); 51 userId, orderId, startTime);
51 } 52 }
52 53
  54 + @Override
  55 + public CombinationValidateJoinRespDTO validateJoinCombination(Long activityId, Long userId, Long skuId, Integer count) {
  56 + return recordService.validateJoinCombination(activityId, userId, skuId, count);
  57 + }
  58 +
53 } 59 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java
1 package cn.iocoder.yudao.module.promotion.controller.app.activity; 1 package cn.iocoder.yudao.module.promotion.controller.app.activity;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.map.MapUtil;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.module.promotion.controller.app.activity.vo.AppActivityRespVO; 6 import cn.iocoder.yudao.module.promotion.controller.app.activity.vo.AppActivityRespVO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
  9 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
  10 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
  11 +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
  12 +import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
  13 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
5 import io.swagger.v3.oas.annotations.Operation; 14 import io.swagger.v3.oas.annotations.Operation;
6 import io.swagger.v3.oas.annotations.Parameter; 15 import io.swagger.v3.oas.annotations.Parameter;
7 import io.swagger.v3.oas.annotations.tags.Tag; 16 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -11,8 +20,11 @@ import org.springframework.web.bind.annotation.RequestMapping; @@ -11,8 +20,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
11 import org.springframework.web.bind.annotation.RequestParam; 20 import org.springframework.web.bind.annotation.RequestParam;
12 import org.springframework.web.bind.annotation.RestController; 21 import org.springframework.web.bind.annotation.RestController;
13 22
14 -import java.time.LocalDateTime;  
15 -import java.util.*; 23 +import javax.annotation.Resource;
  24 +import java.util.ArrayList;
  25 +import java.util.HashMap;
  26 +import java.util.List;
  27 +import java.util.Map;
16 28
17 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 29 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
18 30
@@ -22,47 +34,66 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -22,47 +34,66 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
22 @Validated 34 @Validated
23 public class AppActivityController { 35 public class AppActivityController {
24 36
25 - // TODO @puhui999:可以实现下 37 + @Resource
  38 + private CombinationActivityService combinationActivityService;
  39 + @Resource
  40 + private SeckillActivityService seckillActivityService;
  41 + @Resource
  42 + private BargainActivityService bargainActivityService;
  43 +
26 @GetMapping("/list-by-spu-id") 44 @GetMapping("/list-by-spu-id")
27 @Operation(summary = "获得单个商品,近期参与的每个活动") // 每种活动,只返回一个 45 @Operation(summary = "获得单个商品,近期参与的每个活动") // 每种活动,只返回一个
28 @Parameter(name = "spuId", description = "商品编号", required = true) 46 @Parameter(name = "spuId", description = "商品编号", required = true)
29 public CommonResult<List<AppActivityRespVO>> getActivityListBySpuId(@RequestParam("spuId") Long spuId) { 47 public CommonResult<List<AppActivityRespVO>> getActivityListBySpuId(@RequestParam("spuId") Long spuId) {
30 - // TODO 芋艿,实现  
31 - List<AppActivityRespVO> randomList = new ArrayList<>();  
32 - Random random = new Random();  
33 - for (int i = 0; i < 3; i++) { // 生成5个随机对象  
34 - AppActivityRespVO vo = new AppActivityRespVO();  
35 - vo.setId(random.nextLong()); // 随机生成一个长整型 ID  
36 - vo.setType(i + 1); // 随机生成一个介于0到2之间的整数,对应枚举类型的三种类型之一  
37 - vo.setName(String.format("活动%d", random.nextInt(100))); // 随机生成一个类似于“活动XX”的活动名称,XX为0到99之间的随机整数  
38 - vo.setStartTime(LocalDateTime.now()); // 随机生成一个在过去的一年内的开始时间(以毫秒为单位)  
39 - vo.setEndTime(LocalDateTime.now()); // 随机生成一个在未来的一年内的结束时间(以毫秒为单位)  
40 - randomList.add(vo);  
41 - }  
42 - return success(randomList); 48 + return success(getAppActivityRespVOList(spuId));
43 } 49 }
44 50
45 - // TODO @puhui999:可以实现下  
46 @GetMapping("/list-by-spu-ids") 51 @GetMapping("/list-by-spu-ids")
47 @Operation(summary = "获得多个商品,近期参与的每个活动") // 每种活动,只返回一个;key 为 SPU 编号 52 @Operation(summary = "获得多个商品,近期参与的每个活动") // 每种活动,只返回一个;key 为 SPU 编号
48 @Parameter(name = "spuIds", description = "商品编号数组", required = true) 53 @Parameter(name = "spuIds", description = "商品编号数组", required = true)
49 public CommonResult<Map<Long, List<AppActivityRespVO>>> getActivityListBySpuIds(@RequestParam("spuIds") List<Long> spuIds) { 54 public CommonResult<Map<Long, List<AppActivityRespVO>>> getActivityListBySpuIds(@RequestParam("spuIds") List<Long> spuIds) {
50 - // TODO 芋艿,实现  
51 - List<AppActivityRespVO> randomList = new ArrayList<>();  
52 - Random random = new Random();  
53 - for (int i = 0; i < 5; i++) { // 生成5个随机对象  
54 - AppActivityRespVO vo = new AppActivityRespVO();  
55 - vo.setId(random.nextLong()); // 随机生成一个长整型 ID  
56 - vo.setType(random.nextInt(3)); // 随机生成一个介于0到2之间的整数,对应枚举类型的三种类型之一  
57 - vo.setName(String.format("活动%d", random.nextInt(100))); // 随机生成一个类似于“活动XX”的活动名称,XX为0到99之间的随机整数  
58 - vo.setStartTime(LocalDateTime.now()); // 随机生成一个在过去的一年内的开始时间(以毫秒为单位)  
59 - vo.setEndTime(LocalDateTime.now()); // 随机生成一个在未来的一年内的结束时间(以毫秒为单位)  
60 - randomList.add(vo); 55 +
  56 + if (CollUtil.isEmpty(spuIds)) {
  57 + return success(MapUtil.empty());
61 } 58 }
62 - Map<Long, List<AppActivityRespVO>> map = new HashMap<>();  
63 - map.put(109L, randomList);  
64 - map.put(2L, randomList); 59 +
  60 + Map<Long, List<AppActivityRespVO>> map = new HashMap<>(spuIds.size());
  61 + spuIds.forEach(spuId -> {
  62 + map.put(spuId, getAppActivityRespVOList(spuId));
  63 + });
65 return success(map); 64 return success(map);
66 } 65 }
67 66
  67 + private List<AppActivityRespVO> getAppActivityRespVOList(Long spuId) {
  68 + List<AppActivityRespVO> respList = new ArrayList<>();
  69 + CombinationActivityDO combination = combinationActivityService.getCombinationActivityBySpuId(spuId);
  70 + if (combination != null) {
  71 + respList.add(new AppActivityRespVO()
  72 + .setId(combination.getId())
  73 + .setType(PromotionTypeEnum.COMBINATION_ACTIVITY.getType())
  74 + .setName(combination.getName())
  75 + .setStartTime(combination.getStartTime())
  76 + .setEndTime(combination.getEndTime()));
  77 + }
  78 + SeckillActivityDO seckill = seckillActivityService.getSeckillActivityBySpuId(spuId);
  79 + if (seckill != null) {
  80 + respList.add(new AppActivityRespVO()
  81 + .setId(seckill.getId())
  82 + .setType(PromotionTypeEnum.SECKILL_ACTIVITY.getType())
  83 + .setName(seckill.getName())
  84 + .setStartTime(seckill.getStartTime())
  85 + .setEndTime(seckill.getEndTime()));
  86 + }
  87 + BargainActivityDO bargain = bargainActivityService.getBargainActivityBySpuId(spuId);
  88 + if (bargain != null) {
  89 + respList.add(new AppActivityRespVO()
  90 + .setId(bargain.getId())
  91 + .setType(PromotionTypeEnum.BARGAIN_ACTIVITY.getType())
  92 + .setName(bargain.getName())
  93 + .setStartTime(bargain.getStartTime())
  94 + .setEndTime(bargain.getEndTime()));
  95 + }
  96 + return respList;
  97 + }
  98 +
68 } 99 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainRecordController.java
@@ -92,40 +92,28 @@ public class AppBargainRecordController { @@ -92,40 +92,28 @@ public class AppBargainRecordController {
92 // 1. 查询砍价记录 + 砍价活动 92 // 1. 查询砍价记录 + 砍价活动
93 Assert.isTrue(id != null || activityId != null, "砍价记录编号和活动编号不能同时为空"); 93 Assert.isTrue(id != null || activityId != null, "砍价记录编号和活动编号不能同时为空");
94 BargainRecordDO record = id != null ? bargainRecordService.getBargainRecord(id) 94 BargainRecordDO record = id != null ? bargainRecordService.getBargainRecord(id)
95 - : bargainRecordService.getInProgressBargainRecord(getLoginUserId(), activityId); 95 + : bargainRecordService.getLastBargainRecord(getLoginUserId(), activityId);
96 if (activityId == null || record != null) { 96 if (activityId == null || record != null) {
97 activityId = record.getActivityId(); 97 activityId = record.getActivityId();
98 } 98 }
99 // 2. 查询助力记录 99 // 2. 查询助力记录
100 - Integer helpAction = getHelpAction(record, activityId); 100 + Long userId = getLoginUserId();
  101 + Integer helpAction = getHelpAction(userId, record, activityId);
101 // 3. 如果是自己的订单,则查询订单信息 102 // 3. 如果是自己的订单,则查询订单信息
  103 + TradeOrderRespDTO order = record != null && record.getOrderId() != null && record.getUserId().equals(getLoginUserId())
  104 + ? tradeOrderApi.getOrder(record.getOrderId()) : null;
102 // TODO 继续查询别的字段 105 // TODO 继续查询别的字段
103 106
104 // 拼接返回 107 // 拼接返回
105 - return success(BargainRecordConvert.INSTANCE.convert02(record, helpAction));  
106 -//  
107 -// AppBargainRecordDetailRespVO detail = new AppBargainRecordDetailRespVO();  
108 -// detail.setId(1L);  
109 -// detail.setUserId(1L);  
110 -// detail.setSpuId(1L);  
111 -// detail.setSkuId(1L);  
112 -// detail.setPrice(500);  
113 -// detail.setActivityId(1L);  
114 -// detail.setBargainPrice(150);  
115 -// detail.setPrice(200);  
116 -// detail.setPayPrice(180);  
117 -// detail.setStatus(1);  
118 -// detail.setExpireTime(LocalDateTimeUtils.addTime(Duration.ofDays(2)));  
119 -// return success(detail); 108 + return success(BargainRecordConvert.INSTANCE.convert02(record, helpAction, order));
120 } 109 }
121 110
122 - private Integer getHelpAction(BargainRecordDO record, Long activityId) { 111 + private Integer getHelpAction(Long userId, BargainRecordDO record, Long activityId) {
123 // 0.1 如果没有活动,无法帮砍 112 // 0.1 如果没有活动,无法帮砍
124 if (activityId == null) { 113 if (activityId == null) {
125 return null; 114 return null;
126 } 115 }
127 // 0.2 如果是自己的砍价记录,无法帮砍 116 // 0.2 如果是自己的砍价记录,无法帮砍
128 - Long userId = getLoginUserId();  
129 if (record != null && record.getUserId().equals(userId)) { 117 if (record != null && record.getUserId().equals(userId)) {
130 return null; 118 return null;
131 } 119 }
@@ -141,7 +129,7 @@ public class AppBargainRecordController { @@ -141,7 +129,7 @@ public class AppBargainRecordController {
141 && bargainHelpService.getBargainHelpCountByActivity(activityId, userId) >= activity.getBargainCount()) { 129 && bargainHelpService.getBargainHelpCountByActivity(activityId, userId) >= activity.getBargainCount()) {
142 return AppBargainRecordDetailRespVO.HELP_ACTION_FULL; 130 return AppBargainRecordDetailRespVO.HELP_ACTION_FULL;
143 } 131 }
144 - 132 + // 3. 允许助力
145 return AppBargainRecordDetailRespVO.HELP_ACTION_NONE; 133 return AppBargainRecordDetailRespVO.HELP_ACTION_NONE;
146 } 134 }
147 135
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationActivityController.java
@@ -14,6 +14,8 @@ import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivity @@ -14,6 +14,8 @@ import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivity
14 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; 14 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
15 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; 15 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
16 import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; 16 import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
  17 +import com.google.common.cache.CacheLoader;
  18 +import com.google.common.cache.LoadingCache;
17 import io.swagger.v3.oas.annotations.Operation; 19 import io.swagger.v3.oas.annotations.Operation;
18 import io.swagger.v3.oas.annotations.Parameter; 20 import io.swagger.v3.oas.annotations.Parameter;
19 import io.swagger.v3.oas.annotations.tags.Tag; 21 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -24,10 +26,13 @@ import org.springframework.web.bind.annotation.RequestParam; @@ -24,10 +26,13 @@ import org.springframework.web.bind.annotation.RequestParam;
24 import org.springframework.web.bind.annotation.RestController; 26 import org.springframework.web.bind.annotation.RestController;
25 27
26 import javax.annotation.Resource; 28 import javax.annotation.Resource;
  29 +import java.time.Duration;
27 import java.util.Collections; 30 import java.util.Collections;
28 import java.util.List; 31 import java.util.List;
29 32
  33 +import static cn.hutool.core.util.ObjectUtil.defaultIfNull;
30 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 34 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  35 +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
31 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; 36 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
32 37
33 @Tag(name = "用户 APP - 拼团活动") 38 @Tag(name = "用户 APP - 拼团活动")
@@ -36,24 +41,40 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @@ -36,24 +41,40 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
36 @Validated 41 @Validated
37 public class AppCombinationActivityController { 42 public class AppCombinationActivityController {
38 43
  44 + /**
  45 + * {@link AppCombinationActivityRespVO} 缓存,通过它异步刷新 {@link #getCombinationActivityList0(Integer)} 所要的首页数据
  46 + */
  47 + private final LoadingCache<Integer, List<AppCombinationActivityRespVO>> combinationActivityListCache = buildAsyncReloadingCache(Duration.ofSeconds(10L),
  48 + new CacheLoader<Integer, List<AppCombinationActivityRespVO>>() {
  49 +
  50 + @Override
  51 + public List<AppCombinationActivityRespVO> load(Integer count) {
  52 + return getCombinationActivityList0(count);
  53 + }
  54 +
  55 + });
  56 +
39 @Resource 57 @Resource
40 private CombinationActivityService activityService; 58 private CombinationActivityService activityService;
41 @Resource 59 @Resource
42 private ProductSpuApi spuApi; 60 private ProductSpuApi spuApi;
43 61
44 - // TODO 芋艿:增加 Spring Cache  
45 @GetMapping("/list") 62 @GetMapping("/list")
46 @Operation(summary = "获得拼团活动列表", description = "用于小程序首页") 63 @Operation(summary = "获得拼团活动列表", description = "用于小程序首页")
47 @Parameter(name = "count", description = "需要展示的数量", example = "6") 64 @Parameter(name = "count", description = "需要展示的数量", example = "6")
48 public CommonResult<List<AppCombinationActivityRespVO>> getCombinationActivityList( 65 public CommonResult<List<AppCombinationActivityRespVO>> getCombinationActivityList(
49 @RequestParam(name = "count", defaultValue = "6") Integer count) { 66 @RequestParam(name = "count", defaultValue = "6") Integer count) {
50 - List<CombinationActivityDO> list = activityService.getCombinationActivityListByCount(6); 67 + return success(combinationActivityListCache.getUnchecked(count));
  68 + }
  69 +
  70 + private List<AppCombinationActivityRespVO> getCombinationActivityList0(Integer count) {
  71 + List<CombinationActivityDO> list = activityService.getCombinationActivityListByCount(defaultIfNull(count, 6));
51 if (CollUtil.isEmpty(list)) { 72 if (CollUtil.isEmpty(list)) {
52 - return success(Collections.emptyList()); 73 + return Collections.emptyList();
53 } 74 }
54 // 拼接返回 75 // 拼接返回
55 List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(list, CombinationActivityDO::getSpuId)); 76 List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(list, CombinationActivityDO::getSpuId));
56 - return success(CombinationActivityConvert.INSTANCE.convertAppList(list, spuList)); 77 + return CombinationActivityConvert.INSTANCE.convertAppList(list, spuList);
57 } 78 }
58 79
59 @GetMapping("/page") 80 @GetMapping("/page")
@@ -75,7 +96,7 @@ public class AppCombinationActivityController { @@ -75,7 +96,7 @@ public class AppCombinationActivityController {
75 // 1、获取活动 96 // 1、获取活动
76 CombinationActivityDO combinationActivity = activityService.getCombinationActivity(id); 97 CombinationActivityDO combinationActivity = activityService.getCombinationActivity(id);
77 if (combinationActivity == null 98 if (combinationActivity == null
78 - || ObjectUtil.equal(combinationActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { 99 + || ObjectUtil.equal(combinationActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
79 return success(null); 100 return success(null);
80 } 101 }
81 // 2、获取活动商品 102 // 2、获取活动商品
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationRecordController.java
1 package cn.iocoder.yudao.module.promotion.controller.app.combination; 1 package cn.iocoder.yudao.module.promotion.controller.app.combination;
2 2
  3 +import cn.hutool.core.util.ObjectUtil;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; 5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordDetailRespVO; 6 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordDetailRespVO;
6 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordRespVO; 7 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordRespVO;
7 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordSummaryRespVO; 8 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordSummaryRespVO;
  9 +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
  10 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
  11 +import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
8 import io.swagger.v3.oas.annotations.Operation; 12 import io.swagger.v3.oas.annotations.Operation;
9 import io.swagger.v3.oas.annotations.Parameter; 13 import io.swagger.v3.oas.annotations.Parameter;
  14 +import io.swagger.v3.oas.annotations.Parameters;
10 import io.swagger.v3.oas.annotations.tags.Tag; 15 import io.swagger.v3.oas.annotations.tags.Tag;
11 import org.springframework.validation.annotation.Validated; 16 import org.springframework.validation.annotation.Validated;
12 import org.springframework.web.bind.annotation.GetMapping; 17 import org.springframework.web.bind.annotation.GetMapping;
@@ -14,13 +19,14 @@ import org.springframework.web.bind.annotation.RequestMapping; @@ -14,13 +19,14 @@ import org.springframework.web.bind.annotation.RequestMapping;
14 import org.springframework.web.bind.annotation.RequestParam; 19 import org.springframework.web.bind.annotation.RequestParam;
15 import org.springframework.web.bind.annotation.RestController; 20 import org.springframework.web.bind.annotation.RestController;
16 21
  22 +import javax.annotation.Resource;
17 import javax.validation.constraints.Max; 23 import javax.validation.constraints.Max;
18 -import java.time.Duration;  
19 -import java.time.LocalDateTime;  
20 -import java.util.ArrayList; 24 +import java.util.Collections;
21 import java.util.List; 25 import java.util.List;
22 26
23 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 27 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  28 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  29 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
24 30
25 @Tag(name = "用户 APP - 拼团活动") 31 @Tag(name = "用户 APP - 拼团活动")
26 @RestController 32 @RestController
@@ -28,81 +34,78 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -28,81 +34,78 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
28 @Validated 34 @Validated
29 public class AppCombinationRecordController { 35 public class AppCombinationRecordController {
30 36
  37 + @Resource
  38 + private CombinationRecordService combinationRecordService;
  39 +
31 @GetMapping("/get-summary") 40 @GetMapping("/get-summary")
32 @Operation(summary = "获得拼团记录的概要信息", description = "用于小程序首页") 41 @Operation(summary = "获得拼团记录的概要信息", description = "用于小程序首页")
33 // TODO 芋艿:增加 @Cache 缓存,1 分钟过期 42 // TODO 芋艿:增加 @Cache 缓存,1 分钟过期
34 public CommonResult<AppCombinationRecordSummaryRespVO> getCombinationRecordSummary() { 43 public CommonResult<AppCombinationRecordSummaryRespVO> getCombinationRecordSummary() {
  44 + // 获取所有拼团记录
  45 + Long count = combinationRecordService.getRecordsCount();
35 AppCombinationRecordSummaryRespVO summary = new AppCombinationRecordSummaryRespVO(); 46 AppCombinationRecordSummaryRespVO summary = new AppCombinationRecordSummaryRespVO();
36 - summary.setUserCount(1024);  
37 - summary.setAvatars(new ArrayList<>());  
38 - summary.getAvatars().add("https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLjFK35Wvia9lJKHoXfQuHhk0qZbvpPNxrAiaEKF7aL2k4I8kuqrdTWwliamdPHeyAA7DjAg725X2GIQ/132");  
39 - summary.getAvatars().add("https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTK1pXgdj5DvBMwrbe8v3tFibSWeQATEsAibt3fllD8XwJ460P2r6KS3WCQvDefuv1bVpDhNCle6CTCA/132");  
40 - summary.getAvatars().add("https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTL7KRGHBE62N0awFyBesmmxiaCicf1fJ7E7UCh6zA8GWlT1QC1zT01gG4OxI7BWDESkdPZ5o7tno4hA/132");  
41 - summary.getAvatars().add("https://thirdwx.qlogo.cn/mmopen/vi_32/ouwtwJycbic2JrCoZjETict0klxd1uRuicRneKk00ewMcCClxVcVHQT91Sh9MJGtwibf1fOicD1WpwSP4icJM6eQq1AA/132");  
42 - summary.getAvatars().add("https://thirdwx.qlogo.cn/mmopen/vi_32/RpUrhwens58qc99OcGs993xL4M5QPOe05ekqF9Eia440kRicAlicicIdQWicHBmy2bzLgHzHguWEzHHxnIgeictL7bLA/132");  
43 - summary.getAvatars().add("https://thirdwx.qlogo.cn/mmopen/vi_32/S4tfqmxc8GZGsKc1K4mnhpvtG16gtMrLnTQfDibhr7jJich9LRI5RQKZDoqEjZM3azMib5nic7F4ZXKMEgYyLO08KA/132");  
44 - summary.getAvatars().add("https://static.iocoder.cn/mall/132.jpeg"); 47 + if (count == null || count == 0L) {
  48 + summary.setAvatars(Collections.emptyList());
  49 + summary.setUserCount(count);
  50 + return success(summary);
  51 + }
  52 +
  53 + summary.setUserCount(count);
  54 + // TODO 只返回最近的 7 个
  55 + int num = 7;
  56 + summary.setAvatars(convertList(combinationRecordService.getLatestRecordList(num), CombinationRecordDO::getAvatar));
45 return success(summary); 57 return success(summary);
46 } 58 }
47 59
48 @GetMapping("/get-head-list") 60 @GetMapping("/get-head-list")
49 @Operation(summary = "获得最近 n 条拼团记录(团长发起的)") 61 @Operation(summary = "获得最近 n 条拼团记录(团长发起的)")
50 - // TODO @芋艿:注解要补全 62 + @Parameters({
  63 + @Parameter(name = "activityId", description = "拼团活动编号"),
  64 + @Parameter(name = "status", description = "状态"),
  65 + @Parameter(name = "count", description = "数量")
  66 + })
51 public CommonResult<List<AppCombinationRecordRespVO>> getHeadCombinationRecordList( 67 public CommonResult<List<AppCombinationRecordRespVO>> getHeadCombinationRecordList(
52 @RequestParam(value = "activityId", required = false) Long activityId, 68 @RequestParam(value = "activityId", required = false) Long activityId,
53 @RequestParam("status") Integer status, 69 @RequestParam("status") Integer status,
54 @RequestParam(value = "count", defaultValue = "20") @Max(20) Integer count) { 70 @RequestParam(value = "count", defaultValue = "20") @Max(20) Integer count) {
55 - List<AppCombinationRecordRespVO> list = new ArrayList<>();  
56 - for (int i = 1; i <= count; i++) {  
57 - AppCombinationRecordRespVO record = new AppCombinationRecordRespVO();  
58 - record.setId((long) i);  
59 - record.setNickname("用户" + i);  
60 - record.setAvatar("头像" + i);  
61 - record.setExpireTime(LocalDateTime.now());  
62 - record.setUserSize(10);  
63 - record.setUserCount(i);  
64 - record.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");  
65 - record.setActivityId(1L);  
66 - record.setSpuName("活动:" + i);  
67 - list.add(record);  
68 - }  
69 - return success(list); 71 + return success(CombinationActivityConvert.INSTANCE.convertList3(
  72 + combinationRecordService.getRecordListWithHead(activityId, status, count)));
70 } 73 }
71 74
72 @GetMapping("/get-detail") 75 @GetMapping("/get-detail")
73 @Operation(summary = "获得拼团记录明细") 76 @Operation(summary = "获得拼团记录明细")
74 @Parameter(name = "id", description = "拼团记录编号", required = true, example = "1024") 77 @Parameter(name = "id", description = "拼团记录编号", required = true, example = "1024")
75 public CommonResult<AppCombinationRecordDetailRespVO> getCombinationRecordDetail(@RequestParam("id") Long id) { 78 public CommonResult<AppCombinationRecordDetailRespVO> getCombinationRecordDetail(@RequestParam("id") Long id) {
  79 + // 1、查询这条记录
  80 + CombinationRecordDO record = combinationRecordService.getRecordById(id);
  81 + if (record == null) {
  82 + return success(null);
  83 + }
  84 +
76 AppCombinationRecordDetailRespVO detail = new AppCombinationRecordDetailRespVO(); 85 AppCombinationRecordDetailRespVO detail = new AppCombinationRecordDetailRespVO();
77 - // 团长  
78 - AppCombinationRecordRespVO headRecord = new AppCombinationRecordRespVO();  
79 - headRecord.setId(1L);  
80 - headRecord.setNickname("用户" + 1);  
81 - headRecord.setAvatar("头像" + 1);  
82 - headRecord.setExpireTime(LocalDateTimeUtils.addTime(Duration.ofDays(1)));  
83 - headRecord.setUserSize(10);  
84 - headRecord.setUserCount(3);  
85 - headRecord.setStatus(1);  
86 - headRecord.setActivityId(10L);  
87 - headRecord.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");  
88 - headRecord.setCombinationPrice(100);  
89 - detail.setHeadRecord(headRecord);  
90 - // 团员  
91 - List<AppCombinationRecordRespVO> list = new ArrayList<>();  
92 - for (int i = 1; i <= 2; i++) {  
93 - AppCombinationRecordRespVO record = new AppCombinationRecordRespVO();  
94 - record.setId((long) i);  
95 - record.setNickname("用户" + i);  
96 - record.setAvatar("头像" + i);  
97 - record.setExpireTime(LocalDateTime.now());  
98 - record.setUserSize(10);  
99 - record.setUserCount(i);  
100 - record.setStatus(1);  
101 - list.add(record); 86 + List<CombinationRecordDO> records;
  87 + // 2、判断是否为团长
  88 + if (record.getHeadId() == null) {
  89 + detail.setHeadRecord(CombinationActivityConvert.INSTANCE.convert(record));
  90 + // 2.1、查找团员拼团记录
  91 + records = combinationRecordService.getRecordListByHeadId(record.getId());
  92 + } else {
  93 + // 2.2、查找团长拼团记录
  94 + CombinationRecordDO headRecord = combinationRecordService.getRecordById(record.getHeadId());
  95 + if (headRecord == null) {
  96 + return success(null);
  97 + }
  98 +
  99 + detail.setHeadRecord(CombinationActivityConvert.INSTANCE.convert(headRecord));
  100 + // 2.3、查找团员拼团记录
  101 + records = combinationRecordService.getRecordListByHeadId(headRecord.getId());
  102 +
102 } 103 }
103 - detail.setMemberRecords(list);  
104 - // 订单编号  
105 - detail.setOrderId(100L); 104 + detail.setMemberRecords(CombinationActivityConvert.INSTANCE.convertList3(records));
  105 +
  106 + // 3、获取当前用户参团记录订单编号
  107 + CombinationRecordDO userRecord = CollectionUtils.findFirst(records, r -> ObjectUtil.equal(r.getUserId(), getLoginUserId()));
  108 + detail.setOrderId(userRecord == null ? null : userRecord.getOrderId()); // 如果没参团,返回 null
106 return success(detail); 109 return success(detail);
107 } 110 }
108 111
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordDetailRespVO.java
@@ -16,7 +16,6 @@ public class AppCombinationRecordDetailRespVO { @@ -16,7 +16,6 @@ public class AppCombinationRecordDetailRespVO {
16 private List<AppCombinationRecordRespVO> memberRecords; 16 private List<AppCombinationRecordRespVO> memberRecords;
17 17
18 @Schema(description = "当前用户参团记录对应的订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 18 @Schema(description = "当前用户参团记录对应的订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
19 - // 如果没参团,返回 null  
20 private Long orderId; 19 private Long orderId;
21 20
22 } 21 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordSummaryRespVO.java
@@ -10,9 +10,9 @@ import java.util.List; @@ -10,9 +10,9 @@ import java.util.List;
10 public class AppCombinationRecordSummaryRespVO { 10 public class AppCombinationRecordSummaryRespVO {
11 11
12 @Schema(description = "拼团用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 12 @Schema(description = "拼团用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
13 - private Integer userCount; 13 + private Long userCount;
14 14
15 - @Schema(description = "拼团用户头像列表", requiredMode = Schema.RequiredMode.REQUIRED) // 只返回最近的 7 个 15 + @Schema(description = "拼团用户头像列表", requiredMode = Schema.RequiredMode.REQUIRED)
16 private List<String> avatars; 16 private List<String> avatars;
17 17
18 } 18 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainRecordConvert.java
@@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityD @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityD
13 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO; 13 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO;
14 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; 14 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
15 import org.mapstruct.Mapper; 15 import org.mapstruct.Mapper;
  16 +import org.mapstruct.Mapping;
16 import org.mapstruct.factory.Mappers; 17 import org.mapstruct.factory.Mappers;
17 18
18 import java.util.List; 19 import java.util.List;
@@ -83,6 +84,9 @@ public interface BargainRecordConvert { @@ -83,6 +84,9 @@ public interface BargainRecordConvert {
83 return summary; 84 return summary;
84 } 85 }
85 86
86 - AppBargainRecordDetailRespVO convert02(BargainRecordDO record, Integer helpAction); 87 + @Mapping(source = "record.id", target = "id")
  88 + @Mapping(source = "record.userId", target = "userId")
  89 + @Mapping(source = "record.status", target = "status")
  90 + AppBargainRecordDetailRespVO convert02(BargainRecordDO record, Integer helpAction, TradeOrderRespDTO order);
87 91
88 } 92 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
@@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; @@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
7 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 7 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
8 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 8 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
9 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 9 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
10 -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;  
11 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; 10 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
12 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO; 11 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO;
13 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; 12 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@@ -15,6 +14,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product @@ -15,6 +14,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product
15 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO; 14 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO;
16 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityDetailRespVO; 15 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityDetailRespVO;
17 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityRespVO; 16 import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityRespVO;
  17 +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordRespVO;
18 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; 18 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
19 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; 19 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
20 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; 20 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
@@ -108,8 +108,6 @@ public interface CombinationActivityConvert { @@ -108,8 +108,6 @@ public interface CombinationActivityConvert {
108 .setPicUrl(sku.getPicUrl()); 108 .setPicUrl(sku.getPicUrl());
109 } 109 }
110 110
111 - List<CombinationRecordRespDTO> convert(List<CombinationRecordDO> bean);  
112 -  
113 List<AppCombinationActivityRespVO> convertAppList(List<CombinationActivityDO> list); 111 List<AppCombinationActivityRespVO> convertAppList(List<CombinationActivityDO> list);
114 112
115 default List<AppCombinationActivityRespVO> convertAppList(List<CombinationActivityDO> list, List<ProductSpuRespDTO> spuList) { 113 default List<AppCombinationActivityRespVO> convertAppList(List<CombinationActivityDO> list, List<ProductSpuRespDTO> spuList) {
@@ -144,4 +142,8 @@ public interface CombinationActivityConvert { @@ -144,4 +142,8 @@ public interface CombinationActivityConvert {
144 return convert2(combinationActivity).setProducts(convertList1(products)); 142 return convert2(combinationActivity).setProducts(convertList1(products));
145 } 143 }
146 144
  145 + List<AppCombinationRecordRespVO> convertList3(List<CombinationRecordDO> records);
  146 +
  147 + AppCombinationRecordRespVO convert(CombinationRecordDO record);
  148 +
147 } 149 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java
@@ -83,4 +83,11 @@ public interface BargainActivityMapper extends BaseMapperX&lt;BargainActivityDO&gt; { @@ -83,4 +83,11 @@ public interface BargainActivityMapper extends BaseMapperX&lt;BargainActivityDO&gt; {
83 .last("LIMIT " + count)); 83 .last("LIMIT " + count));
84 } 84 }
85 85
  86 + default BargainActivityDO selectOne(Long spuId) {
  87 + return selectOne(new LambdaQueryWrapperX<BargainActivityDO>()
  88 + .eq(BargainActivityDO::getSpuId, spuId)
  89 + .orderByDesc(BargainActivityDO::getCreateTime)
  90 + , false);
  91 + }
  92 +
86 } 93 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainRecordMapper.java
@@ -42,6 +42,14 @@ public interface BargainRecordMapper extends BaseMapperX&lt;BargainRecordDO&gt; { @@ -42,6 +42,14 @@ public interface BargainRecordMapper extends BaseMapperX&lt;BargainRecordDO&gt; {
42 .eq(BargainRecordDO::getStatus, status)); 42 .eq(BargainRecordDO::getStatus, status));
43 } 43 }
44 44
  45 + default BargainRecordDO selectLastByUserIdAndActivityId(Long userId, Long activityId) {
  46 + return selectOne(new LambdaQueryWrapper<>(BargainRecordDO.class)
  47 + .eq(BargainRecordDO::getUserId, userId)
  48 + .eq(BargainRecordDO::getActivityId, activityId)
  49 + .orderByDesc(BargainRecordDO::getId)
  50 + .last("LIMIT 1"));
  51 + }
  52 +
45 default Long selectCountByUserIdAndActivityIdAndStatus( 53 default Long selectCountByUserIdAndActivityIdAndStatus(
46 Long userId, Long activityId, Integer status) { 54 Long userId, Long activityId, Integer status) {
47 return selectCount(new LambdaQueryWrapper<>(BargainRecordDO.class) 55 return selectCount(new LambdaQueryWrapper<>(BargainRecordDO.class)
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java
@@ -40,4 +40,11 @@ public interface CombinationActivityMapper extends BaseMapperX&lt;CombinationActivi @@ -40,4 +40,11 @@ public interface CombinationActivityMapper extends BaseMapperX&lt;CombinationActivi
40 .last("LIMIT " + count)); 40 .last("LIMIT " + count));
41 } 41 }
42 42
  43 + default CombinationActivityDO selectOne(Long spuId) {
  44 + return selectOne(new LambdaQueryWrapperX<CombinationActivityDO>()
  45 + .eq(CombinationActivityDO::getSpuId, spuId)
  46 + .orderByDesc(CombinationActivityDO::getCreateTime)
  47 + , false);
  48 + }
  49 +
43 } 50 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java
@@ -29,6 +29,7 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO @@ -29,6 +29,7 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO
29 .eq(CombinationRecordDO::getUserId, userId) 29 .eq(CombinationRecordDO::getUserId, userId)
30 .eq(CombinationRecordDO::getStatus, status)); 30 .eq(CombinationRecordDO::getStatus, status));
31 } 31 }
  32 +
32 /** 33 /**
33 * 查询拼团记录 34 * 查询拼团记录
34 * 35 *
@@ -47,10 +48,6 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO @@ -47,10 +48,6 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO
47 .eq(CombinationRecordDO::getStatus, status)); 48 .eq(CombinationRecordDO::getStatus, status));
48 } 49 }
49 50
50 - default List<CombinationRecordDO> selectListByStatus(Integer status) {  
51 - return selectList(CombinationRecordDO::getStatus, status);  
52 - }  
53 -  
54 /** 51 /**
55 * 查询拼团记录 52 * 查询拼团记录
56 * 53 *
@@ -63,4 +60,34 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO @@ -63,4 +60,34 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO
63 .eq(CombinationRecordDO::getUserId, userId) 60 .eq(CombinationRecordDO::getUserId, userId)
64 .eq(CombinationRecordDO::getActivityId, activityId)); 61 .eq(CombinationRecordDO::getActivityId, activityId));
65 } 62 }
  63 +
  64 + /**
  65 + * 获取最近的 count 条数据
  66 + *
  67 + * @param count 数量
  68 + * @return 拼团记录列表
  69 + */
  70 + default List<CombinationRecordDO> selectLatestList(int count) {
  71 + return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
  72 + .orderByDesc(CombinationRecordDO::getCreateTime)
  73 + .last("LIMIT " + count));
  74 + }
  75 +
  76 + /**
  77 + * 获得最近 count 条拼团记录(团长发起的)
  78 + *
  79 + * @param activityId 拼团活动编号
  80 + * @param status 记录状态
  81 + * @param count 数量
  82 + * @return 拼团记录列表
  83 + */
  84 + default List<CombinationRecordDO> selectList(Long activityId, Integer status, Integer count) {
  85 + return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
  86 + .eqIfPresent(CombinationRecordDO::getActivityId, activityId)
  87 + .eqIfPresent(CombinationRecordDO::getStatus, status)
  88 + .eq(CombinationRecordDO::getHeadId, null) // TODO 团长的 headId 是不是 null 还是自己的记录编号来着?
  89 + .orderByDesc(CombinationRecordDO::getCreateTime)
  90 + .last("LIMIT " + count));
  91 + }
  92 +
66 } 93 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
@@ -56,4 +56,11 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; { @@ -56,4 +56,11 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; {
56 .apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0")); 56 .apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0"));
57 } 57 }
58 58
  59 + default SeckillActivityDO selectOne(Long spuId) {
  60 + return selectOne(new LambdaQueryWrapperX<SeckillActivityDO>()
  61 + .eq(SeckillActivityDO::getSpuId, spuId)
  62 + .orderByDesc(SeckillActivityDO::getCreateTime)
  63 + , false);
  64 + }
  65 +
59 } 66 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java
@@ -98,4 +98,12 @@ public interface BargainActivityService { @@ -98,4 +98,12 @@ public interface BargainActivityService {
98 */ 98 */
99 List<BargainActivityDO> getBargainActivityListByCount(Integer count); 99 List<BargainActivityDO> getBargainActivityListByCount(Integer count);
100 100
  101 + /**
  102 + * 获取指定 spu 编号的活动
  103 + *
  104 + * @param spuId spu 编号
  105 + * @return 砍价活动
  106 + */
  107 + BargainActivityDO getBargainActivityBySpuId(Long spuId);
  108 +
101 } 109 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java
@@ -175,4 +175,9 @@ public class BargainActivityServiceImpl implements BargainActivityService { @@ -175,4 +175,9 @@ public class BargainActivityServiceImpl implements BargainActivityService {
175 return bargainActivityMapper.selectList(count, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()); 175 return bargainActivityMapper.selectList(count, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
176 } 176 }
177 177
  178 + @Override
  179 + public BargainActivityDO getBargainActivityBySpuId(Long spuId) {
  180 + return bargainActivityMapper.selectOne(spuId);
  181 + }
  182 +
178 } 183 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainRecordService.java
@@ -74,15 +74,13 @@ public interface BargainRecordService { @@ -74,15 +74,13 @@ public interface BargainRecordService {
74 BargainRecordDO getBargainRecord(Long id); 74 BargainRecordDO getBargainRecord(Long id);
75 75
76 /** 76 /**
77 - * 获得用户当前正在【砍价中】+ 指定活动的砍价记录  
78 - *  
79 - * 因为一个用户,在一个砍价活动,【砍价中】只存在一条 77 + * 获得用户在当前砍价活动中的最后一条砍价记录
80 * 78 *
81 * @param userId 用户编号 79 * @param userId 用户编号
82 * @param activityId 砍价记录编号 80 * @param activityId 砍价记录编号
83 * @return 砍价记录 81 * @return 砍价记录
84 */ 82 */
85 - BargainRecordDO getInProgressBargainRecord(Long userId, Long activityId); 83 + BargainRecordDO getLastBargainRecord(Long userId, Long activityId);
86 84
87 /** 85 /**
88 * 获得砍价人数 Map 86 * 获得砍价人数 Map
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainRecordServiceImpl.java
@@ -115,10 +115,8 @@ public class BargainRecordServiceImpl implements BargainRecordService { @@ -115,10 +115,8 @@ public class BargainRecordServiceImpl implements BargainRecordService {
115 } 115 }
116 116
117 @Override 117 @Override
118 - public BargainRecordDO getInProgressBargainRecord(Long userId, Long activityId) {  
119 - List<BargainRecordDO> list = bargainRecordMapper.selectListByUserIdAndActivityIdAndStatus(  
120 - userId, activityId, BargainRecordStatusEnum.IN_PROGRESS.getStatus());  
121 - return CollUtil.getFirst(list); 118 + public BargainRecordDO getLastBargainRecord(Long userId, Long activityId) {
  119 + return bargainRecordMapper.selectLastByUserIdAndActivityId(userId, activityId);
122 } 120 }
123 121
124 @Override 122 @Override
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
@@ -100,4 +100,21 @@ public interface CombinationActivityService { @@ -100,4 +100,21 @@ public interface CombinationActivityService {
100 */ 100 */
101 PageResult<CombinationActivityDO> getCombinationActivityPage(PageParam pageParam); 101 PageResult<CombinationActivityDO> getCombinationActivityPage(PageParam pageParam);
102 102
  103 + /**
  104 + * 获取指定活动指定 sku 编号的商品
  105 + *
  106 + * @param activityId 活动编号
  107 + * @param skuId sku 编号
  108 + * @return 活动商品信息
  109 + */
  110 + CombinationProductDO selectByActivityIdAndSkuId(Long activityId, Long skuId);
  111 +
  112 + /**
  113 + * 获取指定 spu 编号的活动
  114 + *
  115 + * @param spuId spu 编号
  116 + * @return 拼团活动
  117 + */
  118 + CombinationActivityDO getCombinationActivityBySpuId(Long spuId);
  119 +
103 } 120 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
@@ -216,4 +216,16 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -216,4 +216,16 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
216 return combinationActivityMapper.selectPage(pageParam, CommonStatusEnum.ENABLE.getStatus()); 216 return combinationActivityMapper.selectPage(pageParam, CommonStatusEnum.ENABLE.getStatus());
217 } 217 }
218 218
  219 + @Override
  220 + public CombinationProductDO selectByActivityIdAndSkuId(Long activityId, Long skuId) {
  221 + return combinationProductMapper.selectOne(
  222 + CombinationProductDO::getActivityId, activityId,
  223 + CombinationProductDO::getSkuId, skuId);
  224 + }
  225 +
  226 + @Override
  227 + public CombinationActivityDO getCombinationActivityBySpuId(Long spuId) {
  228 + return combinationActivityMapper.selectOne(spuId);
  229 + }
  230 +
219 } 231 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
1 package cn.iocoder.yudao.module.promotion.service.combination; 1 package cn.iocoder.yudao.module.promotion.service.combination;
2 2
  3 +import cn.iocoder.yudao.framework.common.core.KeyValue;
3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 4 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
  5 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO;
  6 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
4 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
5 9
6 import java.time.LocalDateTime; 10 import java.time.LocalDateTime;
@@ -16,8 +20,8 @@ public interface CombinationRecordService { @@ -16,8 +20,8 @@ public interface CombinationRecordService {
16 /** 20 /**
17 * 更新拼团状态 21 * 更新拼团状态
18 * 22 *
19 - * @param status 状态  
20 - * @param userId 用户编号 23 + * @param status 状态
  24 + * @param userId 用户编号
21 * @param orderId 订单编号 25 * @param orderId 订单编号
22 */ 26 */
23 void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId); 27 void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId);
@@ -30,8 +34,9 @@ public interface CombinationRecordService { @@ -30,8 +34,9 @@ public interface CombinationRecordService {
30 * @param userId 用户编号 34 * @param userId 用户编号
31 * @param skuId sku 编号 35 * @param skuId sku 编号
32 * @param count 数量 36 * @param count 数量
  37 + * @return 返回拼团活动和拼团活动商品
33 */ 38 */
34 - void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count); 39 + KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count);
35 40
36 /** 41 /**
37 * 创建拼团记录 42 * 创建拼团记录
@@ -43,9 +48,9 @@ public interface CombinationRecordService { @@ -43,9 +48,9 @@ public interface CombinationRecordService {
43 /** 48 /**
44 * 更新拼团状态和开始时间 49 * 更新拼团状态和开始时间
45 * 50 *
46 - * @param status 状态  
47 - * @param userId 用户编号  
48 - * @param orderId 订单编号 51 + * @param status 状态
  52 + * @param userId 用户编号
  53 + * @param orderId 订单编号
49 * @param startTime 开始时间 54 * @param startTime 开始时间
50 */ 55 */
51 void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime); 56 void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime);
@@ -68,4 +73,58 @@ public interface CombinationRecordService { @@ -68,4 +73,58 @@ public interface CombinationRecordService {
68 */ 73 */
69 List<CombinationRecordDO> getRecordListByUserIdAndActivityId(Long userId, Long activityId); 74 List<CombinationRecordDO> getRecordListByUserIdAndActivityId(Long userId, Long activityId);
70 75
  76 + /**
  77 + * 【下单前】校验是否满足拼团活动条件
  78 + *
  79 + * 如果校验失败,则抛出业务异常
  80 + *
  81 + * @param activityId 活动编号
  82 + * @param userId 用户编号
  83 + * @param skuId sku 编号
  84 + * @param count 数量
  85 + * @return 拼团信息
  86 + */
  87 + CombinationValidateJoinRespDTO validateJoinCombination(Long activityId, Long userId, Long skuId, Integer count);
  88 +
  89 + /**
  90 + * 获取所有拼团记录数
  91 + *
  92 + * @return 记录数
  93 + */
  94 + Long getRecordsCount();
  95 +
  96 + /**
  97 + * 获取最近的 count 条拼团记录
  98 + *
  99 + * @param count 限制数量
  100 + * @return 拼团记录列表
  101 + */
  102 + List<CombinationRecordDO> getLatestRecordList(int count);
  103 +
  104 + /**
  105 + * 获得最近 n 条拼团记录(团长发起的)
  106 + *
  107 + * @param activityId 拼团活动编号
  108 + * @param status 状态
  109 + * @param count 数量
  110 + * @return 拼团记录列表
  111 + */
  112 + List<CombinationRecordDO> getRecordListWithHead(Long activityId, Integer status, Integer count);
  113 +
  114 + /**
  115 + * 获取指定编号的拼团记录
  116 + *
  117 + * @param id 拼团记录编号
  118 + * @return 拼团记录
  119 + */
  120 + CombinationRecordDO getRecordById(Long id);
  121 +
  122 + /**
  123 + * 获取指定团长编号的拼团记录
  124 + *
  125 + * @param headId 团长编号
  126 + * @return 拼团记录列表
  127 + */
  128 + List<CombinationRecordDO> getRecordListByHeadId(Long headId);
  129 +
71 } 130 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.combination; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.combination;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
  5 +import cn.iocoder.yudao.framework.common.core.KeyValue;
5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 import cn.iocoder.yudao.module.member.api.user.MemberUserApi; 7 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
7 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; 8 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
@@ -10,8 +11,10 @@ import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; @@ -10,8 +11,10 @@ import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
10 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; 11 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
11 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 12 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
12 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 13 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
  14 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO;
13 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; 15 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
14 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; 16 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
  17 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
15 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; 18 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
16 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper; 19 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
17 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; 20 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
@@ -62,35 +65,35 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -62,35 +65,35 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
62 @Transactional(rollbackFor = Exception.class) 65 @Transactional(rollbackFor = Exception.class)
63 public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) { 66 public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
64 // 校验拼团是否存在 67 // 校验拼团是否存在
65 - CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId); 68 + CombinationRecordDO record = validateCombinationRecord(userId, orderId);
66 69
67 // 更新状态 70 // 更新状态
68 - recordDO.setStatus(status);  
69 - recordMapper.updateById(recordDO); 71 + record.setStatus(status);
  72 + recordMapper.updateById(record);
70 } 73 }
71 74
72 @Override 75 @Override
73 @Transactional(rollbackFor = Exception.class) 76 @Transactional(rollbackFor = Exception.class)
74 public void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime) { 77 public void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime) {
75 - CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId); 78 + CombinationRecordDO record = validateCombinationRecord(userId, orderId);
76 // 更新状态 79 // 更新状态
77 - recordDO.setStatus(status); 80 + record.setStatus(status);
78 // 更新开始时间 81 // 更新开始时间
79 - recordDO.setStartTime(startTime);  
80 - recordMapper.updateById(recordDO); 82 + record.setStartTime(startTime);
  83 + recordMapper.updateById(record);
81 84
82 // 更新拼团参入人数 85 // 更新拼团参入人数
83 - List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), status);  
84 - if (CollUtil.isNotEmpty(recordDOs)) {  
85 - recordDOs.forEach(item -> {  
86 - item.setUserCount(recordDOs.size()); 86 + List<CombinationRecordDO> records = recordMapper.selectListByHeadIdAndStatus(record.getHeadId(), status);
  87 + if (CollUtil.isNotEmpty(records)) {
  88 + records.forEach(item -> {
  89 + item.setUserCount(records.size());
87 // 校验拼团是否满足要求 90 // 校验拼团是否满足要求
88 - if (ObjectUtil.equal(recordDOs.size(), recordDO.getUserSize())) { 91 + if (ObjectUtil.equal(records.size(), record.getUserSize())) {
89 item.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus()); 92 item.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus());
90 } 93 }
91 }); 94 });
92 } 95 }
93 - recordMapper.updateBatch(recordDOs); 96 + recordMapper.updateBatch(records);
94 } 97 }
95 98
96 private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) { 99 private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) {
@@ -104,7 +107,8 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -104,7 +107,8 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
104 107
105 // TODO @芋艿:在详细预览下; 108 // TODO @芋艿:在详细预览下;
106 @Override 109 @Override
107 - public void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count) { 110 + public KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord(
  111 + Long activityId, Long userId, Long skuId, Integer count) {
108 // 1.1 校验拼团活动是否存在 112 // 1.1 校验拼团活动是否存在
109 CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId); 113 CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId);
110 // 1.2 校验活动是否开启 114 // 1.2 校验活动是否开启
@@ -115,10 +119,24 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -115,10 +119,24 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
115 if (count > activity.getSingleLimitCount()) { 119 if (count > activity.getSingleLimitCount()) {
116 throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED); 120 throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
117 } 121 }
  122 + // 2.1、校验活动商品是否存在
  123 + CombinationProductDO product = combinationActivityService.selectByActivityIdAndSkuId(activityId, skuId);
  124 + if (product == null) {
  125 + throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
  126 + }
  127 + // 2.2、校验 sku 是否存在
  128 + ProductSkuRespDTO sku = productSkuApi.getSku(skuId);
  129 + if (sku == null) {
  130 + throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
  131 + }
  132 + // 2.3、 校验库存是否充足
  133 + if (count > sku.getStock()) {
  134 + throw exception(COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL);
  135 + }
118 // 3、校验是否有拼团记录 136 // 3、校验是否有拼团记录
119 List<CombinationRecordDO> recordList = getRecordListByUserIdAndActivityId(userId, activityId); 137 List<CombinationRecordDO> recordList = getRecordListByUserIdAndActivityId(userId, activityId);
120 if (CollUtil.isEmpty(recordList)) { 138 if (CollUtil.isEmpty(recordList)) {
121 - return; 139 + return new KeyValue<>(activity, product);
122 } 140 }
123 // 4、校验是否超出总限购数量 141 // 4、校验是否超出总限购数量
124 Integer sumValue = getSumValue(convertList(recordList, CombinationRecordDO::getCount, 142 Integer sumValue = getSumValue(convertList(recordList, CombinationRecordDO::getCount,
@@ -129,7 +147,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -129,7 +147,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
129 // 5、校验拼团记录是否存在未支付的订单(如果存在未支付的订单则不允许发起新的拼团) 147 // 5、校验拼团记录是否存在未支付的订单(如果存在未支付的订单则不允许发起新的拼团)
130 CombinationRecordDO record = findFirst(recordList, item -> ObjectUtil.equals(item.getStatus(), null)); 148 CombinationRecordDO record = findFirst(recordList, item -> ObjectUtil.equals(item.getStatus(), null));
131 if (record == null) { 149 if (record == null) {
132 - return; 150 + return new KeyValue<>(activity, product);
133 } 151 }
134 // 5.1、查询关联的订单是否已经支付 152 // 5.1、查询关联的订单是否已经支付
135 // 当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先; 153 // 当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先;
@@ -138,57 +156,45 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -138,57 +156,45 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
138 if (ObjectUtil.equal(orderStatus, TradeOrderStatusEnum.UNPAID.getStatus())) { 156 if (ObjectUtil.equal(orderStatus, TradeOrderStatusEnum.UNPAID.getStatus())) {
139 throw exception(COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID); 157 throw exception(COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID);
140 } 158 }
  159 +
  160 + return new KeyValue<>(activity, product);
141 } 161 }
142 162
143 // TODO 芋艿:在详细 review 下; 163 // TODO 芋艿:在详细 review 下;
144 @Override 164 @Override
145 @Transactional(rollbackFor = Exception.class) 165 @Transactional(rollbackFor = Exception.class)
146 public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) { 166 public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
147 -  
148 - // 1.1、 校验拼团活动  
149 - CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId());  
150 - // 1.2 校验是否超出单次限购数量  
151 - if (reqDTO.getCount() > activity.getSingleLimitCount()) {  
152 - throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);  
153 - }  
154 - // 1.3、校验是否有拼团记录  
155 - List<CombinationRecordDO> records = getRecordListByUserIdAndActivityId(reqDTO.getUserId(), reqDTO.getActivityId());  
156 - if (CollUtil.isEmpty(records)) {  
157 - return;  
158 - }  
159 - // 1.4、校验是否超出总限购数量  
160 - Integer sumValue = getSumValue(convertList(records, CombinationRecordDO::getCount,  
161 - item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), i -> i, Integer::sum);  
162 - if ((sumValue + reqDTO.getCount()) > activity.getTotalLimitCount()) {  
163 - throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);  
164 - }  
165 - // 2、 校验用户是否参加了其它拼团 167 + // 1、校验拼团活动
  168 + KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(
  169 + reqDTO.getActivityId(), reqDTO.getUserId(), reqDTO.getSkuId(), reqDTO.getCount());
  170 + CombinationActivityDO activity = keyValue.getKey();
  171 + // 2、校验用户是否参加了其它拼团
166 List<CombinationRecordDO> recordDOList = recordMapper.selectListByUserIdAndStatus(reqDTO.getUserId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus()); 172 List<CombinationRecordDO> recordDOList = recordMapper.selectListByUserIdAndStatus(reqDTO.getUserId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
167 if (CollUtil.isNotEmpty(recordDOList)) { 173 if (CollUtil.isNotEmpty(recordDOList)) {
168 throw exception(COMBINATION_RECORD_FAILED_HAVE_JOINED); 174 throw exception(COMBINATION_RECORD_FAILED_HAVE_JOINED);
169 } 175 }
170 - // 3、 校验活动是否开启 176 + // 3、校验活动是否开启
171 if (LocalDateTime.now().isAfter(activity.getStartTime())) { 177 if (LocalDateTime.now().isAfter(activity.getStartTime())) {
172 throw exception(COMBINATION_RECORD_FAILED_TIME_NOT_START); 178 throw exception(COMBINATION_RECORD_FAILED_TIME_NOT_START);
173 } 179 }
174 - // 4、 校验当前活动是否过期 180 + // 4、校验当前活动是否过期
175 if (LocalDateTime.now().isAfter(activity.getEndTime())) { 181 if (LocalDateTime.now().isAfter(activity.getEndTime())) {
176 throw exception(COMBINATION_RECORD_FAILED_TIME_END); 182 throw exception(COMBINATION_RECORD_FAILED_TIME_END);
177 } 183 }
178 - // 5、 父拼团是否存在,是否已经满了 184 + // 5、父拼团是否存在,是否已经满了
179 if (reqDTO.getHeadId() != null) { 185 if (reqDTO.getHeadId() != null) {
180 - // 查询进行中的父拼团 186 + // 5.1、查询进行中的父拼团
181 CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus()); 187 CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
182 if (record == null) { 188 if (record == null) {
183 throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS); 189 throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
184 } 190 }
185 - // 校验拼团是否满足要求 191 + // 5.2、校验拼团是否满足要求
186 if (ObjectUtil.equal(record.getUserCount(), record.getUserSize())) { 192 if (ObjectUtil.equal(record.getUserCount(), record.getUserSize())) {
187 throw exception(COMBINATION_RECORD_USER_FULL); 193 throw exception(COMBINATION_RECORD_USER_FULL);
188 } 194 }
189 } 195 }
190 196
191 - // 2. 创建拼团记录 197 + // 6. 创建拼团记录
192 MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId()); 198 MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
193 ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId()); 199 ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
194 ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId()); 200 ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId());
@@ -205,13 +211,38 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -205,13 +211,38 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
205 return recordMapper.selectListByUserIdAndActivityId(userId, activityId); 211 return recordMapper.selectListByUserIdAndActivityId(userId, activityId);
206 } 212 }
207 213
208 - /**  
209 - * APP 端获取开团记录  
210 - *  
211 - * @return 开团记录  
212 - */  
213 - public List<CombinationRecordDO> getRecordListByStatus(Integer status) {  
214 - return recordMapper.selectListByStatus(status); 214 + @Override
  215 + public CombinationValidateJoinRespDTO validateJoinCombination(Long activityId, Long userId, Long skuId, Integer count) {
  216 + KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(activityId, userId, skuId, count);
  217 + return new CombinationValidateJoinRespDTO()
  218 + .setActivityId(keyValue.getKey().getId())
  219 + .setName(keyValue.getKey().getName())
  220 + .setCombinationPrice(keyValue.getValue().getCombinationPrice());
  221 + }
  222 +
  223 + @Override
  224 + public Long getRecordsCount() {
  225 + return recordMapper.selectCount();
  226 + }
  227 +
  228 + @Override
  229 + public List<CombinationRecordDO> getLatestRecordList(int count) {
  230 + return recordMapper.selectLatestList(count);
  231 + }
  232 +
  233 + @Override
  234 + public List<CombinationRecordDO> getRecordListWithHead(Long activityId, Integer status, Integer count) {
  235 + return recordMapper.selectList(activityId, status, count);
  236 + }
  237 +
  238 + @Override
  239 + public CombinationRecordDO getRecordById(Long id) {
  240 + return recordMapper.selectById(id);
  241 + }
  242 +
  243 + @Override
  244 + public List<CombinationRecordDO> getRecordListByHeadId(Long headId) {
  245 + return recordMapper.selectList(CombinationRecordDO::getHeadId, headId);
215 } 246 }
216 247
217 } 248 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
@@ -119,4 +119,12 @@ public interface SeckillActivityService { @@ -119,4 +119,12 @@ public interface SeckillActivityService {
119 */ 119 */
120 SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count); 120 SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count);
121 121
  122 + /**
  123 + * 获取指定 spu 编号的活动
  124 + *
  125 + * @param spuId spu 编号
  126 + * @return 秒杀活动
  127 + */
  128 + SeckillActivityDO getSeckillActivityBySpuId(Long spuId);
  129 +
122 } 130 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
@@ -310,4 +310,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -310,4 +310,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
310 return SeckillActivityConvert.INSTANCE.convert02(activity, product); 310 return SeckillActivityConvert.INSTANCE.convert02(activity, product);
311 } 311 }
312 312
  313 + @Override
  314 + public SeckillActivityDO getSeckillActivityBySpuId(Long spuId) {
  315 + return seckillActivityMapper.selectOne(spuId);
  316 + }
  317 +
313 } 318 }
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java
@@ -20,6 +20,14 @@ public interface TradeOrderApi { @@ -20,6 +20,14 @@ public interface TradeOrderApi {
20 */ 20 */
21 List<TradeOrderRespDTO> getOrderList(Collection<Long> ids); 21 List<TradeOrderRespDTO> getOrderList(Collection<Long> ids);
22 22
  23 + /**
  24 + * 获得订单
  25 + *
  26 + * @param id 订单编号
  27 + * @return 订单
  28 + */
  29 + TradeOrderRespDTO getOrder(Long id);
  30 +
23 // TODO 芋艿:看看是不是可以删除掉; 31 // TODO 芋艿:看看是不是可以删除掉;
24 /** 32 /**
25 * 获取订单状态 33 * 获取订单状态
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java
@@ -16,6 +16,7 @@ public enum TradeOrderOperateTypeEnum { @@ -16,6 +16,7 @@ public enum TradeOrderOperateTypeEnum {
16 MEMBER_CREATE(1, "用户下单"), 16 MEMBER_CREATE(1, "用户下单"),
17 ADMIN_UPDATE_PRICE(2, "订单价格 {oldPayPrice} 修改,实际支付金额为 {newPayPrice} 元"), 17 ADMIN_UPDATE_PRICE(2, "订单价格 {oldPayPrice} 修改,实际支付金额为 {newPayPrice} 元"),
18 MEMBER_PAY(10, "用户付款成功"), 18 MEMBER_PAY(10, "用户付款成功"),
  19 + SYSTEM_UP_ADDRESS(11, "订单 {orderId} 收货地址修改"),
19 ADMIN_DELIVERY(20, "已发货,快递公司:{deliveryName},快递单号:{logisticsNo}"), 20 ADMIN_DELIVERY(20, "已发货,快递公司:{deliveryName},快递单号:{logisticsNo}"),
20 MEMBER_RECEIVE(30, "用户已收货"), 21 MEMBER_RECEIVE(30, "用户已收货"),
21 SYSTEM_RECEIVE(31, "到期未收货,系统自动确认收货"), 22 SYSTEM_RECEIVE(31, "到期未收货,系统自动确认收货"),
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
@@ -32,6 +32,11 @@ public class TradeOrderApiImpl implements TradeOrderApi { @@ -32,6 +32,11 @@ public class TradeOrderApiImpl implements TradeOrderApi {
32 } 32 }
33 33
34 @Override 34 @Override
  35 + public TradeOrderRespDTO getOrder(Long id) {
  36 + return TradeOrderConvert.INSTANCE.convert(tradeOrderQueryService.getOrder(id));
  37 + }
  38 +
  39 + @Override
35 public Integer getOrderStatus(Long id) { 40 public Integer getOrderStatus(Long id) {
36 TradeOrderDO order = tradeOrderQueryService.getOrder(id); 41 TradeOrderDO order = tradeOrderQueryService.getOrder(id);
37 if (order == null) { 42 if (order == null) {
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDeta @@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDeta
16 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 16 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
17 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; 17 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
18 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 18 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  19 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
19 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; 20 import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
20 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; 21 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
21 import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; 22 import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
@@ -38,6 +39,7 @@ import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; @@ -38,6 +39,7 @@ import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
38 import org.mapstruct.Mapper; 39 import org.mapstruct.Mapper;
39 import org.mapstruct.Mapping; 40 import org.mapstruct.Mapping;
40 import org.mapstruct.Mappings; 41 import org.mapstruct.Mappings;
  42 +import org.mapstruct.Named;
41 import org.mapstruct.factory.Mappers; 43 import org.mapstruct.factory.Mappers;
42 44
43 import java.util.ArrayList; 45 import java.util.ArrayList;
@@ -261,6 +263,19 @@ public interface TradeOrderConvert { @@ -261,6 +263,19 @@ public interface TradeOrderConvert {
261 return bo; 263 return bo;
262 } 264 }
263 265
  266 + @Named("convertList04")
264 List<TradeOrderRespDTO> convertList04(List<TradeOrderDO> list); 267 List<TradeOrderRespDTO> convertList04(List<TradeOrderDO> list);
265 268
  269 + @Mappings({
  270 + @Mapping(target = "activityId", source = "order.combinationActivityId"),
  271 + @Mapping(target = "spuId", source = "item.spuId"),
  272 + @Mapping(target = "skuId", source = "item.skuId"),
  273 + @Mapping(target = "count", source = "item.count"),
  274 + @Mapping(target = "orderId", source = "order.id"),
  275 + @Mapping(target = "userId", source = "order.userId"),
  276 + @Mapping(target = "headId", source = "order.combinationHeadId"),
  277 + @Mapping(target = "combinationPrice", source = "item.payPrice"),
  278 + })
  279 + CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO item);
  280 +
266 } 281 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
@@ -7,7 +7,10 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; @@ -7,7 +7,10 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
7 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; 7 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
8 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; 8 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
9 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 9 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
10 -import cn.iocoder.yudao.module.trade.enums.order.*; 10 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum;
  11 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
  12 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
  13 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
11 import com.baomidou.mybatisplus.annotation.KeySequence; 14 import com.baomidou.mybatisplus.annotation.KeySequence;
12 import com.baomidou.mybatisplus.annotation.TableName; 15 import com.baomidou.mybatisplus.annotation.TableName;
13 import lombok.*; 16 import lombok.*;
@@ -308,4 +311,17 @@ public class TradeOrderDO extends BaseDO { @@ -308,4 +311,17 @@ public class TradeOrderDO extends BaseDO {
308 */ 311 */
309 private Long bargainRecordId; 312 private Long bargainRecordId;
310 313
  314 + /**
  315 + * 拼团活动编号
  316 + *
  317 + * 关联 CombinationActivityDO 的 id 字段
  318 + */
  319 + private Long combinationActivityId;
  320 + /**
  321 + * 团长编号
  322 + *
  323 + * 关联 CombinationRecordDO 的 id 字段
  324 + */
  325 + private Long combinationHeadId;
  326 +
311 } 327 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
@@ -738,16 +738,19 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -738,16 +738,19 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
738 } 738 }
739 739
740 @Override 740 @Override
  741 + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_UP_ADDRESS)
741 public void updateOrderAddress(TradeOrderUpdateAddressReqVO reqVO) { 742 public void updateOrderAddress(TradeOrderUpdateAddressReqVO reqVO) {
742 // 校验交易订单 743 // 校验交易订单
743 - validateOrderExists(reqVO.getId()); 744 + TradeOrderDO order = validateOrderExists(reqVO.getId());
744 // TODO @puhui999:是否需要校验订单是否发货 745 // TODO @puhui999:是否需要校验订单是否发货
745 // TODO 发货后是否支持修改收货地址 746 // TODO 发货后是否支持修改收货地址
746 747
747 // 更新 748 // 更新
748 tradeOrderMapper.updateById(TradeOrderConvert.INSTANCE.convert(reqVO)); 749 tradeOrderMapper.updateById(TradeOrderConvert.INSTANCE.convert(reqVO));
749 750
750 - // TODO @puhui999:操作日志 751 + // 记录订单日志
  752 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus(),
  753 + MapUtil.<String, Object>builder().put("orderId", order.getId()).build());
751 } 754 }
752 755
753 @Override 756 @Override
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java
1 package cn.iocoder.yudao.module.trade.service.order.handler; 1 package cn.iocoder.yudao.module.trade.service.order.handler;
2 2
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.ObjectUtil;
3 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; 5 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
  6 +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
  8 +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
  9 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
4 import org.springframework.stereotype.Component; 10 import org.springframework.stereotype.Component;
5 11
6 import javax.annotation.Resource; 12 import javax.annotation.Resource;
  13 +import java.util.List;
7 14
8 /** 15 /**
9 * 拼团订单 handler 接口实现类 16 * 拼团订单 handler 接口实现类
@@ -16,38 +23,43 @@ public class TradeCombinationHandler implements TradeOrderHandler { @@ -16,38 +23,43 @@ public class TradeCombinationHandler implements TradeOrderHandler {
16 @Resource 23 @Resource
17 private CombinationRecordApi combinationRecordApi; 24 private CombinationRecordApi combinationRecordApi;
18 25
19 -// @Override  
20 -// public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {  
21 -// // 如果不是拼团订单则结束  
22 -// if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {  
23 -// return;  
24 -// }  
25 -//  
26 -// // 获取商品信息  
27 -// TradeBeforeOrderCreateReqBO.Item item = reqBO.getItems().get(0);  
28 -// // 校验是否满足拼团活动相关限制  
29 -// combinationRecordApi.validateCombinationRecord(reqBO.getCombinationActivityId(), reqBO.getUserId(), item.getSkuId(), item.getCount());  
30 -// }  
31 -  
32 -// @Override  
33 -// public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {  
34 -// if (reqBO.getCombinationActivityId() == null) {  
35 -// return;  
36 -// }  
37 -//  
38 -// // 创建砍价记录  
39 -// combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(reqBO));  
40 -// }  
41 -  
42 -// @Override  
43 -// public void afterPayOrder(TradeAfterPayOrderReqBO reqBO) {  
44 -// // 如果不是拼团订单则结束  
45 -// if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {  
46 -// return;  
47 -// }  
48 -//  
49 -// // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录  
50 -// combinationRecordApi.updateRecordStatusToInProgress(reqBO.getUserId(), reqBO.getOrderId(), reqBO.getPayTime());  
51 -// } 26 + @Override
  27 + public void beforeOrderCreate(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
  28 + // 如果不是拼团订单则结束
  29 + if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
  30 + return;
  31 + }
  32 + Assert.isTrue(orderItems.size() == 1, "拼团时,只允许选择一个商品");
  33 +
  34 + // 获取商品信息
  35 + TradeOrderItemDO item = orderItems.get(0);
  36 + // 校验是否满足拼团活动相关限制
  37 + combinationRecordApi.validateCombinationRecord(order.getCombinationActivityId(), order.getUserId(), item.getSkuId(), item.getCount());
  38 + }
  39 +
  40 + @Override
  41 + public void afterOrderCreate(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
  42 + // 如果不是拼团订单则结束
  43 + if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
  44 + return;
  45 + }
  46 + Assert.isTrue(orderItems.size() == 1, "拼团时,只允许选择一个商品");
  47 +
  48 + // 获取商品信息
  49 + TradeOrderItemDO item = orderItems.get(0);
  50 + // 创建砍价记录
  51 + combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, item));
  52 + }
  53 +
  54 + @Override
  55 + public void afterPayOrder(TradeOrderDO order) {
  56 + // 如果不是拼团订单则结束
  57 + if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
  58 + return;
  59 + }
  60 +
  61 + // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
  62 + combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), order.getPayTime());
  63 + }
52 64
53 } 65 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCombinationActivityPriceCalculator.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.price.calculator;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
  6 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO;
  7 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
  8 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
  9 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
  10 +import org.springframework.core.annotation.Order;
  11 +import org.springframework.stereotype.Component;
  12 +
  13 +import javax.annotation.Resource;
  14 +
  15 +/**
  16 + * 拼团活动的 {@link TradePriceCalculator} 实现类
  17 + *
  18 + * @author HUIHUI
  19 + */
  20 +@Component
  21 +@Order(TradePriceCalculator.ORDER_COMBINATION_ACTIVITY)
  22 +public class TradeCombinationActivityPriceCalculator implements TradePriceCalculator {
  23 +
  24 + @Resource
  25 + private CombinationRecordApi combinationRecordApi;
  26 +
  27 + @Override
  28 + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
  29 + // 1. 判断订单类型和是否具有拼团活动编号
  30 + if (param.getCombinationActivityId() == null) {
  31 + return;
  32 + }
  33 +
  34 + Assert.isTrue(param.getItems().size() == 1, "拼团时,只允许选择一个商品");
  35 + // 2. 校验是否可以参与拼团
  36 + TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0);
  37 + CombinationValidateJoinRespDTO combinationActivity = combinationRecordApi.validateJoinCombination(
  38 + param.getCombinationActivityId(), param.getUserId(),
  39 + orderItem.getSkuId(), orderItem.getCount());
  40 +
  41 + // 3.1 记录优惠明细
  42 + Integer discountPrice = orderItem.getPayPrice() - combinationActivity.getCombinationPrice() * orderItem.getCount();
  43 + TradePriceCalculatorHelper.addPromotion(result, orderItem,
  44 + param.getCombinationActivityId(), combinationActivity.getName(), PromotionTypeEnum.COMBINATION_ACTIVITY.getType(),
  45 + StrUtil.format("拼团活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)),
  46 + discountPrice);
  47 + // 3.2 更新 SKU 优惠金额
  48 + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice);
  49 + TradePriceCalculatorHelper.recountPayPrice(orderItem);
  50 + TradePriceCalculatorHelper.recountAllPrice(result);
  51 + }
  52 +
  53 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
@@ -17,6 +17,7 @@ public interface TradePriceCalculator { @@ -17,6 +17,7 @@ public interface TradePriceCalculator {
17 17
18 int ORDER_SECKILL_ACTIVITY = 8; 18 int ORDER_SECKILL_ACTIVITY = 8;
19 int ORDER_BARGAIN_ACTIVITY = 8; 19 int ORDER_BARGAIN_ACTIVITY = 8;
  20 + int ORDER_COMBINATION_ACTIVITY = 8;
20 21
21 int ORDER_DISCOUNT_ACTIVITY = 10; 22 int ORDER_DISCOUNT_ACTIVITY = 10;
22 int ORDER_REWARD_ACTIVITY = 20; 23 int ORDER_REWARD_ACTIVITY = 20;