|  | @@ -1,12 +1,9 @@
 | 
	
		
			
				|  |  |  package cn.newfeifan.mall.module.pay.service.order;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import cn.hutool.core.collection.CollUtil;
 | 
	
		
			
				|  |  | -import cn.hutool.core.date.DatePattern;
 | 
	
		
			
				|  |  | -import cn.hutool.core.date.DateUtil;
 | 
	
		
			
				|  |  |  import cn.hutool.core.util.ObjectUtil;
 | 
	
		
			
				|  |  |  import cn.hutool.core.util.StrUtil;
 | 
	
		
			
				|  |  |  import cn.hutool.extra.spring.SpringUtil;
 | 
	
		
			
				|  |  | -import cn.newfeifan.mall.framework.common.exception.ErrorCode;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.framework.common.pojo.PageResult;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.framework.common.util.date.LocalDateTimeUtils;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.framework.common.util.number.MoneyUtils;
 | 
	
	
		
			
				|  | @@ -36,13 +33,11 @@ import cn.newfeifan.mall.module.pay.service.channel.PayChannelService;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.module.pay.service.notify.PayNotifyService;
 | 
	
		
			
				|  |  |  import com.google.common.annotations.VisibleForTesting;
 | 
	
		
			
				|  |  |  import lombok.extern.slf4j.Slf4j;
 | 
	
		
			
				|  |  | -import org.springframework.data.redis.core.StringRedisTemplate;
 | 
	
		
			
				|  |  |  import org.springframework.stereotype.Service;
 | 
	
		
			
				|  |  |  import org.springframework.transaction.annotation.Transactional;
 | 
	
		
			
				|  |  |  import org.springframework.validation.annotation.Validated;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import javax.annotation.Resource;
 | 
	
		
			
				|  |  | -import java.time.Duration;
 | 
	
		
			
				|  |  |  import java.time.LocalDateTime;
 | 
	
		
			
				|  |  |  import java.util.Collection;
 | 
	
		
			
				|  |  |  import java.util.Collections;
 | 
	
	
		
			
				|  | @@ -63,13 +58,6 @@ import static cn.newfeifan.mall.module.pay.enums.ErrorCodeConstants.*;
 | 
	
		
			
				|  |  |  @Slf4j
 | 
	
		
			
				|  |  |  public class PayOrderServiceImpl implements PayOrderService {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    public static final String TRADE_NO = "trade_no:";
 | 
	
		
			
				|  |  | -    public static final String FUYOU_TRADE_ORDER_NO_PREFIX = "16103-";
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    @Resource
 | 
	
		
			
				|  |  | -    StringRedisTemplate stringRedisTemplate;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      @Resource
 | 
	
		
			
				|  |  |      private PayProperties payProperties;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -178,83 +166,60 @@ public class PayOrderServiceImpl implements PayOrderService {
 | 
	
		
			
				|  |  |                  .setRefundPrice(0);
 | 
	
		
			
				|  |  |          order.setParentPayOrderId(reqDTO.getParentPayOrderId());//设置父支付订单ID
 | 
	
		
			
				|  |  |          order.setExpireTime(order.getExpireTime());//把父支付订单的过期时间,设置到子订单
 | 
	
		
			
				|  |  | -        order.setPayOrderNo(generate(FUYOU_TRADE_ORDER_NO_PREFIX));
 | 
	
		
			
				|  |  |          orderMapper.insert(order);
 | 
	
		
			
				|  |  |          return order.getId();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    private String generate(String prefix) {
 | 
	
		
			
				|  |  | -        // 递增序号
 | 
	
		
			
				|  |  | -        String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
 | 
	
		
			
				|  |  | -        String key = TRADE_NO + noPrefix;
 | 
	
		
			
				|  |  | -        Long no = stringRedisTemplate.opsForValue().increment(key);
 | 
	
		
			
				|  |  | -        // 设置过期时间
 | 
	
		
			
				|  |  | -        stringRedisTemplate.expire(key, Duration.ofMinutes(1L));
 | 
	
		
			
				|  |  | -        return noPrefix + no;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      @Override // 注意,这里不能添加事务注解,避免调用支付渠道失败时,将 PayOrderExtensionDO 回滚了
 | 
	
		
			
				|  |  |      public PayOrderSubmitRespVO submitOrder(PayOrderSubmitReqVO reqVO, String userIp) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        String str = "";
 | 
	
		
			
				|  |  | +        log.warn("[submitOrder--------->unifiedOrderResp][订单id({})000000支付开始]", reqVO.getId());
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        try {
 | 
	
		
			
				|  |  | -//            int i = 0/0;
 | 
	
		
			
				|  |  | -            log.warn("[submitOrder--------->unifiedOrderResp][订单id({})000000支付开始]", reqVO.getId());
 | 
	
		
			
				|  |  | -            str = "支付开始";
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // 1.1 获得 PayOrderDO ,并校验其是否存在
 | 
	
		
			
				|  |  | -            PayOrderDO order = validateOrderCanSubmit(reqVO.getId());
 | 
	
		
			
				|  |  | -            // 1.32 校验支付渠道是否有效
 | 
	
		
			
				|  |  | -            PayChannelDO channel = validateChannelCanSubmit(order.getAppId(), reqVO.getChannelCode());
 | 
	
		
			
				|  |  | -            PayClient client = channelService.getPayClient(channel.getId());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            log.warn("[submitOrder--------->unifiedOrderResp][订单id({})1111111支付渠道校验通过]", order.getId());
 | 
	
		
			
				|  |  | -            str = "支付渠道校验通过";
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // 2. 插入 PayOrderExtensionDO
 | 
	
		
			
				|  |  | -            String no = noRedisDAO.generate(payProperties.getOrderNoPrefix());
 | 
	
		
			
				|  |  | -            PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp)
 | 
	
		
			
				|  |  | -                    .setOrderId(order.getId()).setNo(no)
 | 
	
		
			
				|  |  | -                    .setChannelId(channel.getId()).setChannelCode(channel.getCode())
 | 
	
		
			
				|  |  | -                    .setStatus(PayOrderStatusEnum.WAITING.getStatus());
 | 
	
		
			
				|  |  | -            orderExtensionMapper.insert(orderExtension);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            log.warn("[submitOrder--------->unifiedOrderResp][订单id({})2222222支付渠道校验通过]", order.getId());
 | 
	
		
			
				|  |  | -            str = "222支付渠道校验通过";
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // 3. 调用三方接口
 | 
	
		
			
				|  |  | -            PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderConvert.INSTANCE.convert2(reqVO, userIp)
 | 
	
		
			
				|  |  | -                    // 商户相关的字段
 | 
	
		
			
				|  |  | -                    .setOutTradeNo(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性!
 | 
	
		
			
				|  |  | -                    .setSubject(order.getSubject()).setBody(order.getBody())
 | 
	
		
			
				|  |  | -                    .setNotifyUrl(genChannelOrderNotifyUrl(channel))
 | 
	
		
			
				|  |  | -                    .setReturnUrl(reqVO.getReturnUrl())
 | 
	
		
			
				|  |  | -                    // 订单相关字段
 | 
	
		
			
				|  |  | -                    .setPrice(order.getPrice()).setExpireTime(order.getExpireTime());
 | 
	
		
			
				|  |  | -            PayOrderRespDTO unifiedOrderResp = client.unifiedOrder(unifiedOrderReqDTO);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            log.warn("[submitOrder--------->unifiedOrderResp][订单id({})333333支付完成,支付状态({})]", order.getId(), unifiedOrderResp.getStatus());
 | 
	
		
			
				|  |  | -            str = "调用三方接口";
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功
 | 
	
		
			
				|  |  | -            if (unifiedOrderResp != null) {
 | 
	
		
			
				|  |  | -                getSelf().notifyOrder(channel, unifiedOrderResp);
 | 
	
		
			
				|  |  | -                // 如有渠道错误码,则抛出业务异常,提示用户
 | 
	
		
			
				|  |  | -                if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
 | 
	
		
			
				|  |  | -                    throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
 | 
	
		
			
				|  |  | -                            unifiedOrderResp.getChannelErrorMsg());
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                // 此处需要读取最新的状态
 | 
	
		
			
				|  |  | -                order = orderMapper.selectById(order.getId());
 | 
	
		
			
				|  |  | +        // 1.1 获得 PayOrderDO ,并校验其是否存在
 | 
	
		
			
				|  |  | +        PayOrderDO order = validateOrderCanSubmit(reqVO.getId());
 | 
	
		
			
				|  |  | +        // 1.32 校验支付渠道是否有效
 | 
	
		
			
				|  |  | +        PayChannelDO channel = validateChannelCanSubmit(order.getAppId(), reqVO.getChannelCode());
 | 
	
		
			
				|  |  | +        PayClient client = channelService.getPayClient(channel.getId());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        log.warn("[submitOrder--------->unifiedOrderResp][订单id({})1111111支付渠道校验通过]", order.getId());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 2. 插入 PayOrderExtensionDO
 | 
	
		
			
				|  |  | +        String no = noRedisDAO.generate(payProperties.getOrderNoPrefix());
 | 
	
		
			
				|  |  | +        PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp)
 | 
	
		
			
				|  |  | +                .setOrderId(order.getId()).setNo(no)
 | 
	
		
			
				|  |  | +                .setChannelId(channel.getId()).setChannelCode(channel.getCode())
 | 
	
		
			
				|  |  | +                .setStatus(PayOrderStatusEnum.WAITING.getStatus());
 | 
	
		
			
				|  |  | +        orderExtensionMapper.insert(orderExtension);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        log.warn("[submitOrder--------->unifiedOrderResp][订单id({})2222222支付渠道校验通过]", order.getId());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 3. 调用三方接口
 | 
	
		
			
				|  |  | +        PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderConvert.INSTANCE.convert2(reqVO, userIp)
 | 
	
		
			
				|  |  | +                // 商户相关的字段
 | 
	
		
			
				|  |  | +                .setOutTradeNo(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性!
 | 
	
		
			
				|  |  | +                .setSubject(order.getSubject()).setBody(order.getBody())
 | 
	
		
			
				|  |  | +                .setNotifyUrl(genChannelOrderNotifyUrl(channel))
 | 
	
		
			
				|  |  | +                .setReturnUrl(reqVO.getReturnUrl())
 | 
	
		
			
				|  |  | +                // 订单相关字段
 | 
	
		
			
				|  |  | +                .setPrice(order.getPrice()).setExpireTime(order.getExpireTime());
 | 
	
		
			
				|  |  | +        PayOrderRespDTO unifiedOrderResp = client.unifiedOrder(unifiedOrderReqDTO);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        log.warn("[submitOrder--------->unifiedOrderResp][订单id({})333333支付完成,支付状态({})]", order.getId(), unifiedOrderResp.getStatus());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功
 | 
	
		
			
				|  |  | +        if (unifiedOrderResp != null) {
 | 
	
		
			
				|  |  | +            getSelf().notifyOrder(channel, unifiedOrderResp);
 | 
	
		
			
				|  |  | +            // 如有渠道错误码,则抛出业务异常,提示用户
 | 
	
		
			
				|  |  | +            if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
 | 
	
		
			
				|  |  | +                throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
 | 
	
		
			
				|  |  | +                        unifiedOrderResp.getChannelErrorMsg());
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -            log.warn("如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功:{}", unifiedOrderResp);
 | 
	
		
			
				|  |  | -            return PayOrderConvert.INSTANCE.convert(order, unifiedOrderResp);
 | 
	
		
			
				|  |  | -        } catch (Exception e) {
 | 
	
		
			
				|  |  | -            ErrorCode err = new ErrorCode(1,e.getMessage() + "===" + str);
 | 
	
		
			
				|  |  | -            throw exception(err);
 | 
	
		
			
				|  |  | +            // 此处需要读取最新的状态
 | 
	
		
			
				|  |  | +            order = orderMapper.selectById(order.getId());
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        log.warn("如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功:{}", unifiedOrderResp);
 | 
	
		
			
				|  |  | +        return PayOrderConvert.INSTANCE.convert(order, unifiedOrderResp);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      @Override
 | 
	
	
		
			
				|  | @@ -591,6 +556,11 @@ public class PayOrderServiceImpl implements PayOrderService {
 | 
	
		
			
				|  |  |          return count;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    @Override
 | 
	
		
			
				|  |  | +    public void updatePayOrder(PayOrderDO order) {
 | 
	
		
			
				|  |  | +        orderMapper.updateById(order);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /**
 | 
	
		
			
				|  |  |       * 同步单个支付单
 | 
	
		
			
				|  |  |       *
 |