GiftCardServiceImpl.java 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. package com.ylx.giftCard.service.impl;
  2. import cn.hutool.core.bean.BeanUtil;
  3. import cn.hutool.core.collection.CollectionUtil;
  4. import cn.hutool.core.util.ObjectUtil;
  5. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  6. import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  7. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  8. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  9. import com.ylx.common.core.domain.model.WxLoginUser;
  10. import com.ylx.common.exception.ServiceException;
  11. import com.ylx.common.utils.SecurityUtils;
  12. import com.ylx.common.weixinPay.service.WxPayV3Service;
  13. import com.ylx.giftCard.domain.GiftCard;
  14. import com.ylx.giftCard.domain.GiftCardOrder;
  15. import com.ylx.giftCard.domain.dto.GiftCardPurchaseDTO;
  16. import com.ylx.giftCard.domain.vo.GiftCardDetailVO;
  17. import com.ylx.giftCard.domain.vo.GiftCardVO;
  18. import com.ylx.giftCard.mapper.GiftCardMapper;
  19. import com.ylx.giftCard.service.IGiftCardOrderService;
  20. import com.ylx.giftCard.service.IGiftCardService;
  21. import lombok.extern.slf4j.Slf4j;
  22. import org.springframework.stereotype.Service;
  23. import org.springframework.transaction.annotation.Transactional;
  24. import javax.annotation.Resource;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.stream.Collectors;
  28. @Slf4j
  29. @Service
  30. public class GiftCardServiceImpl extends ServiceImpl<GiftCardMapper, GiftCard> implements IGiftCardService {
  31. @Resource
  32. private IGiftCardOrderService giftCardOrderService;
  33. @Resource
  34. private WxPayV3Service wxPayV3Service;
  35. private static final int NOT_DELETE = 0;
  36. private static final int PUBLISHED = 1;
  37. @Override
  38. public Page<GiftCardVO> getGiftCardPage(Page<GiftCard> page) {
  39. LambdaQueryWrapper<GiftCard> wrapper = new LambdaQueryWrapper<>();
  40. wrapper.eq(GiftCard::getIsDelete, NOT_DELETE);
  41. wrapper.eq(GiftCard::getIsPublished, PUBLISHED);
  42. wrapper.orderByDesc(GiftCard::getCreateTime);
  43. Page<GiftCard> giftCardPage = this.baseMapper.selectPage(page, wrapper);
  44. Page<GiftCardVO> pageData = new Page<>(
  45. giftCardPage.getCurrent(),
  46. giftCardPage.getSize(),
  47. giftCardPage.getTotal()
  48. );
  49. if (CollectionUtil.isNotEmpty(giftCardPage.getRecords())) {
  50. List<GiftCardVO> voList = giftCardPage.getRecords().stream()
  51. .map(GiftCardVO::new)
  52. .collect(Collectors.toList());
  53. pageData.setRecords(voList);
  54. }
  55. return pageData;
  56. }
  57. @Override
  58. @Transactional(rollbackFor = Exception.class)
  59. public Map<String, Object> purchaseGiftCard(GiftCardPurchaseDTO dto) {
  60. // 1. 获取当前用户
  61. WxLoginUser wxLoginUser = SecurityUtils.getWxLoginUser();
  62. if (ObjectUtil.isNull(wxLoginUser)) {
  63. log.warn("用户未登录,无法创建订单");
  64. throw new ServiceException("用户未登录");
  65. }
  66. Long id = dto.getId();
  67. Integer quantity = dto.getQuantity();
  68. String merchantId = dto.getMerchantId();
  69. // 2. 查询并校验购物卡
  70. GiftCard card = this.getById(id);
  71. validateGiftCard(card, quantity);
  72. // 3. 乐观锁扣减库存(增加状态校验,防止无效更新)
  73. int rowsAffected = deductStockOptimisticLock(card.getId(), dto.getQuantity());
  74. if (rowsAffected <= 0) {
  75. log.warn("购买失败,库存不足或商品不存在,购物卡ID: {}", id);
  76. throw new ServiceException("库存不足或商品状态异常");
  77. }
  78. log.info("购买成功,购物卡ID: {}, 数量: {}", id, quantity);
  79. // 4. 创建订单
  80. GiftCardOrder order = this.giftCardOrderService.buildOrder(card, quantity, merchantId, wxLoginUser);
  81. // 5. 调用微信支付
  82. return createWxPayOrder(order, wxLoginUser);
  83. }
  84. @Override
  85. public GiftCardDetailVO getGiftCardDetail(Long id) {
  86. LambdaQueryWrapper<GiftCard> wrapper = new LambdaQueryWrapper<>();
  87. wrapper.eq(GiftCard::getId, id)
  88. .eq(GiftCard::getIsDelete, NOT_DELETE)
  89. .eq(GiftCard::getIsPublished, PUBLISHED);
  90. GiftCard card = this.getOne(wrapper);
  91. if (ObjectUtil.isNull(card)) {
  92. return null;
  93. }
  94. GiftCardDetailVO vo = new GiftCardDetailVO();
  95. BeanUtil.copyProperties(card, vo);
  96. return vo;
  97. }
  98. /**
  99. * 校验购物卡有效性
  100. */
  101. private void validateGiftCard(GiftCard card, Integer quantity) {
  102. if (ObjectUtil.isNull(card)) {
  103. throw new ServiceException("商品不存在");
  104. }
  105. if (card.getIsDelete() != NOT_DELETE) {
  106. log.warn("购买失败,购物卡已删除,ID: {}", card.getId());
  107. throw new ServiceException("购物卡已删除");
  108. }
  109. if (card.getIsPublished() != PUBLISHED) {
  110. log.warn("购买失败,购物卡未上架,ID: {}", card.getId());
  111. throw new ServiceException("购物卡未上架");
  112. }
  113. if (card.getStock() < quantity) {
  114. log.warn("购买失败,库存不足,ID: {},库存: {},需求数量: {}", card.getId(), card.getStock(), quantity);
  115. throw new ServiceException("库存不足");
  116. }
  117. }
  118. /**
  119. * 乐观锁扣减库存(增加状态条件,确保只更新有效记录)
  120. */
  121. private int deductStockOptimisticLock(Long cardId, Integer quantity) {
  122. LambdaUpdateWrapper<GiftCard> wrapper = new LambdaUpdateWrapper<>();
  123. wrapper.eq(GiftCard::getId, cardId)
  124. .eq(GiftCard::getIsDelete, NOT_DELETE)
  125. .eq(GiftCard::getIsPublished, PUBLISHED)
  126. .ge(GiftCard::getStock, quantity) // 库存充足时才更新
  127. .setSql("stock = stock - " + quantity + ", sales = sales + " + quantity);
  128. return baseMapper.update(null, wrapper);
  129. }
  130. /**
  131. * 补偿回滚库存
  132. */
  133. private void recoverStock(Long cardId, Integer num) {
  134. GiftCard updateEntity = new GiftCard();
  135. LambdaUpdateWrapper<GiftCard> updateWrapper = new LambdaUpdateWrapper<>();
  136. updateWrapper.eq(GiftCard::getId, cardId)
  137. .eq(GiftCard::getIsDelete, NOT_DELETE);
  138. updateWrapper.setSql("stock = stock + #{num}, sales = sales - #{num}");
  139. // 数据放到实体里
  140. updateEntity.setStock(num);
  141. baseMapper.update(updateEntity, updateWrapper);
  142. }
  143. /**
  144. * 创建微信支付订单(事务外执行,减少事务时长)
  145. */
  146. private Map<String, Object> createWxPayOrder(GiftCardOrder order, WxLoginUser wxLoginUser) {
  147. try {
  148. return wxPayV3Service.createV3JsapiOrder(
  149. order.getOrderNo(),
  150. order.getPayAmount(),
  151. "购物卡购买",
  152. wxLoginUser.getCOpenid()
  153. );
  154. } catch (Exception e) {
  155. log.error("微信支付下单失败,订单号: {}", order.getOrderNo(), e);
  156. // 支付失败:恢复库存、修改订单为取消
  157. recoverStock(order.getGiftCardId(), order.getPurchaseQuantity());
  158. this.giftCardOrderService.cancelOrder(order.getId());
  159. throw new ServiceException("支付服务异常,请稍后重试");
  160. }
  161. }
  162. }