Commit 0b2943ba8b41e0734727dd43717fc39ba3f9dd96

Authored by puhui999
1 parent 07d6ab58

拼团活动:完善拼团下单金额结算

Showing 13 changed files with 154 additions and 34 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/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;
@@ -108,8 +107,6 @@ public interface CombinationActivityConvert { @@ -108,8 +107,6 @@ public interface CombinationActivityConvert {
108 .setPicUrl(sku.getPicUrl()); 107 .setPicUrl(sku.getPicUrl());
109 } 108 }
110 109
111 - List<CombinationRecordRespDTO> convert(List<CombinationRecordDO> bean);  
112 -  
113 List<AppCombinationActivityRespVO> convertAppList(List<CombinationActivityDO> list); 110 List<AppCombinationActivityRespVO> convertAppList(List<CombinationActivityDO> list);
114 111
115 default List<AppCombinationActivityRespVO> convertAppList(List<CombinationActivityDO> list, List<ProductSpuRespDTO> spuList) { 112 default List<AppCombinationActivityRespVO> convertAppList(List<CombinationActivityDO> list, List<ProductSpuRespDTO> spuList) {
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
@@ -100,4 +100,13 @@ public interface CombinationActivityService { @@ -100,4 +100,13 @@ 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 +
103 } 112 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
@@ -216,4 +216,11 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic @@ -216,4 +216,11 @@ 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 +
219 } 226 }
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;
@@ -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 * 创建拼团记录
@@ -68,4 +73,17 @@ public interface CombinationRecordService { @@ -68,4 +73,17 @@ 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 +
71 } 89 }
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;
@@ -104,7 +107,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -104,7 +107,7 @@ 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(Long activityId, Long userId, Long skuId, Integer count) {
108 // 1.1 校验拼团活动是否存在 111 // 1.1 校验拼团活动是否存在
109 CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId); 112 CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId);
110 // 1.2 校验活动是否开启 113 // 1.2 校验活动是否开启
@@ -115,10 +118,24 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -115,10 +118,24 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
115 if (count > activity.getSingleLimitCount()) { 118 if (count > activity.getSingleLimitCount()) {
116 throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED); 119 throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
117 } 120 }
  121 + // 2.1、校验活动商品是否存在
  122 + CombinationProductDO product = combinationActivityService.selectByActivityIdAndSkuId(activityId, skuId);
  123 + if (product == null) {
  124 + throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
  125 + }
  126 + // 2.2、校验 sku 是否存在
  127 + ProductSkuRespDTO sku = productSkuApi.getSku(skuId);
  128 + if (sku == null) {
  129 + throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
  130 + }
  131 + // 2.3、 校验库存是否充足
  132 + if (count > sku.getStock()) {
  133 + throw exception(COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL);
  134 + }
118 // 3、校验是否有拼团记录 135 // 3、校验是否有拼团记录
119 List<CombinationRecordDO> recordList = getRecordListByUserIdAndActivityId(userId, activityId); 136 List<CombinationRecordDO> recordList = getRecordListByUserIdAndActivityId(userId, activityId);
120 if (CollUtil.isEmpty(recordList)) { 137 if (CollUtil.isEmpty(recordList)) {
121 - return; 138 + return new KeyValue<>(activity, product);
122 } 139 }
123 // 4、校验是否超出总限购数量 140 // 4、校验是否超出总限购数量
124 Integer sumValue = getSumValue(convertList(recordList, CombinationRecordDO::getCount, 141 Integer sumValue = getSumValue(convertList(recordList, CombinationRecordDO::getCount,
@@ -129,7 +146,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -129,7 +146,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
129 // 5、校验拼团记录是否存在未支付的订单(如果存在未支付的订单则不允许发起新的拼团) 146 // 5、校验拼团记录是否存在未支付的订单(如果存在未支付的订单则不允许发起新的拼团)
130 CombinationRecordDO record = findFirst(recordList, item -> ObjectUtil.equals(item.getStatus(), null)); 147 CombinationRecordDO record = findFirst(recordList, item -> ObjectUtil.equals(item.getStatus(), null));
131 if (record == null) { 148 if (record == null) {
132 - return; 149 + return new KeyValue<>(activity, product);
133 } 150 }
134 // 5.1、查询关联的订单是否已经支付 151 // 5.1、查询关联的订单是否已经支付
135 // 当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先; 152 // 当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先;
@@ -138,13 +155,14 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -138,13 +155,14 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
138 if (ObjectUtil.equal(orderStatus, TradeOrderStatusEnum.UNPAID.getStatus())) { 155 if (ObjectUtil.equal(orderStatus, TradeOrderStatusEnum.UNPAID.getStatus())) {
139 throw exception(COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID); 156 throw exception(COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID);
140 } 157 }
  158 +
  159 + return new KeyValue<>(activity, product);
141 } 160 }
142 161
143 // TODO 芋艿:在详细 review 下; 162 // TODO 芋艿:在详细 review 下;
144 @Override 163 @Override
145 @Transactional(rollbackFor = Exception.class) 164 @Transactional(rollbackFor = Exception.class)
146 public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) { 165 public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
147 -  
148 // 1.1、 校验拼团活动 166 // 1.1、 校验拼团活动
149 CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId()); 167 CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId());
150 // 1.2 校验是否超出单次限购数量 168 // 1.2 校验是否超出单次限购数量
@@ -205,6 +223,15 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -205,6 +223,15 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
205 return recordMapper.selectListByUserIdAndActivityId(userId, activityId); 223 return recordMapper.selectListByUserIdAndActivityId(userId, activityId);
206 } 224 }
207 225
  226 + @Override
  227 + public CombinationValidateJoinRespDTO validateJoinCombination(Long activityId, Long userId, Long skuId, Integer count) {
  228 + KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(activityId, userId, skuId, count);
  229 + return new CombinationValidateJoinRespDTO()
  230 + .setActivityId(keyValue.getKey().getId())
  231 + .setName(keyValue.getKey().getName())
  232 + .setCombinationPrice(keyValue.getValue().getCombinationPrice());
  233 + }
  234 +
208 /** 235 /**
209 * APP 端获取开团记录 236 * APP 端获取开团记录
210 * 237 *
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -271,7 +271,7 @@ public interface TradeOrderConvert { @@ -271,7 +271,7 @@ public interface TradeOrderConvert {
271 @Mapping(target = "count", source = "item.count"), 271 @Mapping(target = "count", source = "item.count"),
272 @Mapping(target = "orderId", source = "order.id"), 272 @Mapping(target = "orderId", source = "order.id"),
273 @Mapping(target = "userId", source = "order.userId"), 273 @Mapping(target = "userId", source = "order.userId"),
274 - @Mapping(target = "headId", source = "order.combinationRecordHeadId"), 274 + @Mapping(target = "headId", source = "order.combinationHeadId"),
275 @Mapping(target = "combinationPrice", source = "item.payPrice"), 275 @Mapping(target = "combinationPrice", source = "item.payPrice"),
276 }) 276 })
277 CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO item); 277 CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO item);
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
@@ -312,7 +312,7 @@ public class TradeOrderDO extends BaseDO { @@ -312,7 +312,7 @@ public class TradeOrderDO extends BaseDO {
312 private Long bargainRecordId; 312 private Long bargainRecordId;
313 313
314 /** 314 /**
315 - * 拼团活动编号 TODO puhui999:价格计算后设置 315 + * 拼团活动编号
316 * 316 *
317 * 关联 CombinationActivityDO 的 id 字段 317 * 关联 CombinationActivityDO 的 id 字段
318 */ 318 */
@@ -322,6 +322,6 @@ public class TradeOrderDO extends BaseDO { @@ -322,6 +322,6 @@ public class TradeOrderDO extends BaseDO {
322 * 322 *
323 * 关联 CombinationRecordDO 的 id 字段 323 * 关联 CombinationRecordDO 的 id 字段
324 */ 324 */
325 - private Long combinationRecordHeadId; 325 + private Long combinationHeadId;
326 326
327 } 327 }
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;