Commit 5235aff8ad4834a82f07d163c6a4329f24930c02

Authored by 芋道源码
Committed by Gitee
2 parents 3e09da01 5d6bb84d

!610 营销活动+订单:完善大部分 TODO 提到的问题

Merge pull request !610 from puhui999/feature/mall_product
Showing 34 changed files with 479 additions and 198 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/CommonResult.java
@@ -41,7 +41,7 @@ public class CommonResult<T> implements Serializable { @@ -41,7 +41,7 @@ public class CommonResult<T> implements Serializable {
41 * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。 41 * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。
42 * 42 *
43 * @param result 传入的 result 对象 43 * @param result 传入的 result 对象
44 - * @param <T> 返回的泛型 44 + * @param <T> 返回的泛型
45 * @return 新的 CommonResult 对象 45 * @return 新的 CommonResult 对象
46 */ 46 */
47 public static <T> CommonResult<T> error(CommonResult<?> result) { 47 public static <T> CommonResult<T> error(CommonResult<?> result) {
@@ -68,6 +68,14 @@ public class CommonResult&lt;T&gt; implements Serializable { @@ -68,6 +68,14 @@ public class CommonResult&lt;T&gt; implements Serializable {
68 return result; 68 return result;
69 } 69 }
70 70
  71 + public static <T> CommonResult<T> success(T data, String msg) {
  72 + CommonResult<T> result = new CommonResult<>();
  73 + result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
  74 + result.data = data;
  75 + result.msg = msg;
  76 + return result;
  77 + }
  78 +
71 public static boolean isSuccess(Integer code) { 79 public static boolean isSuccess(Integer code) {
72 return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode()); 80 return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
73 } 81 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.bargain;
  2 +
  3 +/**
  4 + * 砍价活动 Api 接口
  5 + *
  6 + * @author HUIHUI
  7 + */
  8 +public interface BargainActivityApi {
  9 +
  10 + /**
  11 + * 更新砍价活动库存
  12 + *
  13 + * @param activityId 砍价活动编号
  14 + * @param count 购买数量
  15 + */
  16 + void updateBargainActivityStock(Long activityId, Integer count);
  17 +
  18 +}
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/dto/BargainRecordCreateReqDTO.java
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.bargain.dto; @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.bargain.dto;
2 2
3 import lombok.Data; 3 import lombok.Data;
4 4
5 -import javax.validation.constraints.NotEmpty;  
6 import javax.validation.constraints.NotNull; 5 import javax.validation.constraints.NotNull;
7 6
8 // TODO @芋艿:这块要在看看 7 // TODO @芋艿:这块要在看看
@@ -40,17 +39,7 @@ public class BargainRecordCreateReqDTO { @@ -40,17 +39,7 @@ public class BargainRecordCreateReqDTO {
40 */ 39 */
41 @NotNull(message = "订单编号不能为空") 40 @NotNull(message = "订单编号不能为空")
42 private Long orderId; 41 private Long orderId;
43 - // TODO @puhui999:spuName、picUrl、 之类字段不用传递;  
44 - /**  
45 - * 商品名字  
46 - */  
47 - @NotEmpty(message = "商品名字不能为空")  
48 - private String spuName;  
49 - /**  
50 - * 商品图片  
51 - */  
52 - @NotEmpty(message = "商品图片不能为空")  
53 - private String picUrl; 42 +
54 /** 43 /**
55 * 砍价商品单价 44 * 砍价商品单价
56 */ 45 */
@@ -61,17 +50,7 @@ public class BargainRecordCreateReqDTO { @@ -61,17 +50,7 @@ public class BargainRecordCreateReqDTO {
61 */ 50 */
62 @NotNull(message = "商品原价不能为空") 51 @NotNull(message = "商品原价不能为空")
63 private Integer price; 52 private Integer price;
64 - // TODO @puhui999:nickname、avatar 不用传递,去查询;  
65 - /**  
66 - * 用户昵称  
67 - */  
68 - @NotEmpty(message = "用户昵称不能为空")  
69 - private String nickname;  
70 - /**  
71 - * 用户头像  
72 - */  
73 - @NotEmpty(message = "用户头像不能为空")  
74 - private String avatar; 53 +
75 /** 54 /**
76 * 开团状态:进行中 砍价成功 砍价失败 55 * 开团状态:进行中 砍价成功 砍价失败
77 */ 56 */
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
@@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.promotion.api.combination; @@ -2,9 +2,9 @@ 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.CombinationRecordRespDTO; 4 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
5 -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;  
6 5
7 import javax.validation.Valid; 6 import javax.validation.Valid;
  7 +import java.time.LocalDateTime;
8 import java.util.List; 8 import java.util.List;
9 9
10 // TODO @芋艿:后面也再撸撸这几个接口 10 // TODO @芋艿:后面也再撸撸这几个接口
@@ -51,13 +51,29 @@ public interface CombinationRecordApi { @@ -51,13 +51,29 @@ public interface CombinationRecordApi {
51 */ 51 */
52 void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount); 52 void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);
53 53
54 - // TODO @puhui999:是不是搞成具体的方法,拼团成功,拼团失败,这种方法; 54 + /**
  55 + * 更新拼团状态为 成功
  56 + *
  57 + * @param userId 用户编号
  58 + * @param orderId 订单编号
  59 + */
  60 + void updateRecordStatusToSuccess(Long userId, Long orderId);
55 61
56 /** 62 /**
57 - * 更新开团记录状态 63 + * 更新拼团状态为 失败
58 * 64 *
59 - * @param reqDTO 请求 DTO 65 + * @param userId 用户编号
  66 + * @param orderId 订单编号
  67 + */
  68 + void updateRecordStatusToFailed(Long userId, Long orderId);
  69 +
  70 + /**
  71 + * 更新拼团状态为 进行中
  72 + *
  73 + * @param userId 用户编号
  74 + * @param orderId 订单编号
  75 + * @param startTime 开始时间
60 */ 76 */
61 - void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO); 77 + void updateRecordStatusToInProgress(Long userId, Long orderId, LocalDateTime startTime);
62 78
63 } 79 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordUpdateStatusReqDTO.java deleted
1 -package cn.iocoder.yudao.module.promotion.api.combination.dto;  
2 -  
3 -import lombok.Data;  
4 -  
5 -import javax.validation.constraints.NotNull;  
6 -import java.time.LocalDateTime;  
7 -  
8 -/**  
9 - * 拼团记录的更新状态 Request DTO  
10 - *  
11 - * @author HUIHUI  
12 - */  
13 -@Data  
14 -public class CombinationRecordUpdateStatusReqDTO {  
15 -  
16 - /**  
17 - * 用户编号  
18 - */  
19 - @NotNull(message = "用户编号不能为空")  
20 - private Long userId;  
21 -  
22 - /**  
23 - * 订单编号  
24 - */  
25 - @NotNull(message = "订单编号不能为空")  
26 - private Long orderId;  
27 -  
28 - /**  
29 - * 开团状态:正在开团 拼团成功 拼团失败  
30 - */  
31 - @NotNull(message = "开团状态不能为空")  
32 - private Integer status;  
33 -  
34 - /**  
35 - * 团开始时间  
36 - */  
37 - private LocalDateTime startTime;  
38 -  
39 -}  
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.seckill;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
  4 +
  5 +/**
  6 + * 秒杀活动 API 接口
  7 + *
  8 + * @author HUIHUI
  9 + */
  10 +public interface SeckillActivityApi {
  11 +
  12 +
  13 + /**
  14 + * 更新秒杀库存
  15 + *
  16 + * @param updateStockReqDTO 请求
  17 + */
  18 + void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO);
  19 +
  20 +}
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.seckill.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * 更新秒杀库存 request DTO
  9 + *
  10 + * @author HUIHUI
  11 + */
  12 +@Data
  13 +public class SeckillActivityUpdateStockReqDTO {
  14 +
  15 + /**
  16 + * 活动编号
  17 + */
  18 + private Long activityId;
  19 + /**
  20 + * 总购买数量
  21 + */
  22 + private Integer count;
  23 + /**
  24 + * 活动商品
  25 + */
  26 + private List<Item> items;
  27 +
  28 + @Data
  29 + public static class Item {
  30 +
  31 + /**
  32 + * SPU 编号
  33 + */
  34 + private Long spuId;
  35 + /**
  36 + * SKU 编号
  37 + */
  38 + private Long skuId;
  39 + /**
  40 + * 购买数量
  41 + */
  42 + private Integer count;
  43 +
  44 + }
  45 +
  46 +}
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
@@ -51,10 +51,11 @@ public interface ErrorCodeConstants { @@ -51,10 +51,11 @@ public interface ErrorCodeConstants {
51 51
52 // ========== 秒杀活动 1013008000 ========== 52 // ========== 秒杀活动 1013008000 ==========
53 ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1013008000, "秒杀活动不存在"); 53 ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1013008000, "秒杀活动不存在");
54 - ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013008002, "存在商品参加了其它秒杀活动"); 54 + ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013008002, "存在商品参加了其它秒杀活动,秒杀时段冲突");
55 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改"); 55 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
56 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除"); 56 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭"); 57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
  58 + ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "更新秒杀活动库存失败,原因秒杀库存不足");
58 59
59 // ========== 秒杀时段 1013009000 ========== 60 // ========== 秒杀时段 1013009000 ==========
60 ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在"); 61 ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.bargain;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
  4 +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
  5 +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
  6 +import org.springframework.stereotype.Service;
  7 +
  8 +import javax.annotation.Resource;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  11 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.BARGAIN_ACTIVITY_NOT_EXISTS;
  12 +
  13 +/**
  14 + * 砍价活动 Api 接口实现类
  15 + *
  16 + * @author HUIHUI
  17 + */
  18 +@Service
  19 +public class BargainActivityApiImpl implements BargainActivityApi {
  20 +
  21 + @Resource
  22 + private BargainActivityService bargainActivityService;
  23 +
  24 + @Override
  25 + public void updateBargainActivityStock(Long activityId, Integer count) {
  26 + // 查询砍价活动
  27 + BargainActivityDO activity = bargainActivityService.getBargainActivity(activityId);
  28 + if (activity == null) {
  29 + throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
  30 + }
  31 +
  32 + // 更新砍价库存
  33 + BargainActivityUpdateReqVO reqVO = new BargainActivityUpdateReqVO();
  34 + reqVO.setId(activityId);
  35 + reqVO.setStock(activity.getStock() - count);
  36 + bargainActivityService.updateBargainActivity(reqVO);
  37 + }
  38 +
  39 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
@@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.promotion.api.combination; @@ -2,13 +2,13 @@ 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.CombinationRecordRespDTO; 4 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
5 -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;  
6 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; 5 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
7 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; 6 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
8 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; 7 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
9 import org.springframework.stereotype.Service; 8 import org.springframework.stereotype.Service;
10 9
11 import javax.annotation.Resource; 10 import javax.annotation.Resource;
  11 +import java.time.LocalDateTime;
12 import java.util.List; 12 import java.util.List;
13 13
14 /** 14 /**
@@ -43,12 +43,19 @@ public class CombinationRecordApiImpl implements CombinationRecordApi { @@ -43,12 +43,19 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
43 } 43 }
44 44
45 @Override 45 @Override
46 - public void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO) {  
47 - if (null == reqDTO.getStartTime()) {  
48 - recordService.updateCombinationRecordStatusByUserIdAndOrderId(reqDTO);  
49 - } else {  
50 - recordService.updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(reqDTO);  
51 - } 46 + public void updateRecordStatusToSuccess(Long userId, Long orderId) {
  47 + recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId);
  48 + }
  49 +
  50 + @Override
  51 + public void updateRecordStatusToFailed(Long userId, Long orderId) {
  52 + recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.FAILED.getStatus(), userId, orderId);
  53 + }
  54 +
  55 + @Override
  56 + public void updateRecordStatusToInProgress(Long userId, Long orderId, LocalDateTime startTime) {
  57 + recordService.updateRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordStatusEnum.IN_PROGRESS.getStatus(),
  58 + userId, orderId, startTime);
52 } 59 }
53 60
54 } 61 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.seckill;
  2 +
  3 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  4 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
  5 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  6 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  7 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
  8 +import org.springframework.stereotype.Service;
  9 +
  10 +import javax.annotation.Resource;
  11 +import java.util.ArrayList;
  12 +import java.util.HashMap;
  13 +import java.util.List;
  14 +import java.util.Map;
  15 +
  16 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  17 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_UPDATE_STOCK_FAIL;
  18 +
  19 +/**
  20 + * 秒杀活动接口 Api 接口实现类
  21 + *
  22 + * @author HUIHUI
  23 + */
  24 +@Service
  25 +public class SeckillActivityApiImpl implements SeckillActivityApi {
  26 +
  27 + @Resource
  28 + private SeckillActivityService activityService;
  29 +
  30 + @Override
  31 + public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
  32 + SeckillActivityDO seckillActivity = activityService.getSeckillActivity(updateStockReqDTO.getActivityId());
  33 + if (seckillActivity.getStock() < updateStockReqDTO.getCount()) {
  34 + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
  35 + }
  36 + // 获取活动商品
  37 + List<SeckillProductDO> productDOs = activityService.getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
  38 + List<SeckillActivityUpdateStockReqDTO.Item> items = updateStockReqDTO.getItems();
  39 + Map<Long, List<Long>> map = new HashMap<>();
  40 + items.forEach(item -> {
  41 + if (map.containsKey(item.getSpuId())) {
  42 + List<Long> skuIds = map.get(item.getSpuId());
  43 + skuIds.add(item.getSkuId());
  44 + map.put(item.getSpuId(), skuIds);
  45 + } else {
  46 + List<Long> list = new ArrayList<>();
  47 + list.add(item.getSkuId());
  48 + map.put(item.getSpuId(), list);
  49 + }
  50 + });
  51 + // 过滤出购买的商品
  52 + List<SeckillProductDO> productDOList = CollectionUtils.filterList(productDOs, item -> map.get(item.getSpuId()).contains(item.getSkuId()));
  53 + Map<Long, SeckillActivityUpdateStockReqDTO.Item> productDOMap = CollectionUtils.convertMap(items, SeckillActivityUpdateStockReqDTO.Item::getSkuId, p -> p);
  54 + // 检查活动商品库存是否充足
  55 + boolean b = CollectionUtils.anyMatch(productDOList, item -> {
  56 + SeckillActivityUpdateStockReqDTO.Item item1 = productDOMap.get(item.getSkuId());
  57 + return (item.getStock() < item1.getCount()) || (item.getStock() - item1.getCount()) < 0;
  58 + });
  59 + if (b) {
  60 + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
  61 + }
  62 + List<SeckillProductDO> doList = CollectionUtils.convertList(productDOList, item -> {
  63 + item.setStock(item.getStock() - productDOMap.get(item.getSkuId()).getCount());
  64 + return item;
  65 + });
  66 +
  67 + // 更新活动库存
  68 + seckillActivity.setStock(seckillActivity.getStock() + updateStockReqDTO.getCount());
  69 + seckillActivity.setTotalStock(seckillActivity.getTotalStock() - updateStockReqDTO.getCount());
  70 + activityService.updateSeckillActivity(seckillActivity);
  71 + // 更新活动商品库存
  72 + activityService.updateSeckillActivityProductByList(doList);
  73 + }
  74 +
  75 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java
@@ -86,11 +86,11 @@ public class CombinationRecordDO extends BaseDO { @@ -86,11 +86,11 @@ public class CombinationRecordDO extends BaseDO {
86 */ 86 */
87 private Boolean virtualGroup; 87 private Boolean virtualGroup;
88 /** 88 /**
89 - * 过期时间,单位:小时 89 + * 过期时间
90 * 90 *
91 - * 关联 {@link CombinationActivityDO#getLimitDuration()} 91 + * {@link CombinationRecordDO#getStartTime()} + {@link CombinationActivityDO#getLimitDuration()} 计算
92 */ 92 */
93 - private Integer expireTime; 93 + private LocalDateTime expireTime;
94 /** 94 /**
95 * 开始时间 (订单付款后开始的时间) 95 * 开始时间 (订单付款后开始的时间)
96 */ 96 */
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.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.CombinationRecordUpdateStatusReqDTO;  
5 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; 4 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
6 5
  6 +import java.time.LocalDateTime;
7 import java.util.List; 7 import java.util.List;
8 8
9 /** 9 /**
@@ -16,9 +16,11 @@ public interface CombinationRecordService { @@ -16,9 +16,11 @@ public interface CombinationRecordService {
16 /** 16 /**
17 * 更新拼团状态 17 * 更新拼团状态
18 * 18 *
19 - * @param reqDTO 请求 DTO 19 + * @param status 状态
  20 + * @param userId 用户编号
  21 + * @param orderId 订单编号
20 */ 22 */
21 - void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO); 23 + void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId);
22 24
23 /** 25 /**
24 * 创建拼团记录 26 * 创建拼团记录
@@ -30,9 +32,12 @@ public interface CombinationRecordService { @@ -30,9 +32,12 @@ public interface CombinationRecordService {
30 /** 32 /**
31 * 更新拼团状态和开始时间 33 * 更新拼团状态和开始时间
32 * 34 *
33 - * @param reqDTO 请求 DTO 35 + * @param status 状态
  36 + * @param userId 用户编号
  37 + * @param orderId 订单编号
  38 + * @param startTime 开始时间
34 */ 39 */
35 - void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO); 40 + void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime);
36 41
37 /** 42 /**
38 * 获得拼团状态 43 * 获得拼团状态
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.service.combination; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.service.combination;
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.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; 5 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
6 -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;  
7 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; 6 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
9 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
@@ -21,6 +20,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU @@ -21,6 +20,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
21 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 20 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
22 21
23 // TODO 芋艿:等拼团记录做完,完整 review 下 22 // TODO 芋艿:等拼团记录做完,完整 review 下
  23 +
24 /** 24 /**
25 * 拼团记录 Service 实现类 25 * 拼团记录 Service 实现类
26 * 26 *
@@ -38,27 +38,27 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -38,27 +38,27 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
38 38
39 @Override 39 @Override
40 @Transactional(rollbackFor = Exception.class) 40 @Transactional(rollbackFor = Exception.class)
41 - public void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) { 41 + public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
42 // 校验拼团是否存在 42 // 校验拼团是否存在
43 - CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId()); 43 + CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId);
44 44
45 // 更新状态 45 // 更新状态
46 - recordDO.setStatus(reqDTO.getStatus()); 46 + recordDO.setStatus(status);
47 recordMapper.updateById(recordDO); 47 recordMapper.updateById(recordDO);
48 } 48 }
49 49
50 @Override 50 @Override
51 @Transactional(rollbackFor = Exception.class) 51 @Transactional(rollbackFor = Exception.class)
52 - public void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {  
53 - CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId()); 52 + public void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime) {
  53 + CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId);
54 // 更新状态 54 // 更新状态
55 - recordDO.setStatus(reqDTO.getStatus()); 55 + recordDO.setStatus(status);
56 // 更新开始时间 56 // 更新开始时间
57 - recordDO.setStartTime(reqDTO.getStartTime()); 57 + recordDO.setStartTime(startTime);
58 recordMapper.updateById(recordDO); 58 recordMapper.updateById(recordDO);
59 59
60 // 更新拼团参入人数 60 // 更新拼团参入人数
61 - List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), reqDTO.getStatus()); 61 + List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), status);
62 if (CollUtil.isNotEmpty(recordDOs)) { 62 if (CollUtil.isNotEmpty(recordDOs)) {
63 recordDOs.forEach(item -> { 63 recordDOs.forEach(item -> {
64 item.setUserCount(recordDOs.size()); 64 item.setUserCount(recordDOs.size());
@@ -115,8 +115,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { @@ -115,8 +115,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
115 // 2. 创建拼团记录 115 // 2. 创建拼团记录
116 CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO); 116 CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
117 record.setVirtualGroup(false); 117 record.setVirtualGroup(false);
118 - // TODO @puhui999:过期时间,应该是 Date 哈;  
119 - record.setExpireTime(activity.getLimitDuration()); 118 + record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
120 record.setUserSize(activity.getUserSize()); 119 record.setUserSize(activity.getUserSize());
121 recordMapper.insert(record); 120 recordMapper.insert(record);
122 } 121 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
@@ -34,6 +34,20 @@ public interface SeckillActivityService { @@ -34,6 +34,20 @@ public interface SeckillActivityService {
34 void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO); 34 void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
35 35
36 /** 36 /**
  37 + * 更新秒杀活动
  38 + *
  39 + * @param activityDO 秒杀活动
  40 + */
  41 + void updateSeckillActivity(SeckillActivityDO activityDO);
  42 +
  43 + /**
  44 + * 更新秒杀活动商品
  45 + *
  46 + * @param productDOList 活动商品列表
  47 + */
  48 + void updateSeckillActivityProductByList(List<SeckillProductDO> productDOList);
  49 +
  50 + /**
37 * 关闭秒杀活动 51 * 关闭秒杀活动
38 * 52 *
39 * @param id 编号 53 * @param id 编号
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
@@ -79,8 +79,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -79,8 +79,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
79 * 1. 校验秒杀时段是否存在 79 * 1. 校验秒杀时段是否存在
80 * 2. 秒杀商品是否参加其它活动 80 * 2. 秒杀商品是否参加其它活动
81 * 81 *
82 - * @param configIds 秒杀时段数组  
83 - * @param spuId 商品 SPU 编号 82 + * @param configIds 秒杀时段数组
  83 + * @param spuId 商品 SPU 编号
84 * @param activityId 秒杀活动编号 84 * @param activityId 秒杀活动编号
85 */ 85 */
86 private void validateProductConflict(List<Long> configIds, Long spuId, Long activityId) { 86 private void validateProductConflict(List<Long> configIds, Long spuId, Long activityId) {
@@ -92,15 +92,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -92,15 +92,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
92 if (activityId != null) { // 排除自己 92 if (activityId != null) { // 排除自己
93 activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId)); 93 activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
94 } 94 }
95 - // TODO @puhui999:一个 spu,参与两个活动应该没关系,关键是活动时间不充能重叠;  
96 - // 2.2 过滤出所有 spuId 有交集的活动,判断是否存在重叠  
97 - List<SeckillActivityDO> activityDOs1 = filterList(activityList, s -> ObjectUtil.equal(s.getSpuId(), spuId));  
98 - if (isNotEmpty(activityDOs1)) {  
99 - throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);  
100 - }  
101 - // 2.3 过滤出所有 configIds 有交集的活动,判断是否存在重叠  
102 - List<SeckillActivityDO> activityDOs2 = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds));  
103 - if (isNotEmpty(activityDOs2)) { 95 + // 2.2 过滤出所有 configIds 有交集的活动,判断是否存在重叠
  96 + List<SeckillActivityDO> activityDOs = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds));
  97 + if (isNotEmpty(activityDOs)) {
104 throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); 98 throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
105 } 99 }
106 } 100 }
@@ -108,7 +102,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -108,7 +102,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
108 /** 102 /**
109 * 校验秒杀商品是否都存在 103 * 校验秒杀商品是否都存在
110 * 104 *
111 - * @param spuId 商品 SPU 编号 105 + * @param spuId 商品 SPU 编号
112 * @param products 秒杀商品 106 * @param products 秒杀商品
113 */ 107 */
114 private void validateProductExists(Long spuId, List<SeckillProductBaseVO> products) { 108 private void validateProductExists(Long spuId, List<SeckillProductBaseVO> products) {
@@ -150,11 +144,21 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -150,11 +144,21 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
150 updateSeckillProduct(updateObj, updateReqVO.getProducts()); 144 updateSeckillProduct(updateObj, updateReqVO.getProducts());
151 } 145 }
152 146
  147 + @Override
  148 + public void updateSeckillActivity(SeckillActivityDO activityDO) {
  149 + seckillActivityMapper.updateById(activityDO);
  150 + }
  151 +
  152 + @Override
  153 + public void updateSeckillActivityProductByList(List<SeckillProductDO> productDOList) {
  154 + seckillProductMapper.updateBatch(productDOList);
  155 + }
  156 +
153 /** 157 /**
154 * 更新秒杀商品 158 * 更新秒杀商品
155 * 159 *
156 * @param activity 秒杀活动 160 * @param activity 秒杀活动
157 - * @param products 该活动的最新商品配置 161 + * @param products 该活动的最新商品配置
158 */ 162 */
159 private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductBaseVO> products) { 163 private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductBaseVO> products) {
160 // 第一步,对比新老数据,获得添加、修改、删除的列表 164 // 第一步,对比新老数据,获得添加、修改、删除的列表
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java
1 package cn.iocoder.yudao.module.promotion.util; 1 package cn.iocoder.yudao.module.promotion.util;
2 2
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
5 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; 4 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
6 -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;  
7 5
8 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
9 -import java.util.List;  
10 -import java.util.Set;  
11 -import java.util.function.Function;  
12 -  
13 -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;  
14 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch;  
15 -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;  
16 7
17 /** 8 /**
18 * 活动工具类 9 * 活动工具类
@@ -31,21 +22,4 @@ public class PromotionUtils { @@ -31,21 +22,4 @@ public class PromotionUtils {
31 return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus(); 22 return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus();
32 } 23 }
33 24
34 - /**  
35 - * 校验商品 sku 是否都存在  
36 - *  
37 - * @param skus 数据库中的商品 skus  
38 - * @param products 需要校验的商品  
39 - * @param func 获取需要校验的商品的 skuId  
40 - */  
41 - public static <T> void validateProductSkuAllExists(List<ProductSkuRespDTO> skus, List<T> products, Function<T, Long> func) {  
42 - // 校验 sku 个数是否一致  
43 - Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func);  
44 - Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId);  
45 - // 校验 skuId 是否存在  
46 - if (anyMatch(skuIdsSet, s -> !skuIdsSet1.contains(s))) {  
47 - throw exception(SKU_NOT_EXISTS);  
48 - }  
49 - }  
50 -  
51 } 25 }
yudao-module-mall/yudao-module-trade-biz/pom.xml
@@ -86,6 +86,11 @@ @@ -86,6 +86,11 @@
86 <artifactId>yudao-spring-boot-starter-mybatis</artifactId> 86 <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
87 </dependency> 87 </dependency>
88 88
  89 + <dependency>
  90 + <groupId>cn.iocoder.boot</groupId>
  91 + <artifactId>yudao-spring-boot-starter-redis</artifactId>
  92 + </dependency>
  93 +
89 <!-- Test 测试相关 --> 94 <!-- Test 测试相关 -->
90 <dependency> 95 <dependency>
91 <groupId>cn.iocoder.boot</groupId> 96 <groupId>cn.iocoder.boot</groupId>
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java
@@ -36,6 +36,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -36,6 +36,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
36 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 36 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
37 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; 37 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
38 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 38 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
  39 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.AFTER_SALE_NOT_FOUND;
39 40
40 @Tag(name = "管理后台 - 售后订单") 41 @Tag(name = "管理后台 - 售后订单")
41 @RestController 42 @RestController
@@ -76,6 +77,9 @@ public class TradeAfterSaleController { @@ -76,6 +77,9 @@ public class TradeAfterSaleController {
76 public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { 77 public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
77 // 查询订单 78 // 查询订单
78 TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id); 79 TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id);
  80 + if (afterSale == null) {
  81 + return success(null, AFTER_SALE_NOT_FOUND.getMsg());
  82 + }
79 // 查询订单 83 // 查询订单
80 TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId()); 84 TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId());
81 // 查询订单项 85 // 查询订单项
@@ -92,7 +96,11 @@ public class TradeAfterSaleController { @@ -92,7 +96,11 @@ public class TradeAfterSaleController {
92 TradeAfterSaleLogRespDTO respVO = new TradeAfterSaleLogRespDTO(); 96 TradeAfterSaleLogRespDTO respVO = new TradeAfterSaleLogRespDTO();
93 respVO.setId((long) i); 97 respVO.setId((long) i);
94 respVO.setUserId((long) i); 98 respVO.setUserId((long) i);
95 - respVO.setUserType(1); 99 + respVO.setUserType(i % 2 == 0 ? 2 : 1);
  100 + // 模拟系统操作
  101 + if (i == 2) {
  102 + respVO.setUserType(3);
  103 + }
96 respVO.setAfterSaleId(id); 104 respVO.setAfterSaleId(id);
97 respVO.setOrderId((long) i); 105 respVO.setOrderId((long) i);
98 respVO.setOrderItemId((long) i); 106 respVO.setOrderItemId((long) i);
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDetailRespVO.java
@@ -35,7 +35,7 @@ public class TradeAfterSaleDetailRespVO extends TradeAfterSaleBaseVO { @@ -35,7 +35,7 @@ public class TradeAfterSaleDetailRespVO extends TradeAfterSaleBaseVO {
35 /** 35 /**
36 * 售后日志 36 * 售后日志
37 */ 37 */
38 - private List<TradeAfterSaleLogRespVO> afterSaleLog; 38 + private List<TradeAfterSaleLogRespVO> logs;
39 39
40 @Schema(description = "管理后台 - 交易订单的详情的订单项目") 40 @Schema(description = "管理后台 - 交易订单的详情的订单项目")
41 @Data 41 @Data
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
@@ -25,6 +25,7 @@ import java.util.Map; @@ -25,6 +25,7 @@ import java.util.Map;
25 25
26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  28 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
28 29
29 @Tag(name = "管理后台 - 交易订单") 30 @Tag(name = "管理后台 - 交易订单")
30 @RestController 31 @RestController
@@ -67,6 +68,9 @@ public class TradeOrderController { @@ -67,6 +68,9 @@ public class TradeOrderController {
67 public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { 68 public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
68 // 查询订单 69 // 查询订单
69 TradeOrderDO order = tradeOrderQueryService.getOrder(id); 70 TradeOrderDO order = tradeOrderQueryService.getOrder(id);
  71 + if (order == null) {
  72 + return success(null, ORDER_NOT_FOUND.getMsg());
  73 + }
70 // 查询订单项 74 // 查询订单项
71 List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id); 75 List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);
72 // orderLog 76 // orderLog
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java
@@ -26,24 +26,23 @@ public class TradeOrderDetailRespVO extends TradeOrderBaseVO { @@ -26,24 +26,23 @@ public class TradeOrderDetailRespVO extends TradeOrderBaseVO {
26 private MemberUserRespVO user; 26 private MemberUserRespVO user;
27 27
28 /** 28 /**
29 - * TODO 订单操作日志, 先模拟一波;返回 logs,简洁,然后复数哈 29 + * TODO 订单操作日志, 先模拟一波
30 */ 30 */
31 - private List<OrderLog> orderLog; 31 + private List<OrderLog> logs;
32 32
33 - // TODO @puhui999:swagger 注解 33 + @Schema(description = "管理后台 - 交易订单的操作日志")
34 @Data 34 @Data
35 public static class OrderLog { 35 public static class OrderLog {
36 36
37 - /**  
38 - * 内容  
39 - */ 37 + @Schema(description = "操作详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单发货")
40 private String content; 38 private String content;
41 39
42 - /**  
43 - * 创建时间  
44 - */ 40 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-06-01 10:50:20")
45 private LocalDateTime createTime; 41 private LocalDateTime createTime;
46 42
  43 + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  44 + private Integer userType;
  45 +
47 } 46 }
48 47
49 @Schema(description = "管理后台 - 交易订单的详情的订单项目") 48 @Schema(description = "管理后台 - 交易订单的详情的订单项目")
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
@@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; 5 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
6 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; 6 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
7 -import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;  
8 import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; 7 import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
9 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; 8 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
10 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; 9 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
@@ -34,6 +33,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -34,6 +33,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
34 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 33 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
35 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; 34 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
36 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 35 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
  36 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
37 37
38 @Tag(name = "用户 App - 交易订单") 38 @Tag(name = "用户 App - 交易订单")
39 @RestController 39 @RestController
@@ -83,7 +83,7 @@ public class AppTradeOrderController { @@ -83,7 +83,7 @@ public class AppTradeOrderController {
83 // 查询订单 83 // 查询订单
84 TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id); 84 TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
85 if (order == null) { 85 if (order == null) {
86 - return success(null); 86 + return success(null, ORDER_NOT_FOUND.getMsg());
87 } 87 }
88 88
89 // 查询订单项 89 // 查询订单项
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
@@ -56,6 +56,10 @@ public class AppTradeOrderSettlementReqVO { @@ -56,6 +56,10 @@ public class AppTradeOrderSettlementReqVO {
56 @Schema(description = "拼团团长编号", example = "2048") 56 @Schema(description = "拼团团长编号", example = "2048")
57 private Long combinationHeadId; 57 private Long combinationHeadId;
58 58
  59 + // ========== 砍价活动相关字段 ==========
  60 + @Schema(description = "砍价活动编号", example = "123")
  61 + private Long bargainActivityId;
  62 +
59 @Data 63 @Data
60 @Schema(description = "用户 App - 商品项") 64 @Schema(description = "用户 App - 商品项")
61 @Valid 65 @Valid
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java
@@ -78,7 +78,7 @@ public interface TradeAfterSaleConvert { @@ -78,7 +78,7 @@ public interface TradeAfterSaleConvert {
78 // 处理订单信息 78 // 处理订单信息
79 respVO.setOrder(convert(order)); 79 respVO.setOrder(convert(order));
80 // 处理售后日志 80 // 处理售后日志
81 - respVO.setAfterSaleLog(convertList1(logs)); 81 + respVO.setLogs(convertList1(logs));
82 return respVO; 82 return respVO;
83 } 83 }
84 List<TradeAfterSaleLogRespVO> convertList1(List<TradeAfterSaleLogRespDTO> list); 84 List<TradeAfterSaleLogRespVO> convertList1(List<TradeAfterSaleLogRespDTO> list);
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -95,6 +95,7 @@ public interface TradeOrderConvert { @@ -95,6 +95,7 @@ public interface TradeOrderConvert {
95 items.forEach(item -> item.setIncrCount(-item.getIncrCount())); 95 items.forEach(item -> item.setIncrCount(-item.getIncrCount()));
96 return new ProductSkuUpdateStockReqDTO(items); 96 return new ProductSkuUpdateStockReqDTO(items);
97 } 97 }
  98 +
98 List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list); 99 List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list);
99 100
100 @Mappings({ 101 @Mappings({
@@ -153,9 +154,10 @@ public interface TradeOrderConvert { @@ -153,9 +154,10 @@ public interface TradeOrderConvert {
153 TradeOrderDetailRespVO.OrderLog orderLog = new TradeOrderDetailRespVO.OrderLog(); 154 TradeOrderDetailRespVO.OrderLog orderLog = new TradeOrderDetailRespVO.OrderLog();
154 orderLog.setContent("订单操作" + i); 155 orderLog.setContent("订单操作" + i);
155 orderLog.setCreateTime(LocalDateTime.now()); 156 orderLog.setCreateTime(LocalDateTime.now());
  157 + orderLog.setUserType(i % 2 == 0 ? 2 : 1);
156 orderLogs.add(orderLog); 158 orderLogs.add(orderLog);
157 } 159 }
158 - orderVO.setOrderLog(orderLogs); 160 + orderVO.setLogs(orderLogs);
159 return orderVO; 161 return orderVO;
160 } 162 }
161 163
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/no/TradeOrderNoRedisDAO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.dal.redis.no;
  2 +
  3 +import cn.hutool.core.date.DatePattern;
  4 +import cn.hutool.core.date.DateUtil;
  5 +import org.springframework.data.redis.core.StringRedisTemplate;
  6 +import org.springframework.stereotype.Repository;
  7 +
  8 +import javax.annotation.Resource;
  9 +import java.time.LocalDateTime;
  10 +
  11 +/**
  12 + * 订单序号的 Redis DAO
  13 + *
  14 + * @author HUIHUI
  15 + */
  16 +@Repository
  17 +public class TradeOrderNoRedisDAO {
  18 + public static final String TRADE_ORDER_NO_PREFIX = "O";
  19 +
  20 + @Resource
  21 + private StringRedisTemplate stringRedisTemplate;
  22 +
  23 + /**
  24 + * 生成序号
  25 + *
  26 + * @param prefix 前缀
  27 + * @return 序号
  28 + */
  29 + public String generate(String prefix) {
  30 + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
  31 + Long no = stringRedisTemplate.opsForValue().increment(noPrefix);
  32 + return noPrefix + no;
  33 + }
  34 +
  35 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java
@@ -90,12 +90,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa @@ -90,12 +90,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
90 90
91 @Override 91 @Override
92 public TradeAfterSaleDO getAfterSale(Long id) { 92 public TradeAfterSaleDO getAfterSale(Long id) {
93 - TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);  
94 - // TODO @puhui999;读不到,不要这里报错哈;交给前端报错;一般是读取信息不到,message 提示,然后 close tab;  
95 - if (afterSale == null) {  
96 - throw exception(AFTER_SALE_NOT_FOUND);  
97 - }  
98 - return afterSale; 93 + return tradeAfterSaleMapper.selectById(id);
99 } 94 }
100 95
101 // TODO 芋艿:拼团失败,要不要发起售后的方式退款?还是走取消逻辑? 96 // TODO 芋艿:拼团失败,要不要发起售后的方式退款?还是走取消逻辑?
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order; @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
5 -import cn.hutool.core.util.IdUtil;  
6 import cn.hutool.core.util.ObjectUtil; 5 import cn.hutool.core.util.ObjectUtil;
7 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
8 import cn.hutool.extra.spring.SpringUtil; 7 import cn.hutool.extra.spring.SpringUtil;
@@ -27,12 +26,14 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; @@ -27,12 +26,14 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
27 import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; 26 import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
28 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; 27 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
29 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 28 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
  29 +import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
30 import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi; 30 import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
31 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; 31 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
32 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO; 32 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
33 -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;  
34 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; 33 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
35 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; 34 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
  35 +import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
  36 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
36 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; 37 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
37 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; 38 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
38 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; 39 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
@@ -48,6 +49,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; @@ -48,6 +49,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
48 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; 49 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
49 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; 50 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
50 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; 51 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
  52 +import cn.iocoder.yudao.module.trade.dal.redis.no.TradeOrderNoRedisDAO;
51 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; 53 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
52 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 54 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
53 import cn.iocoder.yudao.module.trade.enums.order.*; 55 import cn.iocoder.yudao.module.trade.enums.order.*;
@@ -73,7 +75,7 @@ import java.util.Set; @@ -73,7 +75,7 @@ import java.util.Set;
73 75
74 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 76 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
75 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 77 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
76 -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND; 78 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL;
77 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID; 79 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID;
78 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; 80 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
79 81
@@ -91,6 +93,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -91,6 +93,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
91 private TradeOrderMapper tradeOrderMapper; 93 private TradeOrderMapper tradeOrderMapper;
92 @Resource 94 @Resource
93 private TradeOrderItemMapper tradeOrderItemMapper; 95 private TradeOrderItemMapper tradeOrderItemMapper;
  96 + @Resource
  97 + private TradeOrderNoRedisDAO orderNoRedisDAO;
94 98
95 @Resource 99 @Resource
96 private CartService cartService; 100 private CartService cartService;
@@ -114,6 +118,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -114,6 +118,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
114 @Resource 118 @Resource
115 private BargainRecordApi bargainRecordApi; 119 private BargainRecordApi bargainRecordApi;
116 @Resource 120 @Resource
  121 + private SeckillActivityApi seckillActivityApi;
  122 + @Resource
  123 + private BargainActivityApi bargainActivityApi;
  124 + @Resource
117 private MemberUserApi memberUserApi; 125 private MemberUserApi memberUserApi;
118 @Resource 126 @Resource
119 private MemberLevelApi memberLevelApi; 127 private MemberLevelApi memberLevelApi;
@@ -194,22 +202,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -194,22 +202,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
194 // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去 202 // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去
195 // 拼团 203 // 拼团
196 if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { 204 if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
197 - MemberUserRespDTO user = memberUserApi.getUser(userId);  
198 - List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());  
199 - // TODO 拼团一次应该只能选择一种规格的商品  
200 - TradeOrderItemDO orderItemDO = orderItems.get(0);  
201 - if (CollUtil.isNotEmpty(recordRespDTOS)) {  
202 - List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));  
203 - List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,  
204 - CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);  
205 - combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),  
206 - CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());  
207 - }  
208 -  
209 - combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user)); 205 + createCombinationRecord(userId, createReqVO, orderItems, order);
210 } 206 }
211 // 3.2 秒杀的特殊逻辑 207 // 3.2 秒杀的特殊逻辑
212 - // TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除  
213 if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) { 208 if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
214 209
215 } 210 }
@@ -219,6 +214,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -219,6 +214,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
219 return order; 214 return order;
220 } 215 }
221 216
  217 + private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {
  218 + MemberUserRespDTO user = memberUserApi.getUser(userId);
  219 + List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
  220 + // TODO 拼团一次应该只能选择一种规格的商品
  221 + TradeOrderItemDO orderItemDO = orderItems.get(0);
  222 + if (CollUtil.isNotEmpty(recordRespDTOS)) {
  223 + List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
  224 + List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
  225 + CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
  226 + combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
  227 + CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
  228 + }
  229 +
  230 + combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
  231 + }
  232 +
222 // TODO @puhui999:订单超时,自动取消; 233 // TODO @puhui999:订单超时,自动取消;
223 234
224 /** 235 /**
@@ -245,8 +256,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -245,8 +256,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
245 address = validateAddress(userId, createReqVO.getAddressId()); 256 address = validateAddress(userId, createReqVO.getAddressId());
246 } 257 }
247 TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address); 258 TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address);
  259 + String no = orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX);
248 order.setType(validateActivity(createReqVO)); 260 order.setType(validateActivity(createReqVO));
249 - order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @puhui999: 参考支付订单,的 no 生成哈; 261 + order.setNo(no);
250 order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); 262 order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
251 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); 263 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
252 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); 264 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
@@ -298,19 +310,23 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -298,19 +310,23 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
298 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, 310 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
299 TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems, 311 TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
300 TradePriceCalculateRespBO calculateRespBO) { 312 TradePriceCalculateRespBO calculateRespBO) {
301 - // 下单时扣减商品库存  
302 - // TODO @puhui999:扣库存,需要前置; 313 + Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);
303 // 1)如果是秒杀商品:额外扣减秒杀的库存; 314 // 1)如果是秒杀商品:额外扣减秒杀的库存;
304 - // 2)如果是拼团活动:额外扣减拼团的库存;  
305 - // 3)如果是砍价活动:额外扣减砍价的库存;  
306 - productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));  
307 -  
308 - // 删除购物车商品  
309 - Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);  
310 - if (CollUtil.isNotEmpty(cartIds)) {  
311 - cartService.deleteCart(userId, cartIds);  
312 - }  
313 - 315 + if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {
  316 + SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();
  317 + updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());
  318 + updateStockReqDTO.setCount(count);
  319 + updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> {
  320 + SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();
  321 + item1.setSpuId(item.getSpuId());
  322 + item1.setSkuId(item.getSkuId());
  323 + item1.setCount(item.getCount());
  324 + return item1;
  325 + }));
  326 + seckillActivityApi.updateSeckillStock(updateStockReqDTO);
  327 + }
  328 + // 2)如果是砍价活动:额外扣减砍价的库存;
  329 + bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count);
314 // 扣减积分 TODO 芋艿:待实现,需要前置; 330 // 扣减积分 TODO 芋艿:待实现,需要前置;
315 // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣 331 // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
316 332
@@ -320,6 +336,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -320,6 +336,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
320 .setOrderId(tradeOrderDO.getId())); 336 .setOrderId(tradeOrderDO.getId()));
321 } 337 }
322 338
  339 + // 下单时扣减商品库存
  340 + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));
  341 +
  342 + // 删除购物车商品
  343 + Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
  344 + if (CollUtil.isNotEmpty(cartIds)) {
  345 + cartService.deleteCart(userId, cartIds);
  346 + }
  347 +
323 // 生成预支付 348 // 生成预支付
324 createPayOrder(tradeOrderDO, orderItems, calculateRespBO); 349 createPayOrder(tradeOrderDO, orderItems, calculateRespBO);
325 350
@@ -356,8 +381,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -356,8 +381,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
356 // 1、拼团活动 381 // 1、拼团活动
357 if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { 382 if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
358 // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录 383 // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
359 - combinationRecordApi.updateCombinationRecordStatus(new CombinationRecordUpdateStatusReqDTO().setUserId(order.getUserId())  
360 - .setOrderId(order.getId()).setStatus(CombinationRecordStatusEnum.IN_PROGRESS.getStatus()).setStartTime(LocalDateTime.now())); 384 + combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now());
361 } 385 }
362 // TODO 芋艿:发送订单变化的消息 386 // TODO 芋艿:发送订单变化的消息
363 387
@@ -472,11 +496,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -472,11 +496,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
472 */ 496 */
473 private TradeOrderDO validateOrderDeliverable(Long id) { 497 private TradeOrderDO validateOrderDeliverable(Long id) {
474 TradeOrderDO order = validateOrderExists(id); 498 TradeOrderDO order = validateOrderExists(id);
475 - // 校验订单是否是待发货状态  
476 - // TODO @puhui999:已经发货,可以重新发货,修改信息;  
477 - if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) {  
478 - throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);  
479 - }  
480 // 校验订单是否退款 499 // 校验订单是否退款
481 if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) { 500 if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
482 throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE); 501 throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE);
@@ -548,14 +567,25 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -548,14 +567,25 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
548 if (order.getPayStatus()) { 567 if (order.getPayStatus()) {
549 throw exception(ORDER_UPDATE_PRICE_FAIL_PAID); 568 throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
550 } 569 }
551 - // TODO @puhui999:如果改价,需要校验下是否真的变化; 570 + if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) {
  571 + throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL);
  572 + }
552 573
553 - // 更新  
554 - // TODO @puhui999:TradeOrderItemDO 需要做 adjustPrice 的分摊;另外,支付订单那的价格,需要 update 下; 574 + List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId());
  575 + // TradeOrderItemDO 需要做 adjustPrice 的分摊
  576 + int price = reqVO.getAdjustPrice() / itemDOs.size();
  577 + itemDOs.forEach(item -> {
  578 + item.setAdjustPrice(price);
  579 + });
  580 + // 更新 TradeOrderItem
  581 + tradeOrderItemMapper.updateBatch(itemDOs);
  582 + // 更新订单
555 TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO); 583 TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO);
556 update.setPayPrice(update.getPayPrice() + update.getAdjustPrice()); 584 update.setPayPrice(update.getPayPrice() + update.getAdjustPrice());
557 // TODO @芋艿:改价时,赠送的积分,要不要做改动??? 585 // TODO @芋艿:改价时,赠送的积分,要不要做改动???
558 tradeOrderMapper.updateById(update); 586 tradeOrderMapper.updateById(update);
  587 + // 更新支付订单
  588 + payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice());
559 } 589 }
560 590
561 @Override 591 @Override
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java
@@ -29,4 +29,11 @@ public interface PayOrderApi { @@ -29,4 +29,11 @@ public interface PayOrderApi {
29 */ 29 */
30 PayOrderRespDTO getOrder(Long id); 30 PayOrderRespDTO getOrder(Long id);
31 31
  32 + /**
  33 + * 更新支付订单价格
  34 + *
  35 + * @param payOrderId 支付单编号
  36 + * @param payPrice 支付单价格
  37 + */
  38 + void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
32 } 39 }
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
@@ -28,6 +28,7 @@ public interface ErrorCodeConstants { @@ -28,6 +28,7 @@ public interface ErrorCodeConstants {
28 ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}"); 28 ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
29 ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款"); 29 ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
30 ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1007002006, "支付订单调价失败,原因:支付订单已付款,不能调价"); 30 ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1007002006, "支付订单调价失败,原因:支付订单已付款,不能调价");
  31 + ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1007002007, "支付订单调价失败,原因:价格没有变化");
31 32
32 // ========== ORDER 模块(拓展单) 1007003000 ========== 33 // ========== ORDER 模块(拓展单) 1007003000 ==========
33 ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在"); 34 ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java
@@ -31,4 +31,10 @@ public class PayOrderApiImpl implements PayOrderApi { @@ -31,4 +31,10 @@ public class PayOrderApiImpl implements PayOrderApi {
31 return PayOrderConvert.INSTANCE.convert2(order); 31 return PayOrderConvert.INSTANCE.convert2(order);
32 } 32 }
33 33
  34 + @Override
  35 + public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
  36 + payOrderService.updatePayOrderPriceById(payOrderId, payPrice);
  37 + }
  38 +
  39 +
34 } 40 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
@@ -33,7 +33,7 @@ public interface PayOrderService { @@ -33,7 +33,7 @@ public interface PayOrderService {
33 /** 33 /**
34 * 获得支付订单 34 * 获得支付订单
35 * 35 *
36 - * @param appId 应用编号 36 + * @param appId 应用编号
37 * @param merchantOrderId 商户订单编号 37 * @param merchantOrderId 商户订单编号
38 * @return 支付订单 38 * @return 支付订单
39 */ 39 */
@@ -75,7 +75,7 @@ public interface PayOrderService { @@ -75,7 +75,7 @@ public interface PayOrderService {
75 * 提交支付 75 * 提交支付
76 * 此时,会发起支付渠道的调用 76 * 此时,会发起支付渠道的调用
77 * 77 *
78 - * @param reqVO 提交请求 78 + * @param reqVO 提交请求
79 * @param userIp 提交 IP 79 * @param userIp 提交 IP
80 * @return 提交结果 80 * @return 提交结果
81 */ 81 */
@@ -93,12 +93,20 @@ public interface PayOrderService { @@ -93,12 +93,20 @@ public interface PayOrderService {
93 /** 93 /**
94 * 更新支付订单的退款金额 94 * 更新支付订单的退款金额
95 * 95 *
96 - * @param id 编号 96 + * @param id 编号
97 * @param incrRefundPrice 增加的退款金额 97 * @param incrRefundPrice 增加的退款金额
98 */ 98 */
99 void updateOrderRefundPrice(Long id, Integer incrRefundPrice); 99 void updateOrderRefundPrice(Long id, Integer incrRefundPrice);
100 100
101 /** 101 /**
  102 + * 更新支付订单价格
  103 + *
  104 + * @param payOrderId 支付单编号
  105 + * @param payPrice 支付单价格
  106 + */
  107 + void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
  108 +
  109 + /**
102 * 获得支付订单 110 * 获得支付订单
103 * 111 *
104 * @param id 编号 112 * @param id 编号
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
@@ -412,6 +412,17 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -412,6 +412,17 @@ public class PayOrderServiceImpl implements PayOrderService {
412 } 412 }
413 413
414 @Override 414 @Override
  415 + public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
  416 + PayOrderDO order = orderMapper.selectById(payOrderId);
  417 + if (order == null) {
  418 + throw exception(ORDER_NOT_FOUND);
  419 + }
  420 +
  421 + order.setPrice(payPrice);
  422 + orderMapper.updateById(order);
  423 + }
  424 +
  425 + @Override
415 public PayOrderExtensionDO getOrderExtension(Long id) { 426 public PayOrderExtensionDO getOrderExtension(Long id) {
416 return orderExtensionMapper.selectById(id); 427 return orderExtensionMapper.selectById(id);
417 } 428 }