Browse Source

购物卡、购物订单代码提交

wangzhijun 1 week ago
parent
commit
8d195a0ff8

+ 4 - 3
nightFragrance-massage/src/main/java/com/ylx/giftCard/controller/GiftCardController.java

@@ -15,6 +15,7 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import java.util.Map;
 
 @RestController
 @RequestMapping("/gift/card")
@@ -34,9 +35,9 @@ public class GiftCardController {
 
     @PostMapping("/purchase")
     @ApiOperation("购物卡购买接口")
-    public R<String> purchaseGiftCard(@Validated @RequestBody GiftCardPurchaseDTO dto) {
-        boolean success = giftCardService.purchaseGiftCard(dto);
-        return success ? R.ok("购买成功") : R.fail("购买失败,库存不足或商品不存在");
+    public R<Map<String, Object>> purchaseGiftCard(@Validated @RequestBody GiftCardPurchaseDTO dto) {
+        Map<String, Object> data =giftCardService.purchaseGiftCard(dto);
+        return R.ok(data);
     }
 
     @GetMapping("/{id}/detail")

+ 1 - 1
nightFragrance-massage/src/main/java/com/ylx/giftCard/domain/GiftCardOrder.java

@@ -98,7 +98,7 @@ public class GiftCardOrder extends BaseEntity {
     private BigDecimal commissionAmount;
 
     /**
-     * 订单状态:1=已支付,2=已退款,3=已过期
+     * 订单状态:0=待支付,1=已支付,2=已退款,3=已过期
      */
     private Integer status;
 

+ 21 - 0
nightFragrance-massage/src/main/java/com/ylx/giftCard/enums/GiftCardOrderStatusEnum.java

@@ -0,0 +1,21 @@
+package com.ylx.giftCard.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum GiftCardOrderStatusEnum {
+
+    WAIT_PAY(0, "待支付"),
+    PAID(1, "已支付"),
+    REFUNDED(2, "已退款"),
+    EXPIRED(3, "已过期"),
+    CANCEL(4, "已取消");
+
+    private final Integer code;
+    private final String info;
+
+    GiftCardOrderStatusEnum(Integer code, String info) {
+        this.code = code;
+        this.info = info;
+    }
+}

+ 4 - 1
nightFragrance-massage/src/main/java/com/ylx/giftCard/service/IGiftCardOrderService.java

@@ -1,6 +1,7 @@
 package com.ylx.giftCard.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.ylx.common.core.domain.model.WxLoginUser;
 import com.ylx.giftCard.domain.GiftCard;
 import com.ylx.giftCard.domain.GiftCardOrder;
 
@@ -8,5 +9,7 @@ import java.util.List;
 
 public interface IGiftCardOrderService extends IService<GiftCardOrder> {
 
-    GiftCardOrder buildOrder(GiftCard card, Integer quantity, String merchantId);
+    GiftCardOrder buildOrder(GiftCard card, Integer quantity, String merchantId, WxLoginUser wxLoginUser);
+
+    void cancelOrder(Long id);
 }

+ 3 - 1
nightFragrance-massage/src/main/java/com/ylx/giftCard/service/IGiftCardService.java

@@ -6,11 +6,13 @@ import com.ylx.giftCard.domain.dto.GiftCardPurchaseDTO;
 import com.ylx.giftCard.domain.vo.GiftCardDetailVO;
 import com.ylx.giftCard.domain.vo.GiftCardVO;
 
+import java.util.Map;
+
 public interface IGiftCardService {
 
     Page<GiftCardVO> getGiftCardPage(Page<GiftCard> page);
 
-    boolean purchaseGiftCard(GiftCardPurchaseDTO dto);
+    Map<String, Object> purchaseGiftCard(GiftCardPurchaseDTO dto);
 
     GiftCardDetailVO getGiftCardDetail(Long id);
 }

+ 28 - 11
nightFragrance-massage/src/main/java/com/ylx/giftCard/service/impl/GiftCardOrderServiceImpl.java

@@ -10,6 +10,7 @@ import com.ylx.common.utils.DateUtils;
 import com.ylx.common.utils.SecurityUtils;
 import com.ylx.giftCard.domain.GiftCard;
 import com.ylx.giftCard.domain.GiftCardOrder;
+import com.ylx.giftCard.enums.GiftCardOrderStatusEnum;
 import com.ylx.giftCard.mapper.GiftCardOrderMapper;
 import com.ylx.giftCard.service.IGiftCardOrderService;
 import com.ylx.massage.domain.TJs;
@@ -31,24 +32,17 @@ public class GiftCardOrderServiceImpl extends ServiceImpl<GiftCardOrderMapper, G
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public GiftCardOrder buildOrder(GiftCard card, Integer quantity, String merchantId) {
+    public GiftCardOrder buildOrder(GiftCard card, Integer quantity, String merchantId, WxLoginUser wxLoginUser) {
 
         // 1. 参数校验
         if (ObjectUtil.isNull(card)) {
             throw new IllegalArgumentException("购物卡信息不能为空");
         }
-        if (quantity == null || quantity <= 0) {
+        if (ObjectUtil.isNull(quantity) || quantity <= 0) {
             throw new IllegalArgumentException("购买数量必须大于0");
         }
 
-        // 2. 获取用户信息
-        WxLoginUser wxLoginUser = SecurityUtils.getWxLoginUser();
-        if (ObjectUtil.isNull(wxLoginUser)) {
-            log.warn("用户未登录,无法创建订单");
-            throw new ServiceException("用户未登录");
-        }
-
-        // 3. 创建订单对象
+        // 2. 创建订单对象
         GiftCardOrder order = new GiftCardOrder();
 
         // 4. 生成唯一订单号(使用更安全的方式)
@@ -69,7 +63,7 @@ public class GiftCardOrderServiceImpl extends ServiceImpl<GiftCardOrderMapper, G
         order.setPurchaseQuantity(quantity);
 
         // 9. 设置订单状态和时间
-        order.setStatus(1); // 已支付
+        order.setStatus(GiftCardOrderStatusEnum.WAIT_PAY.getCode()); // 待支付
         order.setCreateTime(DateUtils.getNowDate());
         order.setUpdateTime(order.getCreateTime());
         int rowsAffected = this.baseMapper.insert(order);
@@ -80,6 +74,29 @@ public class GiftCardOrderServiceImpl extends ServiceImpl<GiftCardOrderMapper, G
         return order;
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void cancelOrder(Long id) {
+        // 1. 查询订单
+        GiftCardOrder order = this.getById(id);
+        if (ObjectUtil.isNull(order)) {
+            throw new ServiceException("订单不存在");
+        }
+        // 仅待支付订单可取消
+        if (!GiftCardOrderStatusEnum.PAID.getCode().equals(order.getStatus())) {
+            throw new ServiceException("当前订单状态不支持取消");
+        }
+        // 2. 修改订单状态为已取消
+        order.setStatus(GiftCardOrderStatusEnum.CANCEL.getCode());
+        order.setUpdateTime(DateUtils.getNowDate());
+        boolean update = this.updateById(order);
+        if (!update) {
+            log.error("订单取消失败,订单号:{}", order.getOrderNo());
+            throw new ServiceException("订单取消失败");
+        }
+        log.info("订单取消成功,订单号:{},购物卡ID:{}", order.getOrderNo(), order.getGiftCardId());
+    }
+
     /**
      * 生成唯一订单号
      */

+ 77 - 73
nightFragrance-massage/src/main/java/com/ylx/giftCard/service/impl/GiftCardServiceImpl.java

@@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ylx.common.core.domain.model.WxLoginUser;
 import com.ylx.common.exception.ServiceException;
 import com.ylx.common.utils.SecurityUtils;
+import com.ylx.common.weixinPay.service.WxPayV3Service;
 import com.ylx.giftCard.domain.GiftCard;
 import com.ylx.giftCard.domain.GiftCardOrder;
 import com.ylx.giftCard.domain.dto.GiftCardPurchaseDTO;
@@ -18,15 +19,13 @@ import com.ylx.giftCard.domain.vo.GiftCardVO;
 import com.ylx.giftCard.mapper.GiftCardMapper;
 import com.ylx.giftCard.service.IGiftCardOrderService;
 import com.ylx.giftCard.service.IGiftCardService;
-import com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailAddDto;
-import com.ylx.shopingfundsdetail.service.ShoppingFundsDetailService;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -36,7 +35,7 @@ public class GiftCardServiceImpl extends ServiceImpl<GiftCardMapper, GiftCard> i
     @Resource
     private IGiftCardOrderService giftCardOrderService;
     @Resource
-    private ShoppingFundsDetailService shoppingFundsDetailService;
+    private WxPayV3Service wxPayV3Service;
 
     private static final int NOT_DELETE = 0;
     private static final int PUBLISHED = 1;
@@ -68,59 +67,37 @@ public class GiftCardServiceImpl extends ServiceImpl<GiftCardMapper, GiftCard> i
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public boolean purchaseGiftCard(GiftCardPurchaseDTO dto) {
+    public Map<String, Object> purchaseGiftCard(GiftCardPurchaseDTO dto) {
+
+        // 1. 获取当前用户
+        WxLoginUser wxLoginUser = SecurityUtils.getWxLoginUser();
+        if (ObjectUtil.isNull(wxLoginUser)) {
+            log.warn("用户未登录,无法创建订单");
+            throw new ServiceException("用户未登录");
+        }
+
         Long id = dto.getId();
         Integer quantity = dto.getQuantity();
         String merchantId = dto.getMerchantId();
 
+        // 2. 查询并校验购物卡
         GiftCard card = this.getById(id);
-        if (ObjectUtil.isNull(card)) {
-            log.warn("购买失败,购物卡不存在,ID: {}", id);
-            return false;
-        }
-
-        // 2. 校验购物卡状态
-        if (card.getIsDelete() != NOT_DELETE) {
-            log.warn("购买失败,购物卡已删除,ID: {}", id);
-            return false;
-        }
-        if (card.getIsPublished() != PUBLISHED) {
-            log.warn("购买失败,购物卡未上架,ID: {}", id);
-            return false;
-        }
-
-        // 3. 校验库存是否充足
-        if (card.getStock() < quantity) {
-            log.warn("购买失败,库存不足,ID: {},库存: {},需求数量: {}", id, card.getStock(), quantity);
-            return false;
-        }
-
-        // 4. 扣减库存(使用乐观锁防止超卖)
-        String updateExpr = String.format("stock = stock - %d, sales = sales + %d", quantity, quantity);
-
-        LambdaUpdateWrapper<GiftCard> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.eq(GiftCard::getId, id)
-                .eq(GiftCard::getIsDelete, NOT_DELETE)
-                .eq(GiftCard::getIsPublished, PUBLISHED)
-                .ge(GiftCard::getStock, quantity) // 关键:确保库存充足
-                .setSql(updateExpr);
-
-        int rowsAffected = this.baseMapper.update(null, updateWrapper);
+        validateGiftCard(card, quantity);
 
+        // 3. 乐观锁扣减库存(增加状态校验,防止无效更新)
+        int rowsAffected = deductStockOptimisticLock(card.getId(), dto.getQuantity());
         if (rowsAffected <= 0) {
             log.warn("购买失败,库存不足或商品不存在,购物卡ID: {}", id);
-            return false;
+            throw new ServiceException("库存不足或商品状态异常");
         }
 
         log.info("购买成功,购物卡ID: {}, 数量: {}", id, quantity);
 
-        // 5. 异步创建订单(传入完整的购物卡对象,避免异步方法中再次查询)
-        GiftCardOrder giftCardOrder = createOrderAsync(card, quantity, merchantId);
+        // 4. 创建订单
+        GiftCardOrder order = this.giftCardOrderService.buildOrder(card, quantity, merchantId, wxLoginUser);
 
-        // 6. 异步添加购物金明细
-        addShoppingFundsDetailAsync(card, giftCardOrder);
-
-        return true;
+        //  5. 调用微信支付
+        return createWxPayOrder(order, wxLoginUser);
     }
 
     @Override
@@ -142,44 +119,71 @@ public class GiftCardServiceImpl extends ServiceImpl<GiftCardMapper, GiftCard> i
     }
 
     /**
-     * 异步创建订单
+     * 校验购物卡有效性
      */
-    @Async
-    public GiftCardOrder createOrderAsync(GiftCard card, Integer quantity, String merchantId) {
-        try {
-            // 注意:异步方法中不要依赖主线程的事务,订单创建失败不应影响库存扣减
-            GiftCardOrder order = this.giftCardOrderService.buildOrder(card, quantity, merchantId);
-
-            if (ObjectUtil.isNotNull(order)) {
-                log.info("购物卡订单创建成功,购物卡ID: {}", card.getId());
-            } else {
-                log.warn("购物卡订单创建返回为空,购物卡ID: {}", card.getId());
-            }
-            return order;
-        } catch (Exception e) {
-            log.error("异步创建订单失败,订单数据: cardId={}, quantity={}, merchantId={}",
-                    card.getId(), quantity, merchantId, e);
+    private void validateGiftCard(GiftCard card, Integer quantity) {
+        if (ObjectUtil.isNull(card)) {
+            throw new ServiceException("商品不存在");
+        }
+        if (card.getIsDelete() != NOT_DELETE) {
+            log.warn("购买失败,购物卡已删除,ID: {}", card.getId());
+            throw new ServiceException("购物卡已删除");
+        }
+        if (card.getIsPublished() != PUBLISHED) {
+            log.warn("购买失败,购物卡未上架,ID: {}", card.getId());
+            throw new ServiceException("购物卡未上架");
+        }
+        if (card.getStock() < quantity) {
+            log.warn("购买失败,库存不足,ID: {},库存: {},需求数量: {}", card.getId(), card.getStock(), quantity);
+            throw new ServiceException("库存不足");
         }
-        return null;
+
+    }
+
+    /**
+     * 乐观锁扣减库存(增加状态条件,确保只更新有效记录)
+     */
+    private int deductStockOptimisticLock(Long cardId, Integer quantity) {
+        LambdaUpdateWrapper<GiftCard> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(GiftCard::getId, cardId)
+                .eq(GiftCard::getIsDelete, NOT_DELETE)
+                .eq(GiftCard::getIsPublished, PUBLISHED)
+                .ge(GiftCard::getStock, quantity) // 库存充足时才更新
+                .setSql("stock = stock - " + quantity + ", sales = sales + " + quantity);
+        return baseMapper.update(null, wrapper);
     }
 
     /**
-     * 异步新增购物金明细
+     * 补偿回滚库存
      */
-    @Async
-    public void addShoppingFundsDetailAsync(GiftCard card, GiftCardOrder giftCardOrder) {
+    private void recoverStock(Long cardId, Integer num) {
+        GiftCard updateEntity = new GiftCard();
+        LambdaUpdateWrapper<GiftCard> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.eq(GiftCard::getId, cardId)
+                .eq(GiftCard::getIsDelete, NOT_DELETE);
+        updateWrapper.setSql("stock = stock + #{num}, sales = sales - #{num}");
+        // 数据放到实体里
+        updateEntity.setStock(num);
+        baseMapper.update(updateEntity, updateWrapper);
+    }
 
+    /**
+     * 创建微信支付订单(事务外执行,减少事务时长)
+     */
+    private Map<String, Object> createWxPayOrder(GiftCardOrder order, WxLoginUser wxLoginUser) {
         try {
-            ShoppingFundsDetailAddDto dto = new ShoppingFundsDetailAddDto();
-            dto.setGiftCardId(card.getId());
-            dto.setAmount(card.getAmount());
-            dto.setUserId(giftCardOrder.getUserId());
-            dto.setExpenseType(0);
-            this.shoppingFundsDetailService.addShoppingFundsDetail(dto);
-
+            return wxPayV3Service.createV3JsapiOrder(
+                    order.getOrderNo(),
+                    order.getPayAmount(),
+                    "购物卡购买",
+                    wxLoginUser.getCOpenid()
+            );
         } catch (Exception e) {
-            log.error("异步新增购物金明细失败,订单数据: cardId={}, amount={}, userId={}",
-                    card.getId(), card.getAmount(), giftCardOrder.getUserId(), e);
+            log.error("微信支付下单失败,订单号: {}", order.getOrderNo(), e);
+            // 支付失败:恢复库存、修改订单为取消
+            recoverStock(order.getGiftCardId(), order.getPurchaseQuantity());
+            this.giftCardOrderService.cancelOrder(order.getId());
+            throw new ServiceException("支付服务异常,请稍后重试");
         }
     }