Browse Source

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

puhui999 1 year ago
parent
commit
0e8755972c
19 changed files with 382 additions and 46 deletions
  1. 18 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java
  2. 20 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java
  3. 46 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java
  4. 1 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  5. 39 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java
  6. 75 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
  7. 14 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
  8. 14 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
  9. 5 0
      yudao-module-mall/yudao-module-trade-biz/pom.xml
  10. 4 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
  11. 2 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
  12. 4 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
  13. 35 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/no/TradeOrderNoRedisDAO.java
  14. 69 37
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
  15. 7 0
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java
  16. 1 0
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
  17. 6 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java
  18. 11 3
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
  19. 11 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java

+ 18 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.promotion.api.bargain;
+
+/**
+ * 砍价活动 Api 接口
+ *
+ * @author HUIHUI
+ */
+public interface BargainActivityApi {
+
+    /**
+     * 更新砍价活动库存
+     *
+     * @param activityId 砍价活动编号
+     * @param count      购买数量
+     */
+    void updateBargainActivityStock(Long activityId, Integer count);
+
+}

+ 20 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.promotion.api.seckill;
+
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
+
+/**
+ * 秒杀活动 API 接口
+ *
+ * @author HUIHUI
+ */
+public interface SeckillActivityApi {
+
+
+    /**
+     * 更新秒杀库存
+     *
+     * @param updateStockReqDTO 请求
+     */
+    void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO);
+
+}

+ 46 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java

@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.promotion.api.seckill.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 更新秒杀库存 request DTO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class SeckillActivityUpdateStockReqDTO {
+
+    /**
+     * 活动编号
+     */
+    private Long activityId;
+    /**
+     * 总购买数量
+     */
+    private Integer count;
+    /**
+     * 活动商品
+     */
+    private List<Item> items;
+
+    @Data
+    public static class Item {
+
+        /**
+         * SPU 编号
+         */
+        private Long spuId;
+        /**
+         * SKU 编号
+         */
+        private Long skuId;
+        /**
+         * 购买数量
+         */
+        private Integer count;
+
+    }
+
+}

+ 1 - 0
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 {
     ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
     ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
     ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
+    ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "更新秒杀活动库存失败,原因秒杀库存不足");
 
     // ========== 秒杀时段 1013009000 ==========
     ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");

+ 39 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.promotion.api.bargain;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
+import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.BARGAIN_ACTIVITY_NOT_EXISTS;
+
+/**
+ * 砍价活动 Api 接口实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+public class BargainActivityApiImpl implements BargainActivityApi {
+
+    @Resource
+    private BargainActivityService bargainActivityService;
+
+    @Override
+    public void updateBargainActivityStock(Long activityId, Integer count) {
+        // 查询砍价活动
+        BargainActivityDO activity = bargainActivityService.getBargainActivity(activityId);
+        if (activity == null) {
+            throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
+        }
+
+        // 更新砍价库存
+        BargainActivityUpdateReqVO reqVO = new BargainActivityUpdateReqVO();
+        reqVO.setId(activityId);
+        reqVO.setStock(activity.getStock() - count);
+        bargainActivityService.updateBargainActivity(reqVO);
+    }
+
+}

+ 75 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java

@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.module.promotion.api.seckill;
+
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
+import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_UPDATE_STOCK_FAIL;
+
+/**
+ * 秒杀活动接口 Api 接口实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+public class SeckillActivityApiImpl implements SeckillActivityApi {
+
+    @Resource
+    private SeckillActivityService activityService;
+
+    @Override
+    public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
+        SeckillActivityDO seckillActivity = activityService.getSeckillActivity(updateStockReqDTO.getActivityId());
+        if (seckillActivity.getStock() < updateStockReqDTO.getCount()) {
+            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
+        }
+        // 获取活动商品
+        List<SeckillProductDO> productDOs = activityService.getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
+        List<SeckillActivityUpdateStockReqDTO.Item> items = updateStockReqDTO.getItems();
+        Map<Long, List<Long>> map = new HashMap<>();
+        items.forEach(item -> {
+            if (map.containsKey(item.getSpuId())) {
+                List<Long> skuIds = map.get(item.getSpuId());
+                skuIds.add(item.getSkuId());
+                map.put(item.getSpuId(), skuIds);
+            } else {
+                List<Long> list = new ArrayList<>();
+                list.add(item.getSkuId());
+                map.put(item.getSpuId(), list);
+            }
+        });
+        // 过滤出购买的商品
+        List<SeckillProductDO> productDOList = CollectionUtils.filterList(productDOs, item -> map.get(item.getSpuId()).contains(item.getSkuId()));
+        Map<Long, SeckillActivityUpdateStockReqDTO.Item> productDOMap = CollectionUtils.convertMap(items, SeckillActivityUpdateStockReqDTO.Item::getSkuId, p -> p);
+        // 检查活动商品库存是否充足
+        boolean b = CollectionUtils.anyMatch(productDOList, item -> {
+            SeckillActivityUpdateStockReqDTO.Item item1 = productDOMap.get(item.getSkuId());
+            return (item.getStock() < item1.getCount()) || (item.getStock() - item1.getCount()) < 0;
+        });
+        if (b) {
+            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
+        }
+        List<SeckillProductDO> doList = CollectionUtils.convertList(productDOList, item -> {
+            item.setStock(item.getStock() - productDOMap.get(item.getSkuId()).getCount());
+            return item;
+        });
+
+        // 更新活动库存
+        seckillActivity.setStock(seckillActivity.getStock() + updateStockReqDTO.getCount());
+        seckillActivity.setTotalStock(seckillActivity.getTotalStock() - updateStockReqDTO.getCount());
+        activityService.updateSeckillActivity(seckillActivity);
+        // 更新活动商品库存
+        activityService.updateSeckillActivityProductByList(doList);
+    }
+
+}

+ 14 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java

@@ -33,6 +33,20 @@ public interface SeckillActivityService {
      */
     void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
 
+    /**
+     * 更新秒杀活动
+     *
+     * @param activityDO 秒杀活动
+     */
+    void updateSeckillActivity(SeckillActivityDO activityDO);
+
+    /**
+     * 更新秒杀活动商品
+     *
+     * @param productDOList 活动商品列表
+     */
+    void updateSeckillActivityProductByList(List<SeckillProductDO> productDOList);
+
     /**
      * 关闭秒杀活动
      *

+ 14 - 4
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 {
      * 1. 校验秒杀时段是否存在
      * 2. 秒杀商品是否参加其它活动
      *
-     * @param configIds 秒杀时段数组
-     * @param spuId 商品 SPU 编号
+     * @param configIds  秒杀时段数组
+     * @param spuId      商品 SPU 编号
      * @param activityId 秒杀活动编号
      */
     private void validateProductConflict(List<Long> configIds, Long spuId, Long activityId) {
@@ -102,7 +102,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
     /**
      * 校验秒杀商品是否都存在
      *
-     * @param spuId 商品 SPU 编号
+     * @param spuId    商品 SPU 编号
      * @param products 秒杀商品
      */
     private void validateProductExists(Long spuId, List<SeckillProductBaseVO> products) {
@@ -144,11 +144,21 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         updateSeckillProduct(updateObj, updateReqVO.getProducts());
     }
 
+    @Override
+    public void updateSeckillActivity(SeckillActivityDO activityDO) {
+        seckillActivityMapper.updateById(activityDO);
+    }
+
+    @Override
+    public void updateSeckillActivityProductByList(List<SeckillProductDO> productDOList) {
+        seckillProductMapper.updateBatch(productDOList);
+    }
+
     /**
      * 更新秒杀商品
      *
      * @param activity 秒杀活动
-     * @param products  该活动的最新商品配置
+     * @param products 该活动的最新商品配置
      */
     private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductBaseVO> products) {
         // 第一步,对比新老数据,获得添加、修改、删除的列表

+ 5 - 0
yudao-module-mall/yudao-module-trade-biz/pom.xml

@@ -82,6 +82,11 @@
             <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-redis</artifactId>
+        </dependency>
+
         <!-- Test 测试相关 -->
         <dependency>
             <groupId>cn.iocoder.boot</groupId>

+ 4 - 0
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;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
 
 @Tag(name = "管理后台 - 交易订单")
 @RestController
@@ -67,6 +68,9 @@ public class TradeOrderController {
     public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
         // 查询订单
         TradeOrderDO order = tradeOrderQueryService.getOrder(id);
+        if (order == null) {
+            return success(null, ORDER_NOT_FOUND.getMsg());
+        }
         // 查询订单项
         List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);
         // orderLog

+ 2 - 2
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;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
-import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
 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;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
 
 @Tag(name = "用户 App - 交易订单")
 @RestController
@@ -83,7 +83,7 @@ public class AppTradeOrderController {
         // 查询订单
         TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
         if (order == null) {
-            return success(null);
+            return success(null, ORDER_NOT_FOUND.getMsg());
         }
 
         // 查询订单项

+ 4 - 0
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 {
     @Schema(description = "拼团团长编号", example = "2048")
     private Long combinationHeadId;
 
+    // ========== 砍价活动相关字段 ==========
+    @Schema(description = "砍价活动编号", example = "123")
+    private Long bargainActivityId;
+
     @Data
     @Schema(description = "用户 App - 商品项")
     @Valid

+ 35 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/no/TradeOrderNoRedisDAO.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.trade.dal.redis.no;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Repository;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+
+/**
+ * 订单序号的 Redis DAO
+ *
+ * @author HUIHUI
+ */
+@Repository
+public class TradeOrderNoRedisDAO {
+    public static final String TRADE_ORDER_NO_PREFIX = "O";
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    /**
+     * 生成序号
+     *
+     * @param prefix 前缀
+     * @return 序号
+     */
+    public String generate(String prefix) {
+        String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
+        Long no = stringRedisTemplate.opsForValue().increment(noPrefix);
+        return noPrefix + no;
+    }
+
+}

+ 69 - 37
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;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.Assert;
-import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.spring.SpringUtil;
@@ -25,11 +24,14 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
 import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
+import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
 import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
+import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
 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;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
+import cn.iocoder.yudao.module.trade.dal.redis.no.TradeOrderNoRedisDAO;
 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.order.*;
@@ -70,7 +73,7 @@ import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
+import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL;
 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID;
 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
 
@@ -88,6 +91,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     private TradeOrderMapper tradeOrderMapper;
     @Resource
     private TradeOrderItemMapper tradeOrderItemMapper;
+    @Resource
+    private TradeOrderNoRedisDAO orderNoRedisDAO;
 
     @Resource
     private CartService cartService;
@@ -111,6 +116,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     @Resource
     private BargainRecordApi bargainRecordApi;
     @Resource
+    private SeckillActivityApi seckillActivityApi;
+    @Resource
+    private BargainActivityApi bargainActivityApi;
+    @Resource
     private MemberUserApi memberUserApi;
     @Resource
     private MemberLevelApi memberLevelApi;
@@ -189,22 +198,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去
         // 拼团
         if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
-            MemberUserRespDTO user = memberUserApi.getUser(userId);
-            List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
-            // TODO 拼团一次应该只能选择一种规格的商品
-            TradeOrderItemDO orderItemDO = orderItems.get(0);
-            if (CollUtil.isNotEmpty(recordRespDTOS)) {
-                List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
-                List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
-                        CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
-                combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
-                        CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
-            }
-
-            combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
+            createCombinationRecord(userId, createReqVO, orderItems, order);
         }
         // 3.2 秒杀的特殊逻辑
-        // TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除
         if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
 
         }
@@ -214,6 +210,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         return order;
     }
 
+    private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {
+        MemberUserRespDTO user = memberUserApi.getUser(userId);
+        List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
+        // TODO 拼团一次应该只能选择一种规格的商品
+        TradeOrderItemDO orderItemDO = orderItems.get(0);
+        if (CollUtil.isNotEmpty(recordRespDTOS)) {
+            List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
+            List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
+                    CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
+            combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
+                    CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
+        }
+
+        combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
+    }
+
     // TODO @puhui999:订单超时,自动取消;
 
     /**
@@ -240,8 +252,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
             address = validateAddress(userId, createReqVO.getAddressId());
         }
         TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address);
+        String no = orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX);
         order.setType(validateActivity(createReqVO));
-        order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @puhui999: 参考支付订单,的 no 生成哈;
+        order.setNo(no);
         order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
         order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
         order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
@@ -293,19 +306,23 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
                                        TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
                                        TradePriceCalculateRespBO calculateRespBO) {
-        // 下单时扣减商品库存
-        // TODO @puhui999:扣库存,需要前置;
+        Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);
         // 1)如果是秒杀商品:额外扣减秒杀的库存;
-        // 2)如果是拼团活动:额外扣减拼团的库存;
-        // 3)如果是砍价活动:额外扣减砍价的库存;
-        productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));
-
-        // 删除购物车商品
-        Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
-        if (CollUtil.isNotEmpty(cartIds)) {
-            cartService.deleteCart(userId, cartIds);
-        }
-
+        if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {
+            SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();
+            updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());
+            updateStockReqDTO.setCount(count);
+            updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> {
+                SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();
+                item1.setSpuId(item.getSpuId());
+                item1.setSkuId(item.getSkuId());
+                item1.setCount(item.getCount());
+                return item1;
+            }));
+            seckillActivityApi.updateSeckillStock(updateStockReqDTO);
+        }
+        // 2)如果是砍价活动:额外扣减砍价的库存;
+        bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count);
         // 扣减积分 TODO 芋艿:待实现,需要前置;
         // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
 
@@ -315,6 +332,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
                     .setOrderId(tradeOrderDO.getId()));
         }
 
+        // 下单时扣减商品库存
+        productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));
+
+        // 删除购物车商品
+        Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
+        if (CollUtil.isNotEmpty(cartIds)) {
+            cartService.deleteCart(userId, cartIds);
+        }
+
         // 生成预支付
         createPayOrder(tradeOrderDO, orderItems, calculateRespBO);
 
@@ -464,11 +490,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
      */
     private TradeOrderDO validateOrderDeliverable(Long id) {
         TradeOrderDO order = validateOrderExists(id);
-        // 校验订单是否是待发货状态
-        // TODO @puhui999:已经发货,可以重新发货,修改信息;
-        if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) {
-            throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
-        }
         // 校验订单是否退款
         if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
             throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE);
@@ -540,14 +561,25 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         if (order.getPayStatus()) {
             throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
         }
-        // TODO @puhui999:如果改价,需要校验下是否真的变化;
+        if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) {
+            throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL);
+        }
 
-        // 更新
-        // TODO @puhui999:TradeOrderItemDO 需要做 adjustPrice 的分摊;另外,支付订单那的价格,需要 update 下;
+        List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId());
+        // TradeOrderItemDO 需要做 adjustPrice 的分摊
+        int price = reqVO.getAdjustPrice() / itemDOs.size();
+        itemDOs.forEach(item -> {
+            item.setAdjustPrice(price);
+        });
+        // 更新 TradeOrderItem
+        tradeOrderItemMapper.updateBatch(itemDOs);
+        // 更新订单
         TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO);
         update.setPayPrice(update.getPayPrice() + update.getAdjustPrice());
         // TODO @芋艿:改价时,赠送的积分,要不要做改动???
         tradeOrderMapper.updateById(update);
+        // 更新支付订单
+        payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice());
     }
 
     @Override

+ 7 - 0
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 {
      */
     PayOrderRespDTO getOrder(Long id);
 
+    /**
+     * 更新支付订单价格
+     *
+     * @param payOrderId 支付单编号
+     * @param payPrice   支付单价格
+     */
+    void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
 }

+ 1 - 0
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 {
     ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
     ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
     ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1007002006, "支付订单调价失败,原因:支付订单已付款,不能调价");
+    ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1007002007, "支付订单调价失败,原因:价格没有变化");
 
     // ========== ORDER 模块(拓展单) 1007003000 ==========
     ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");

+ 6 - 0
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 {
         return PayOrderConvert.INSTANCE.convert2(order);
     }
 
+    @Override
+    public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
+        payOrderService.updatePayOrderPriceById(payOrderId, payPrice);
+    }
+
+
 }

+ 11 - 3
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 {
     /**
      * 获得支付订单
      *
-     * @param appId 应用编号
+     * @param appId           应用编号
      * @param merchantOrderId 商户订单编号
      * @return 支付订单
      */
@@ -75,7 +75,7 @@ public interface PayOrderService {
      * 提交支付
      * 此时,会发起支付渠道的调用
      *
-     * @param reqVO 提交请求
+     * @param reqVO  提交请求
      * @param userIp 提交 IP
      * @return 提交结果
      */
@@ -93,11 +93,19 @@ public interface PayOrderService {
     /**
      * 更新支付订单的退款金额
      *
-     * @param id 编号
+     * @param id              编号
      * @param incrRefundPrice 增加的退款金额
      */
     void updateOrderRefundPrice(Long id, Integer incrRefundPrice);
 
+    /**
+     * 更新支付订单价格
+     *
+     * @param payOrderId 支付单编号
+     * @param payPrice   支付单价格
+     */
+    void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
+
     /**
      * 获得支付订单
      *

+ 11 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java

@@ -410,6 +410,17 @@ public class PayOrderServiceImpl implements PayOrderService {
         }
     }
 
+    @Override
+    public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
+        PayOrderDO order = orderMapper.selectById(payOrderId);
+        if (order == null) {
+            throw exception(ORDER_NOT_FOUND);
+        }
+
+        order.setPrice(payPrice);
+        orderMapper.updateById(order);
+    }
+
     @Override
     public PayOrderExtensionDO getOrderExtension(Long id) {
         return orderExtensionMapper.selectById(id);