Commit 01e6140d67b78e274dcc46841ed2d1b606cd2efc

Authored by YunaiV
1 parent 99649bfd

code review:拼团记录流程

yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
... ... @@ -241,7 +241,8 @@ public class CollectionUtils {
241 241 return valueFunc.apply(t);
242 242 }
243 243  
244   - public static <T, V extends Comparable<? super V>> V getSumValue(List<T> from, Function<T, V> valueFunc, BinaryOperator<V> accumulator) {
  244 + public static <T, V extends Comparable<? super V>> V getSumValue(List<T> from, Function<T, V> valueFunc,
  245 + BinaryOperator<V> accumulator) {
245 246 if (CollUtil.isEmpty(from)) {
246 247 return null;
247 248 }
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/combination/CombinationRecordStatusEnum.java
... ... @@ -44,4 +44,8 @@ public enum CombinationRecordStatusEnum implements IntArrayValuable {
44 44 return ObjectUtil.equal(status, IN_PROGRESS.getStatus());
45 45 }
46 46  
  47 + public static boolean isFailed(Integer status) {
  48 + return ObjectUtil.equal(status, FAILED.getStatus());
  49 + }
  50 +
47 51 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java
... ... @@ -35,7 +35,7 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO
35 35 * @param headId 团长编号
36 36 * @return 拼团记录
37 37 */
38   - default CombinationRecordDO selectOneByHeadId(Long headId, Integer status) {
  38 + default CombinationRecordDO selectByHeadId(Long headId, Integer status) {
39 39 return selectOne(new LambdaQueryWrapperX<CombinationRecordDO>()
40 40 .eq(CombinationRecordDO::getId, headId)
41 41 .eq(CombinationRecordDO::getStatus, status));
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
... ... @@ -42,7 +42,8 @@ public interface CombinationRecordService {
42 42 * @param count 数量
43 43 * @return 拼团信息
44 44 */
45   - KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord(Long userId, Long activityId, Long headId, Long skuId, Integer count);
  45 + KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord(Long userId, Long activityId, Long headId,
  46 + Long skuId, Integer count);
46 47  
47 48 /**
48 49 * 创建拼团记录
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
... ... @@ -89,13 +89,13 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
89 89 @Override
90 90 public KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord(
91 91 Long userId, Long activityId, Long headId, Long skuId, Integer count) {
92   - // 1 校验拼团活动是否存在
  92 + // 1. 校验拼团活动是否存在
93 93 CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId);
94 94 // 1.1 校验活动是否开启
95 95 if (ObjUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
96 96 throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
97 97 }
98   - // 1.2、校验活动开始时间
  98 + // 1.2 校验活动开始时间
99 99 if (afterNow(activity.getStartTime())) {
100 100 throw exception(COMBINATION_RECORD_FAILED_TIME_NOT_START);
101 101 }
... ... @@ -104,69 +104,67 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
104 104 throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
105 105 }
106 106  
107   - // 2、父拼团是否存在,是否已经满了
  107 + // 2. 父拼团是否存在,是否已经满了
108 108 if (headId != null) {
109   - // 2.1、查询进行中的父拼团
110   - CombinationRecordDO record = recordMapper.selectOneByHeadId(headId, CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
  109 + // 2.1. 查询进行中的父拼团
  110 + CombinationRecordDO record = recordMapper.selectByHeadId(headId, CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
111 111 if (record == null) {
112 112 throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
113 113 }
114   - // 2.2、校验拼团是否满足要求
  114 + // 2.2. 校验拼团是否已满
115 115 if (ObjUtil.equal(record.getUserCount(), record.getUserSize())) {
116 116 throw exception(COMBINATION_RECORD_USER_FULL);
117 117 }
118   - // 2.3、校验拼团是否过期(有父拼团的时候只校验父拼团的过期时间)
  118 + // 2.3 校验拼团是否过期(有父拼团的时候只校验父拼团的过期时间)
119 119 if (beforeNow(record.getExpireTime())) {
120 120 throw exception(COMBINATION_RECORD_FAILED_TIME_END);
121 121 }
122 122 } else {
123   - // 3、校验当前活动是否结束(自己是父拼团的时候才校验活动是否结束)
  123 + // 3. 校验当前活动是否结束(自己是父拼团的时候才校验活动是否结束)
124 124 if (beforeNow(activity.getEndTime())) {
125 125 throw exception(COMBINATION_RECORD_FAILED_TIME_END);
126 126 }
127 127 }
128 128  
129   - // 4、校验活动商品是否存在
  129 + // 4.1 校验活动商品是否存在
130 130 CombinationProductDO product = combinationActivityService.selectByActivityIdAndSkuId(activityId, skuId);
131 131 if (product == null) {
132 132 throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
133 133 }
134   -
135   - // 5、校验 sku 是否存在
  134 + // 4.2 校验 sku 是否存在
136 135 ProductSkuRespDTO sku = productSkuApi.getSku(skuId);
137 136 if (sku == null) {
138 137 throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
139 138 }
140   - // 5.1、校验库存是否充足
  139 + // 4.3 校验库存是否充足
141 140 if (count > sku.getStock()) {
142 141 throw exception(COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL);
143 142 }
144 143  
145   - // 6、校验是否有拼团记录
146   - List<CombinationRecordDO> recordList = getCombinationRecordListByUserIdAndActivityId(userId, activityId);
147   - if (CollUtil.isEmpty(recordList)) {
  144 + // 6.1 校验是否有拼团记录
  145 + List<CombinationRecordDO> recordList = recordMapper.selectListByUserIdAndActivityId(userId, activityId);
  146 + recordList.removeIf(record -> CombinationRecordStatusEnum.isFailed(record.getStatus())); // 取消的订单,不算数
  147 + if (CollUtil.isEmpty(recordList)) { // 如果为空,说明可以参与,直接返回
148 148 return new KeyValue<>(activity, product);
149 149 }
150   - // 6.1、校验用户是否有该活动正在进行的拼团
151   - List<CombinationRecordDO> filtered = filterList(recordList, record -> CombinationRecordStatusEnum.isInProgress(record.getStatus()));
152   - if (CollUtil.isNotEmpty(filtered)) {
  150 + // 6.2 校验用户是否有该活动正在进行的拼团
  151 + CombinationRecordDO inProgressRecord = findFirst(recordList,
  152 + record -> CombinationRecordStatusEnum.isInProgress(record.getStatus()));
  153 + if (inProgressRecord != null) {
153 154 throw exception(COMBINATION_RECORD_FAILED_HAVE_JOINED);
154 155 }
155   - // 6.2、校验是否超出总限购数量
156   - Integer sumValue = getSumValue(convertList(recordList, CombinationRecordDO::getCount,
157   - item -> CombinationRecordStatusEnum.isSuccess(item.getStatus())), i -> i, Integer::sum);
158   - if ((sumValue + count) > activity.getTotalLimitCount()) {
  156 + // 6.3 校验是否超出总限购数量
  157 + Integer sumValue = getSumValue(recordList, CombinationRecordDO::getCount, Integer::sum);
  158 + if (sumValue != null && sumValue + count > activity.getTotalLimitCount()) {
159 159 throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
160 160 }
161   -
162 161 return new KeyValue<>(activity, product);
163 162 }
164 163  
165   - // TODO 芋艿:在详细 review 下;
166 164 @Override
167 165 @Transactional(rollbackFor = Exception.class)
168 166 public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
169   - // 1、校验拼团活动
  167 + // 1. 校验拼团活动
170 168 KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(reqDTO.getUserId(),
171 169 reqDTO.getActivityId(), reqDTO.getHeadId(), reqDTO.getSkuId(), reqDTO.getCount());
172 170  
... ... @@ -174,23 +172,24 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
174 172 MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
175 173 ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
176 174 ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId());
177   - CombinationRecordDO recordDO = CombinationActivityConvert.INSTANCE.convert(reqDTO, keyValue.getKey(), user, spu, sku);
178   - recordMapper.insert(recordDO);
  175 + CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO, keyValue.getKey(), user, spu, sku);
  176 + recordMapper.insert(record);
179 177  
180   - // 3、如果是团长需要设置 headId 为 CombinationRecordDO#HEAD_ID_GROUP
  178 + // 3. 如果是团长需要设置 headId 为 CombinationRecordDO#HEAD_ID_GROUP
  179 + // TODO @puhui999:是不是只要是团长,record 设置了就好啦,不用 update。。。。
181 180 if (ObjUtil.equal(CombinationRecordDO.HEAD_ID_GROUP, reqDTO.getHeadId())) {
182   - recordMapper.updateById(new CombinationRecordDO().setId(recordDO.getId()).setHeadId(CombinationRecordDO.HEAD_ID_GROUP));
  181 + recordMapper.updateById(new CombinationRecordDO().setId(record.getId()).setHeadId(CombinationRecordDO.HEAD_ID_GROUP));
183 182 return;
184 183 }
185 184  
186   - // TODO 这里要不要弄成异步的
  185 + // TODO 这里要不要弄成异步的;不用异步哈,就是事务好了;
187 186 // 4、更新拼团相关信息到订单
188   - updateOrderCombinationInfo(recordDO.getOrderId(), recordDO.getActivityId(), recordDO.getId(), recordDO.getHeadId());
  187 + updateOrderCombinationInfo(record.getOrderId(), record.getActivityId(), record.getId(), record.getHeadId());
189 188 // 4、更新拼团记录
190   - updateCombinationRecords(keyValue.getKey(), reqDTO.getHeadId());
191   -
  189 + updateCombinationRecordWhenCreate(reqDTO.getHeadId(), keyValue.getKey());
192 190 }
193 191  
  192 + // TODO @puhui999:这个更新,放到 trade 那就好了;createCombinationRecord 返回一个 recordId;
194 193 /**
195 194 * 更新拼团相关信息到订单
196 195 *
... ... @@ -204,35 +203,31 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
204 203 }
205 204  
206 205 /**
207   - * 更新拼团记录
  206 + * 当新增拼团时,更新拼团记录的进展
208 207 *
209   - * @param activity 活动
210 208 * @param headId 团长编号
  209 + * @param activity 活动
211 210 */
212   - private void updateCombinationRecords(CombinationActivityDO activity, Long headId) {
213   - // 团长
214   - CombinationRecordDO recordHead = recordMapper.selectById(headId);
215   - // 团员
  211 + private void updateCombinationRecordWhenCreate(Long headId, CombinationActivityDO activity) {
  212 + // 1. 团长 + 团员
216 213 List<CombinationRecordDO> records = getCombinationRecordListByHeadId(headId);
217   - // 需要更新的记录
218   - List<CombinationRecordDO> updateRecords = new ArrayList<>();
219   -
220 214 if (CollUtil.isEmpty(records)) {
221 215 return;
222 216 }
223   - records.add(recordHead); // 加入团长,团长也需要更新
224   - boolean isEqual = ObjUtil.equal(records.size(), activity.getUserSize());
  217 + CombinationRecordDO headRecord = recordMapper.selectById(headId);
  218 +
  219 + // 2. 批量更新记录
  220 + List<CombinationRecordDO> updateRecords = new ArrayList<>();
  221 + records.add(headRecord); // 加入团长,团长也需要更新
  222 + boolean isFull = records.size() >= activity.getUserSize();
225 223 records.forEach(item -> {
226   - CombinationRecordDO recordDO = new CombinationRecordDO();
227   - recordDO.setId(item.getId());
228   - recordDO.setUserCount(records.size());
229   - // 校验拼团是否满足要求
230   - if (isEqual) {
231   - recordDO.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus());
  224 + CombinationRecordDO updateRecord = new CombinationRecordDO();
  225 + updateRecord.setId(item.getId()).setUserCount(records.size());
  226 + if (isFull) {
  227 + updateRecord.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus());
232 228 }
233   - updateRecords.add(recordDO);
  229 + updateRecords.add(updateRecord);
234 230 });
235   -
236 231 recordMapper.updateBatch(updateRecords);
237 232 }
238 233  
... ... @@ -247,12 +242,12 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
247 242 }
248 243  
249 244 @Override
250   - public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, Long skuId, Integer count) {
251   - KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(userId, activityId, headId, skuId, count);
252   - return new CombinationValidateJoinRespDTO()
253   - .setActivityId(keyValue.getKey().getId())
254   - .setName(keyValue.getKey().getName())
255   - .setCombinationPrice(keyValue.getValue().getCombinationPrice());
  245 + public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId,
  246 + Long skuId, Integer count) {
  247 + KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(userId, activityId,
  248 + headId, skuId, count);
  249 + return new CombinationValidateJoinRespDTO().setActivityId(keyValue.getKey().getId())
  250 + .setName(keyValue.getKey().getName()).setCombinationPrice(keyValue.getValue().getCombinationPrice());
256 251 }
257 252  
258 253 @Override
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java
... ... @@ -30,11 +30,11 @@ public class TradeCombinationHandler implements TradeOrderHandler {
30 30 }
31 31 Assert.isTrue(orderItems.size() == 1, "拼团时,只允许选择一个商品");
32 32  
33   - // 获取商品信息
34   - TradeOrderItemDO item = orderItems.get(0);
35 33 // 校验是否满足拼团活动相关限制
  34 + TradeOrderItemDO item = orderItems.get(0);
36 35 combinationRecordApi.validateCombinationRecord(order.getUserId(), order.getCombinationActivityId(),
37 36 order.getCombinationHeadId(), item.getSkuId(), item.getCount());
  37 + // TODO @puhui999:这里还要限制下,是不是已经 createOrder;就是还没支付的时候,重复下单了;需要校验下;不然的话,一个拼团可以下多个单子了;
38 38 }
39 39  
40 40 @Override
... ...