package com.ylx.giftCard.service.impl; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; import com.ylx.common.core.domain.model.WxLoginUser; import com.ylx.common.exception.ServiceException; import com.ylx.common.utils.DateUtils; import com.ylx.giftCard.domain.GiftCard; import com.ylx.giftCard.domain.GiftCardOrder; import com.ylx.giftCard.domain.dto.GiftCardOrderQueryDTO; import com.ylx.giftCard.domain.dto.UserShoppingFundsDetailQueryDTO; import com.ylx.giftCard.domain.vo.GiftCardOrderExportVO; import com.ylx.giftCard.domain.vo.GiftCardOrderPageVO; import com.ylx.giftCard.domain.vo.UserShoppingFundsDetailItemVO; import com.ylx.giftCard.domain.vo.UserShoppingFundsDetailVO; import com.ylx.giftCard.domain.vo.UserShoppingFundsSummaryVO; import com.ylx.giftCard.enums.GiftCardOrderStatusEnum; import com.ylx.giftCard.mapper.GiftCardOrderMapper; import com.ylx.giftCard.service.IGiftCardOrderService; import com.ylx.massage.domain.TJs; import com.ylx.massage.domain.TWxUser; import com.ylx.massage.service.TJsService; import com.ylx.massage.service.TWxUserService; import com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailAddDto; import com.ylx.shopingfundsdetail.enums.ShoppingFundsExpenseTypeEnum; import com.ylx.shopingfundsdetail.mapper.ShoppingFundsDetailMapper; import com.ylx.shopingfundsdetail.service.ShoppingFundsDetailService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; @Slf4j // 添加日志注解 @Service public class GiftCardOrderServiceImpl extends ServiceImpl implements IGiftCardOrderService { @Resource private TJsService jsService; @Resource private TWxUserService wxUserService; @Resource private ShoppingFundsDetailService shoppingFundsDetailService; @Resource private ShoppingFundsDetailMapper shoppingFundsDetailMapper; private static final int DETAIL_TYPE_PURCHASE = 0; private static final int DETAIL_TYPE_EXPENSE = 1; @Override @Transactional(rollbackFor = Exception.class) public GiftCardOrder buildOrder(GiftCard card, Integer quantity, String merchantId, WxLoginUser wxLoginUser) { // 1. 参数校验 if (ObjectUtil.isNull(card)) { throw new ServiceException("购物卡信息不能为空"); } if (ObjectUtil.isNull(quantity) || quantity <= 0) { throw new ServiceException("购买数量必须大于0"); } // 2. 创建订单对象 GiftCardOrder order = new GiftCardOrder(); // 4. 生成唯一订单号(使用更安全的方式) String orderNo = generateUniqueOrderNo(); order.setOrderNo(orderNo); // 5. 设置购物卡信息 setGiftCardInfo(order, card); // 6. 设置用户信息 setUserInfo(order, wxLoginUser); // 7. 设置商户信息 setMerchantInfo(order, merchantId); // 8. 计算金额 calculateAmount(order, card, quantity); order.setPurchaseQuantity(quantity); // 9. 设置订单状态和时间 order.setStatus(GiftCardOrderStatusEnum.WAIT_PAY.getCode()); // 待支付 order.setCreateTime(DateUtils.getNowDate()); order.setUpdateTime(order.getCreateTime()); int rowsAffected = this.baseMapper.insert(order); if (rowsAffected <= 0) { log.warn("购物卡订单创建失败,购物卡ID: {},下单人ID: {}", card.getId(), wxLoginUser.getId()); return null; } 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()); } @Override @Transactional(rollbackFor = Exception.class) public void processGiftCardPayment(WxPayOrderNotifyV3Result.DecryptNotifyResult result, TWxUser wxUser,GiftCardOrder cardOrder) { // 更新订单状态 this.lambdaUpdate() .set(GiftCardOrder::getStatus, GiftCardOrderStatusEnum.PAID.getCode()) .eq(GiftCardOrder::getId, cardOrder.getId()) .update(); // 计算充值金额 Integer totalCent = result.getAmount().getTotal(); BigDecimal payAmount = new BigDecimal(totalCent).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_HALF_UP); // 更新用户余额 BigDecimal oldBalance = wxUser.getdBalance(); BigDecimal newBalance = oldBalance.add(payAmount); this.wxUserService.lambdaUpdate() .set(TWxUser::getdBalance, newBalance) .eq(TWxUser::getId, wxUser.getId()) .update(); // 记录购物金明细 ShoppingFundsDetailAddDto dto = new ShoppingFundsDetailAddDto(); dto.setUserId(wxUser.getId()); dto.setAmount(payAmount); dto.setOrderNo(result.getOutTradeNo()); dto.setExpenseType(ShoppingFundsExpenseTypeEnum.RECHARGE.getCode()); dto.setBalance(newBalance); dto.setGiftCardId(cardOrder.getGiftCardId()); shoppingFundsDetailService.addShoppingFundsDetail(dto); } @Override public Page getAdminGiftCardOrderPage(Page page, GiftCardOrderQueryDTO dto) { GiftCardOrderQueryDTO query = dto == null ? new GiftCardOrderQueryDTO() : dto; normalizeOrderTimeRange(query); return baseMapper.selectAdminGiftCardOrderPage(page, query); } @Override public List getAdminGiftCardOrderExportList(GiftCardOrderQueryDTO dto) { GiftCardOrderQueryDTO query = dto == null ? new GiftCardOrderQueryDTO() : dto; normalizeOrderTimeRange(query); return baseMapper.selectAdminGiftCardOrderExportList(query); } @Override public UserShoppingFundsDetailVO getPcUserShoppingFundsDetail(Page page, UserShoppingFundsDetailQueryDTO dto) { validateShoppingFundsDetailQuery(dto); normalizeTimeRange(dto); TWxUser user = wxUserService.getById(dto.getUserId()); if (ObjectUtil.isNull(user)) { throw new IllegalArgumentException("用户不存在"); } UserShoppingFundsSummaryVO summary; Page detailPage; // 支出 if (DETAIL_TYPE_EXPENSE == dto.getDetailType()) { summary = shoppingFundsDetailMapper.selectPcExpenseShoppingFundsSummary(dto); detailPage = shoppingFundsDetailMapper.selectPcExpenseShoppingFundsDetail(page, dto); } else { // 购买 summary = baseMapper.selectPcPurchaseShoppingFundsSummary(dto); detailPage = baseMapper.selectPcPurchaseShoppingFundsDetail(page, dto); } UserShoppingFundsDetailVO vo = new UserShoppingFundsDetailVO(); vo.setShoppingFundsBalance(defaultAmount(user.getdBalance())); vo.setTotalAmount(defaultAmount(summary == null ? null : summary.getTotalAmount())); vo.setTotalCount(summary == null || summary.getTotalCount() == null ? 0L : summary.getTotalCount()); vo.setPage(detailPage); return vo; } /** * 校验购物金明细查询参数 * @param dto */ private void validateShoppingFundsDetailQuery(UserShoppingFundsDetailQueryDTO dto) { if (dto.getDetailType() == null) { dto.setDetailType(DETAIL_TYPE_PURCHASE); } if (dto.getDetailType() != DETAIL_TYPE_PURCHASE && dto.getDetailType() != DETAIL_TYPE_EXPENSE) { throw new IllegalArgumentException("明细类型不正确"); } } /** * 格式化时间范围 * @param dto */ private void normalizeTimeRange(UserShoppingFundsDetailQueryDTO dto) { if (StringUtils.isNotBlank(dto.getStartTime()) && dto.getStartTime().trim().length() == 10) { dto.setStartTime(dto.getStartTime().trim() + " 00:00:00"); } if (StringUtils.isNotBlank(dto.getEndTime()) && dto.getEndTime().trim().length() == 10) { dto.setEndTime(dto.getEndTime().trim() + " 23:59:59"); } } /** * 格式化购物卡订单查询时间范围 * @param dto */ private void normalizeOrderTimeRange(GiftCardOrderQueryDTO dto) { if (StringUtils.isNotBlank(dto.getStartTime()) && dto.getStartTime().trim().length() == 10) { dto.setStartTime(dto.getStartTime().trim() + " 00:00:00"); } if (StringUtils.isNotBlank(dto.getEndTime()) && dto.getEndTime().trim().length() == 10) { dto.setEndTime(dto.getEndTime().trim() + " 23:59:59"); } } private BigDecimal defaultAmount(BigDecimal amount) { return amount == null ? BigDecimal.ZERO : amount; } /** * 生成唯一订单号 */ private String generateUniqueOrderNo() { // 使用时间戳 + 随机数 + 更多信息避免冲突 long timestamp = System.currentTimeMillis(); String randomNum = RandomUtil.randomNumbers(6); // 可以加入用户ID后几位、线程ID等进一步降低冲突概率 String suffix = String.valueOf(timestamp % 1000000).substring(0, 3); // 取时间戳后3位 return "GC" + timestamp + randomNum + suffix; } /** * 设置购物卡信息 */ private void setGiftCardInfo(GiftCardOrder order, GiftCard card) { order.setGiftCardId(card.getId()); order.setGiftCardName(card.getName()); order.setGiftCardAmount(card.getAmount()); order.setCommissionRate(card.getCommissionRate()); } /** * 设置用户信息 */ private void setUserInfo(GiftCardOrder order, WxLoginUser wxLoginUser) { order.setUserId(wxLoginUser.getId()); order.setUserName(wxLoginUser.getCNickName()); order.setUserPhone(wxLoginUser.getCPhone()); } /** * 设置商户信息 */ private void setMerchantInfo(GiftCardOrder order, String merchantId) { if (StrUtil.isEmpty(merchantId)) { log.warn("商户ID为空,跳过商户信息查询"); return; } TJs merchant = this.jsService.getById(merchantId); if (ObjectUtil.isNotNull(merchant)) { order.setMerchantId(merchantId); order.setMerchantName(merchant.getcName()); order.setMerchantNickName(merchant.getcNickName()); // 注意:如果 TJs 表有收款账号字段,可以在这里设置 // order.setMerchantAccount(merchant.getAccount()); } } /** * 计算金额 */ private void calculateAmount(GiftCardOrder order, GiftCard card, Integer quantity) { BigDecimal payAmount = card.getAmount() .multiply(new BigDecimal(quantity)) .setScale(2, RoundingMode.HALF_UP); // 保留两位小数 order.setPayAmount(payAmount); BigDecimal commissionAmount = payAmount .multiply(card.getCommissionRate()) .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP); order.setCommissionAmount(commissionAmount); } }