package com.ylx.giftCard.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 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; import com.ylx.giftCard.domain.vo.GiftCardDetailVO; 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 lombok.extern.slf4j.Slf4j; 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 @Service public class GiftCardServiceImpl extends ServiceImpl implements IGiftCardService { @Resource private IGiftCardOrderService giftCardOrderService; @Resource private WxPayV3Service wxPayV3Service; private static final int NOT_DELETE = 0; private static final int PUBLISHED = 1; @Override public Page getGiftCardPage(Page page) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(GiftCard::getIsDelete, NOT_DELETE); wrapper.eq(GiftCard::getIsPublished, PUBLISHED); wrapper.orderByDesc(GiftCard::getCreateTime); Page giftCardPage = this.baseMapper.selectPage(page, wrapper); Page pageData = new Page<>( giftCardPage.getCurrent(), giftCardPage.getSize(), giftCardPage.getTotal() ); if (CollectionUtil.isNotEmpty(giftCardPage.getRecords())) { List voList = giftCardPage.getRecords().stream() .map(GiftCardVO::new) .collect(Collectors.toList()); pageData.setRecords(voList); } return pageData; } @Override @Transactional(rollbackFor = Exception.class) public Map 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); validateGiftCard(card, quantity); // 3. 乐观锁扣减库存(增加状态校验,防止无效更新) int rowsAffected = deductStockOptimisticLock(card.getId(), dto.getQuantity()); if (rowsAffected <= 0) { log.warn("购买失败,库存不足或商品不存在,购物卡ID: {}", id); throw new ServiceException("库存不足或商品状态异常"); } log.info("购买成功,购物卡ID: {}, 数量: {}", id, quantity); // 4. 创建订单 GiftCardOrder order = this.giftCardOrderService.buildOrder(card, quantity, merchantId, wxLoginUser); // 5. 调用微信支付 return createWxPayOrder(order, wxLoginUser); } @Override public GiftCardDetailVO getGiftCardDetail(Long id) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(GiftCard::getId, id) .eq(GiftCard::getIsDelete, NOT_DELETE) .eq(GiftCard::getIsPublished, PUBLISHED); GiftCard card = this.getOne(wrapper); if (ObjectUtil.isNull(card)) { return null; } GiftCardDetailVO vo = new GiftCardDetailVO(); BeanUtil.copyProperties(card, vo); return vo; } /** * 校验购物卡有效性 */ 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("库存不足"); } } /** * 乐观锁扣减库存(增加状态条件,确保只更新有效记录) */ private int deductStockOptimisticLock(Long cardId, Integer quantity) { LambdaUpdateWrapper 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); } /** * 补偿回滚库存 */ private void recoverStock(Long cardId, Integer num) { GiftCard updateEntity = new GiftCard(); LambdaUpdateWrapper 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 createWxPayOrder(GiftCardOrder order, WxLoginUser wxLoginUser) { try { return wxPayV3Service.createV3JsapiOrder( order.getOrderNo(), order.getPayAmount(), "购物卡购买", wxLoginUser.getCOpenid() ); } catch (Exception e) { log.error("微信支付下单失败,订单号: {}", order.getOrderNo(), e); // 支付失败:恢复库存、修改订单为取消 recoverStock(order.getGiftCardId(), order.getPurchaseQuantity()); this.giftCardOrderService.cancelOrder(order.getId()); throw new ServiceException("支付服务异常,请稍后重试"); } } }