Просмотр исходного кода

Merge branch 'dev/2024/0703/update-app-Y' of Harper/feifan-backend-zx-app into master

新增支付通道
Yangzw 8 месяцев назад
Родитель
Сommit
dd1899d1b4

+ 5 - 0
feifan-module-pay/feifan-module-pay-api/src/main/java/cn/newfeifan/mall/module/pay/enums/DictTypeConstants.java

@@ -21,4 +21,9 @@ public interface DictTypeConstants {
     // 富友支付的商户号
     String mchnt_cd = "0006420F7357129";
 
+    public static final String FUYOU_TRADE_ORDER_NO_PREFIX = "16103-";
+
+
+    public static final String TRADE_NO = "trade_no:";
+
 }

+ 12 - 3
feifan-module-pay/feifan-module-pay-biz/src/main/java/cn/newfeifan/mall/module/pay/fuiou/reqvo/SubmitOrderRequestVO.java

@@ -1,19 +1,28 @@
 package cn.newfeifan.mall.module.pay.fuiou.reqvo;
 
 import cn.newfeifan.mall.module.pay.fuiou.reqdata.WxPreCreateDataReq;
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
 /**
  * 提交订单请求
  */
 
 @Data
+@Schema(description = "管理后台 - 支付订单提交 Request VO")
 public class SubmitOrderRequestVO {
 
-    /*
-     * 支付订单编号
-     */
+    @Schema(description = "支付单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "支付单编号不能为空")
     private Long id;
 
+    @Schema(description = "支付渠道", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx_pub")
+    @NotEmpty(message = "支付渠道不能为空")
+    private String channelCode;
+
+    @Schema(description = "支付渠道的额外参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx_pub")
     private WxPreCreateDataReq req;
 }

+ 66 - 9
feifan-module-pay/feifan-module-pay-biz/src/main/java/cn/newfeifan/mall/module/pay/service/fuyouorder/FiYouPayOrderServiceImpl.java

@@ -1,10 +1,17 @@
 package cn.newfeifan.mall.module.pay.service.fuyouorder;
 
-import cn.newfeifan.mall.framework.common.exception.ErrorCode;
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.newfeifan.mall.framework.pay.core.client.PayClient;
+import cn.newfeifan.mall.module.pay.dal.dataobject.channel.PayChannelDO;
 import cn.newfeifan.mall.module.pay.dal.dataobject.order.PayOrderDO;
+import cn.newfeifan.mall.module.pay.dal.dataobject.order.PayOrderExtensionDO;
+import cn.newfeifan.mall.module.pay.dal.mysql.order.PayOrderExtensionMapper;
 import cn.newfeifan.mall.module.pay.fuiou.reqvo.SubmitOrderRequestVO;
 import cn.newfeifan.mall.module.pay.fuiou.respVO.FuYouPayOrderSubmitRespVO;
 import cn.newfeifan.mall.module.pay.fuiou.respVO.FuYouPaymentResponseVO;
+import cn.newfeifan.mall.module.pay.service.app.PayAppService;
+import cn.newfeifan.mall.module.pay.service.channel.PayChannelService;
 import cn.newfeifan.mall.module.pay.service.order.PayOrderService;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
@@ -15,13 +22,20 @@ import cn.newfeifan.mall.module.pay.fuiou.util.MD5;
 import com.alibaba.fastjson.JSON;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
+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 static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.newfeifan.mall.framework.common.util.servlet.ServletUtils.getClientIP;
 import static cn.newfeifan.mall.module.pay.enums.DictTypeConstants.*;
+import static cn.newfeifan.mall.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND;
 import static cn.newfeifan.mall.module.pay.enums.ErrorCodeConstants.SUBMIT_ORDER_ERROR;
 
 @Service
@@ -34,12 +48,38 @@ public class FiYouPayOrderServiceImpl implements FuYouPayOrderService {
 
     @Resource
     private PayOrderService payOrderService;
+    @Resource
+    StringRedisTemplate stringRedisTemplate;
+
+    @Resource
+    private PayOrderExtensionMapper orderExtensionMapper;
+
+    @Resource
+    private PayAppService appService;
+
+    @Resource
+    private PayChannelService channelService;
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public String submitOrder(SubmitOrderRequestVO requestVO) {
 
         // 1.1 获得 PayOrderDO ,并校验其是否存在
         PayOrderDO payOrder = payOrderService.validateOrderCanSubmit(requestVO.getId());
+        payOrder.setPayOrderNo(generate());
+        payOrderService.updatePayOrder(payOrder);
+
+        // 1.32 校验支付渠道是否有效
+        PayChannelDO channel = validateChannelCanSubmit(payOrder.getAppId(), requestVO.getChannelCode());
+
+        // 2. 插入 PayOrderExtensionDO
+        PayOrderExtensionDO orderExtension = PayOrderExtensionDO.builder()
+                .userIp(getClientIP())
+                .orderId(payOrder.getId())
+                .channelId(channel.getId())
+                .channelCode(channel.getCode())
+                .build();
+        orderExtensionMapper.insert(orderExtension);
 
         FuiouHttpPoster http = new FuiouHttpPoster();
         http.setCharset("utf-8");
@@ -49,18 +89,12 @@ public class FiYouPayOrderServiceImpl implements FuYouPayOrderService {
         requestVO.getReq().setRandom_str(DateUtils.getCurrentDate("yyyyMMddHHmmss")
                 + "568974");
         requestVO.getReq().setMchnt_cd(mchnt_cd);
-//        requestVO.getReq().setTrade_type("JSAPI");
-//      req.setOpenid("oDax96l0bZdXqRQ2uVfn_2LV-DxM");//微信支付此字段必填
-//		req.setSub_openid("221122121");//支付宝支付此字段必填
-        requestVO.getReq().setOrder_amt(String.valueOf(payOrder.getPrice() / 100));
+        requestVO.getReq().setOrder_amt(String.valueOf(payOrder.getPrice()));
         requestVO.getReq().setGoods_des(payOrder.getBody());
-//        requestVO.getReq().setOpenid("osMm86Ggu3iLCkdCO2j4Zan-fHOQ");
-//        requestVO.getReq().setSub_openid("osMm86Ggu3iLCkdCO2j4Zan-fHOQ");
-//        requestVO.getReq().setSub_appid("wxe133514440a8829d");
         requestVO.getReq().setSub_appid(appid);
         requestVO.getReq().setMchnt_order_no(payOrder.getPayOrderNo());//不能重复
         requestVO.getReq().setTxn_begin_ts(DateUtils.getCurrentDate("yyyyMMddHHmmss"));
-        requestVO.getReq().setNotify_url("https://zxpt.newfeifan.cn/fuYou/pay/order/notify");
+        requestVO.getReq().setNotify_url("https://letcgo.com/fuYou/pay/order/notify");
         requestVO.getReq().setVersion("1.0");
         StringBuilder sb = new StringBuilder();
         sb.append(requestVO.getReq().getMchnt_cd().trim()).append("|")
@@ -104,6 +138,29 @@ public class FiYouPayOrderServiceImpl implements FuYouPayOrderService {
         }
     }
 
+    private PayChannelDO validateChannelCanSubmit(Long appId, String channelCode) {
+        // 校验 App
+        appService.validPayApp(appId);
+        // 校验支付渠道是否有效
+        PayChannelDO channel = channelService.validPayChannel(appId, channelCode);
+        PayClient client = channelService.getPayClient(channel.getId());
+        if (client == null) {
+            log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
+            throw exception(CHANNEL_NOT_FOUND);
+        }
+        return channel;
+    }
+
+    private String generate() {
+        // 递增序号
+        String noPrefix = cn.newfeifan.mall.module.pay.enums.DictTypeConstants.FUYOU_TRADE_ORDER_NO_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
     public void afterSale(Long afterSaleId) {
 

+ 2 - 0
feifan-module-pay/feifan-module-pay-biz/src/main/java/cn/newfeifan/mall/module/pay/service/order/PayOrderService.java

@@ -171,4 +171,6 @@ public interface PayOrderService {
      */
     int expireOrder();
 
+    void updatePayOrder(PayOrderDO order);
+
 }

+ 48 - 78
feifan-module-pay/feifan-module-pay-biz/src/main/java/cn/newfeifan/mall/module/pay/service/order/PayOrderServiceImpl.java

@@ -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);
+    }
+
     /**
      * 同步单个支付单
      *