|
|
@@ -1,11 +1,157 @@
|
|
|
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.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.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.concurrent.CompletableFuture;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
@Service
|
|
|
public class GiftCardServiceImpl extends ServiceImpl<GiftCardMapper, GiftCard> implements IGiftCardService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private IGiftCardOrderService giftCardOrderService;
|
|
|
+
|
|
|
+ private static final int NOT_DELETE = 0;
|
|
|
+ private static final int PUBLISHED = 1;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Page<GiftCardVO> getGiftCardPage(Page<GiftCard> page) {
|
|
|
+
|
|
|
+ LambdaQueryWrapper<GiftCard> wrapper = new LambdaQueryWrapper<>();
|
|
|
+ wrapper.eq(GiftCard::getIsDelete, NOT_DELETE);
|
|
|
+ wrapper.eq(GiftCard::getIsPublished, PUBLISHED);
|
|
|
+ wrapper.orderByDesc(GiftCard::getCreateTime);
|
|
|
+
|
|
|
+ Page<GiftCard> giftCardPage = this.baseMapper.selectPage(page, wrapper);
|
|
|
+ Page<GiftCardVO> pageData = new Page<>(
|
|
|
+ giftCardPage.getCurrent(),
|
|
|
+ giftCardPage.getSize(),
|
|
|
+ giftCardPage.getTotal()
|
|
|
+ );
|
|
|
+
|
|
|
+ if (CollectionUtil.isNotEmpty(giftCardPage.getRecords())) {
|
|
|
+ List<GiftCardVO> voList = giftCardPage.getRecords().stream()
|
|
|
+ .map(GiftCardVO::new)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ pageData.setRecords(voList);
|
|
|
+ }
|
|
|
+
|
|
|
+ return pageData;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public boolean purchaseGiftCard(GiftCardPurchaseDTO dto) {
|
|
|
+ Long id = dto.getId();
|
|
|
+ Integer quantity = dto.getQuantity();
|
|
|
+ String merchantId = dto.getMerchantId();
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ if (rowsAffected <= 0) {
|
|
|
+ log.warn("购买失败,库存不足或商品不存在,购物卡ID: {}", id);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("购买成功,购物卡ID: {}, 数量: {}", id, quantity);
|
|
|
+
|
|
|
+ // 5. 异步创建订单(传入完整的购物卡对象,避免异步方法中再次查询)
|
|
|
+ createOrderAsync(card, quantity, merchantId);
|
|
|
+
|
|
|
+ // 6. 异步添加购物金明细 TODO
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public GiftCardDetailVO getGiftCardDetail(Long id) {
|
|
|
+
|
|
|
+ LambdaQueryWrapper<GiftCard> 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 异步创建订单
|
|
|
+ */
|
|
|
+ @Async
|
|
|
+ public void createOrderAsync(GiftCard card, Integer quantity, String merchantId) {
|
|
|
+ try {
|
|
|
+ // 注意:异步方法中不要依赖主线程的事务,订单创建失败不应影响库存扣减
|
|
|
+ List<GiftCardOrder> orders = this.giftCardOrderService.buildOrders(card, quantity, merchantId);
|
|
|
+
|
|
|
+ if (orders != null && !orders.isEmpty()) {
|
|
|
+ log.info("购物卡订单创建成功,订单数量: {},购物卡ID: {}", orders.size(), card.getId());
|
|
|
+ } else {
|
|
|
+ log.warn("购物卡订单创建返回为空,购物卡ID: {}", card.getId());
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("异步创建订单失败,订单数据: cardId={}, quantity={}, merchantId={}",
|
|
|
+ card.getId(), quantity, merchantId, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|