Commit 0e8755972c3c97edbd2897f841634fa374566fe4

Authored by puhui999
1 parent 2591ab5d

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

Showing 19 changed files with 382 additions and 46 deletions
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/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
... ... @@ -55,6 +55,7 @@ public interface ErrorCodeConstants {
55 55 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
56 56 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
57 57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
  58 + ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "更新秒杀活动库存失败,原因秒杀库存不足");
58 59  
59 60 // ========== 秒杀时段 1013009000 ==========
60 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/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/service/seckill/SeckillActivityService.java
... ... @@ -34,6 +34,20 @@ public interface SeckillActivityService {
34 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 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 79 * 1. 校验秒杀时段是否存在
80 80 * 2. 秒杀商品是否参加其它活动
81 81 *
82   - * @param configIds 秒杀时段数组
83   - * @param spuId 商品 SPU 编号
  82 + * @param configIds 秒杀时段数组
  83 + * @param spuId 商品 SPU 编号
84 84 * @param activityId 秒杀活动编号
85 85 */
86 86 private void validateProductConflict(List<Long> configIds, Long spuId, Long activityId) {
... ... @@ -102,7 +102,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
102 102 /**
103 103 * 校验秒杀商品是否都存在
104 104 *
105   - * @param spuId 商品 SPU 编号
  105 + * @param spuId 商品 SPU 编号
106 106 * @param products 秒杀商品
107 107 */
108 108 private void validateProductExists(Long spuId, List<SeckillProductBaseVO> products) {
... ... @@ -144,11 +144,21 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
144 144 updateSeckillProduct(updateObj, updateReqVO.getProducts());
145 145 }
146 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 +
147 157 /**
148 158 * 更新秒杀商品
149 159 *
150 160 * @param activity 秒杀活动
151   - * @param products 该活动的最新商品配置
  161 + * @param products 该活动的最新商品配置
152 162 */
153 163 private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductBaseVO> products) {
154 164 // 第一步,对比新老数据,获得添加、修改、删除的列表
... ...
yudao-module-mall/yudao-module-trade-biz/pom.xml
... ... @@ -82,6 +82,11 @@
82 82 <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
83 83 </dependency>
84 84  
  85 + <dependency>
  86 + <groupId>cn.iocoder.boot</groupId>
  87 + <artifactId>yudao-spring-boot-starter-redis</artifactId>
  88 + </dependency>
  89 +
85 90 <!-- Test 测试相关 -->
86 91 <dependency>
87 92 <groupId>cn.iocoder.boot</groupId>
... ...
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 25  
26 26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
27 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 30 @Tag(name = "管理后台 - 交易订单")
30 31 @RestController
... ... @@ -67,6 +68,9 @@ public class TradeOrderController {
67 68 public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
68 69 // 查询订单
69 70 TradeOrderDO order = tradeOrderQueryService.getOrder(id);
  71 + if (order == null) {
  72 + return success(null, ORDER_NOT_FOUND.getMsg());
  73 + }
70 74 // 查询订单项
71 75 List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);
72 76 // orderLog
... ...
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 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
6 6 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
7   -import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;
8 7 import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
9 8 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
10 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 33 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
35 34 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
36 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 38 @Tag(name = "用户 App - 交易订单")
39 39 @RestController
... ... @@ -83,7 +83,7 @@ public class AppTradeOrderController {
83 83 // 查询订单
84 84 TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
85 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 56 @Schema(description = "拼团团长编号", example = "2048")
57 57 private Long combinationHeadId;
58 58  
  59 + // ========== 砍价活动相关字段 ==========
  60 + @Schema(description = "砍价活动编号", example = "123")
  61 + private Long bargainActivityId;
  62 +
59 63 @Data
60 64 @Schema(description = "用户 App - 商品项")
61 65 @Valid
... ...
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/order/TradeOrderUpdateServiceImpl.java
... ... @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.lang.Assert;
5   -import cn.hutool.core.util.IdUtil;
6 5 import cn.hutool.core.util.ObjectUtil;
7 6 import cn.hutool.core.util.StrUtil;
8 7 import cn.hutool.extra.spring.SpringUtil;
... ... @@ -25,11 +24,14 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
25 24 import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
26 25 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
27 26 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
  27 +import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
28 28 import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
29 29 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
30 30 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
31 31 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
32 32 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
  33 +import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
  34 +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
33 35 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
34 36 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
35 37 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
... ... @@ -45,6 +47,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
45 47 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
46 48 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
47 49 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
  50 +import cn.iocoder.yudao.module.trade.dal.redis.no.TradeOrderNoRedisDAO;
48 51 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
49 52 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
50 53 import cn.iocoder.yudao.module.trade.enums.order.*;
... ... @@ -70,7 +73,7 @@ import java.util.Set;
70 73  
71 74 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
72 75 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
73   -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
  76 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL;
74 77 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID;
75 78 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
76 79  
... ... @@ -88,6 +91,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
88 91 private TradeOrderMapper tradeOrderMapper;
89 92 @Resource
90 93 private TradeOrderItemMapper tradeOrderItemMapper;
  94 + @Resource
  95 + private TradeOrderNoRedisDAO orderNoRedisDAO;
91 96  
92 97 @Resource
93 98 private CartService cartService;
... ... @@ -111,6 +116,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
111 116 @Resource
112 117 private BargainRecordApi bargainRecordApi;
113 118 @Resource
  119 + private SeckillActivityApi seckillActivityApi;
  120 + @Resource
  121 + private BargainActivityApi bargainActivityApi;
  122 + @Resource
114 123 private MemberUserApi memberUserApi;
115 124 @Resource
116 125 private MemberLevelApi memberLevelApi;
... ... @@ -189,22 +198,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
189 198 // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去
190 199 // 拼团
191 200 if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
192   - MemberUserRespDTO user = memberUserApi.getUser(userId);
193   - List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
194   - // TODO 拼团一次应该只能选择一种规格的商品
195   - TradeOrderItemDO orderItemDO = orderItems.get(0);
196   - if (CollUtil.isNotEmpty(recordRespDTOS)) {
197   - List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
198   - List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
199   - CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
200   - combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
201   - CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
202   - }
203   -
204   - combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
  201 + createCombinationRecord(userId, createReqVO, orderItems, order);
205 202 }
206 203 // 3.2 秒杀的特殊逻辑
207   - // TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除
208 204 if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
209 205  
210 206 }
... ... @@ -214,6 +210,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
214 210 return order;
215 211 }
216 212  
  213 + private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {
  214 + MemberUserRespDTO user = memberUserApi.getUser(userId);
  215 + List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
  216 + // TODO 拼团一次应该只能选择一种规格的商品
  217 + TradeOrderItemDO orderItemDO = orderItems.get(0);
  218 + if (CollUtil.isNotEmpty(recordRespDTOS)) {
  219 + List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
  220 + List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
  221 + CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
  222 + combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
  223 + CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
  224 + }
  225 +
  226 + combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
  227 + }
  228 +
217 229 // TODO @puhui999:订单超时,自动取消;
218 230  
219 231 /**
... ... @@ -240,8 +252,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
240 252 address = validateAddress(userId, createReqVO.getAddressId());
241 253 }
242 254 TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address);
  255 + String no = orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX);
243 256 order.setType(validateActivity(createReqVO));
244   - order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @puhui999: 参考支付订单,的 no 生成哈;
  257 + order.setNo(no);
245 258 order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
246 259 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
247 260 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
... ... @@ -293,19 +306,23 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
293 306 private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
294 307 TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
295 308 TradePriceCalculateRespBO calculateRespBO) {
296   - // 下单时扣减商品库存
297   - // TODO @puhui999:扣库存,需要前置;
  309 + Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);
298 310 // 1)如果是秒杀商品:额外扣减秒杀的库存;
299   - // 2)如果是拼团活动:额外扣减拼团的库存;
300   - // 3)如果是砍价活动:额外扣减砍价的库存;
301   - productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));
302   -
303   - // 删除购物车商品
304   - Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
305   - if (CollUtil.isNotEmpty(cartIds)) {
306   - cartService.deleteCart(userId, cartIds);
307   - }
308   -
  311 + if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {
  312 + SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();
  313 + updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());
  314 + updateStockReqDTO.setCount(count);
  315 + updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> {
  316 + SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();
  317 + item1.setSpuId(item.getSpuId());
  318 + item1.setSkuId(item.getSkuId());
  319 + item1.setCount(item.getCount());
  320 + return item1;
  321 + }));
  322 + seckillActivityApi.updateSeckillStock(updateStockReqDTO);
  323 + }
  324 + // 2)如果是砍价活动:额外扣减砍价的库存;
  325 + bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count);
309 326 // 扣减积分 TODO 芋艿:待实现,需要前置;
310 327 // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
311 328  
... ... @@ -315,6 +332,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
315 332 .setOrderId(tradeOrderDO.getId()));
316 333 }
317 334  
  335 + // 下单时扣减商品库存
  336 + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));
  337 +
  338 + // 删除购物车商品
  339 + Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
  340 + if (CollUtil.isNotEmpty(cartIds)) {
  341 + cartService.deleteCart(userId, cartIds);
  342 + }
  343 +
318 344 // 生成预支付
319 345 createPayOrder(tradeOrderDO, orderItems, calculateRespBO);
320 346  
... ... @@ -464,11 +490,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
464 490 */
465 491 private TradeOrderDO validateOrderDeliverable(Long id) {
466 492 TradeOrderDO order = validateOrderExists(id);
467   - // 校验订单是否是待发货状态
468   - // TODO @puhui999:已经发货,可以重新发货,修改信息;
469   - if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) {
470   - throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
471   - }
472 493 // 校验订单是否退款
473 494 if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
474 495 throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE);
... ... @@ -540,14 +561,25 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
540 561 if (order.getPayStatus()) {
541 562 throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
542 563 }
543   - // TODO @puhui999:如果改价,需要校验下是否真的变化;
  564 + if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) {
  565 + throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL);
  566 + }
544 567  
545   - // 更新
546   - // TODO @puhui999:TradeOrderItemDO 需要做 adjustPrice 的分摊;另外,支付订单那的价格,需要 update 下;
  568 + List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId());
  569 + // TradeOrderItemDO 需要做 adjustPrice 的分摊
  570 + int price = reqVO.getAdjustPrice() / itemDOs.size();
  571 + itemDOs.forEach(item -> {
  572 + item.setAdjustPrice(price);
  573 + });
  574 + // 更新 TradeOrderItem
  575 + tradeOrderItemMapper.updateBatch(itemDOs);
  576 + // 更新订单
547 577 TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO);
548 578 update.setPayPrice(update.getPayPrice() + update.getAdjustPrice());
549 579 // TODO @芋艿:改价时,赠送的积分,要不要做改动???
550 580 tradeOrderMapper.updateById(update);
  581 + // 更新支付订单
  582 + payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice());
551 583 }
552 584  
553 585 @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 29 */
30 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 28 ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
29 29 ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
30 30 ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1007002006, "支付订单调价失败,原因:支付订单已付款,不能调价");
  31 + ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1007002007, "支付订单调价失败,原因:价格没有变化");
31 32  
32 33 // ========== ORDER 模块(拓展单) 1007003000 ==========
33 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 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 33 /**
34 34 * 获得支付订单
35 35 *
36   - * @param appId 应用编号
  36 + * @param appId 应用编号
37 37 * @param merchantOrderId 商户订单编号
38 38 * @return 支付订单
39 39 */
... ... @@ -75,7 +75,7 @@ public interface PayOrderService {
75 75 * 提交支付
76 76 * 此时,会发起支付渠道的调用
77 77 *
78   - * @param reqVO 提交请求
  78 + * @param reqVO 提交请求
79 79 * @param userIp 提交 IP
80 80 * @return 提交结果
81 81 */
... ... @@ -93,12 +93,20 @@ public interface PayOrderService {
93 93 /**
94 94 * 更新支付订单的退款金额
95 95 *
96   - * @param id 编号
  96 + * @param id 编号
97 97 * @param incrRefundPrice 增加的退款金额
98 98 */
99 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 112 * @param id 编号
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
... ... @@ -411,6 +411,17 @@ public class PayOrderServiceImpl implements PayOrderService {
411 411 }
412 412  
413 413 @Override
  414 + public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
  415 + PayOrderDO order = orderMapper.selectById(payOrderId);
  416 + if (order == null) {
  417 + throw exception(ORDER_NOT_FOUND);
  418 + }
  419 +
  420 + order.setPrice(payPrice);
  421 + orderMapper.updateById(order);
  422 + }
  423 +
  424 + @Override
414 425 public PayOrderExtensionDO getOrderExtension(Long id) {
415 426 return orderExtensionMapper.selectById(id);
416 427 }
... ...