yys 1 неделя назад
Родитель
Сommit
f92a4a7b7a

+ 156 - 66
fs-service/src/main/java/com/fs/app/service/impl/AppPayServiceImpl.java

@@ -1,60 +1,44 @@
 package com.fs.app.service.impl;
 
-import cn.hutool.json.JSONUtil;
-import com.alibaba.fastjson.JSON;
-import com.alipay.api.AlipayApiException;
-import com.alipay.api.AlipayClient;
-import com.alipay.api.DefaultAlipayClient;
-import com.alipay.api.diagnosis.DiagnosisUtils;
-import com.alipay.api.domain.AlipayTradeAppPayModel;
 import com.alipay.api.internal.util.AlipaySignature;
-import com.alipay.api.request.AlipayTradeAppPayRequest;
-import com.alipay.api.response.AlipayTradeAppPayResponse;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.app.service.AppPayService;
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.CustomException;
-import com.fs.common.utils.ServletUtils;
-import com.fs.common.utils.ip.IpUtils;
-import com.fs.core.config.WxPayProperties;
-import com.fs.core.utils.OrderCodeUtils;
+import com.fs.common.utils.DateUtils;
+import com.fs.core.utils.AppPayPlaySourceUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.course.service.IFsUserCourseOrderService;
 import com.fs.course.service.IFsUserVipOrderService;
-import com.fs.his.domain.*;
-import com.fs.his.dto.PayConfigDTO;
-import com.fs.his.enums.FsPackageOrderStatusEnum;
-import com.fs.his.mapper.FsPackageOrderMapper;
+import com.fs.his.domain.FsPayConfig;
+import com.fs.his.domain.FsStorePayment;
+import com.fs.his.domain.MerchantAppConfig;
 import com.fs.his.mapper.FsStorePaymentMapper;
-import com.fs.his.mapper.FsUserWxMapper;
-import com.fs.his.param.FsPackageOrderDoPayParam;
-import com.fs.his.service.*;
-import com.fs.huifuPay.service.HuiFuService;
+import com.fs.his.service.IFsInquiryOrderService;
+import com.fs.his.service.IFsPackageOrderService;
+import com.fs.his.service.IFsStoreOrderService;
+import com.fs.his.service.IMerchantAppConfigService;
 import com.fs.live.service.ILiveOrderService;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
-import com.fs.system.service.ISysConfigService;
-import com.fs.tzBankPay.TzBankService.TzBankService;
-import com.fs.tzBankPay.doman.PayType;
-import com.fs.ybPay.domain.OrderResult;
-import com.fs.ybPay.dto.OrderQueryDTO;
-import com.fs.ybPay.service.IPayService;
 import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
-import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
+import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
+import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
 import com.google.gson.Gson;
+import com.hc.openapi.tool.fastjson.JSON;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
 import java.math.BigDecimal;
-import java.util.Date;
+import java.math.RoundingMode;
 import java.util.Map;
 
 @Slf4j
@@ -76,6 +60,12 @@ public class AppPayServiceImpl implements AppPayService {
     private IFsUserVipOrderService vipOrderService;
     @Autowired
     private ILiveOrderService liveOrderService;
+    @Autowired
+    private IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
+    @Autowired
+    private IMerchantAppConfigService merchantAppConfigService;
+    @Autowired
+    private FsStorePaymentMapper fsStorePaymentMapper;
 
     /**
      * 支付宝回调
@@ -86,7 +76,7 @@ public class AppPayServiceImpl implements AppPayService {
         SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
         FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
         try {
-            boolean flag = AlipaySignature.rsaCheckV1(params, fsPayConfig.getAliPublicKey(), "UTF-8","RSA2");
+            boolean flag = AlipaySignature.rsaCheckV1(params, fsPayConfig.getAliPublicKey(), "UTF-8", "RSA2");
             if (!flag) {
                 log.info("支付宝回调验签失败:{}", params);
             }
@@ -100,67 +90,168 @@ public class AppPayServiceImpl implements AppPayService {
             String tradeNo = params.get("trade_no");
             switch (arr[0]) {
                 case "inquiry":
-                    inquiryOrderService.payConfirm("", arr[1],"","",1,tradeNo,"");
+                    inquiryOrderService.payConfirm("", arr[1], tradeNo, "", 1, tradeNo, null);
                     break;
                 case "store":
-                    storeOrderService.payConfirm("", arr[1],"","",1,tradeNo,"");
+                    storeOrderService.payConfirm("", arr[1], tradeNo, "", 1, tradeNo, null);
                     break;
                 case "package":
-                    packageOrderService.payConfirm("", arr[1],"","",1,tradeNo,"");
+                    packageOrderService.payConfirm("", arr[1], tradeNo, "", 1, tradeNo, null);
                     break;
                 case "appvip":
-                    vipOrderService.payConfirm("", arr[1],"","",1,tradeNo,"");
+                    vipOrderService.payConfirm("", arr[1], tradeNo, "", 1, tradeNo, null);
                     break;
                 case "course":
-                    courseOrderService.payConfirm("", arr[1],"","",1,tradeNo,"");
+                    courseOrderService.payConfirm("", arr[1], tradeNo, "", 1, tradeNo, null);
                     break;
                 case "applive":
                     liveOrderService.payConfirm(1, null, arr[1], tradeNo, tradeNo, null);
                     break;
             }
-
-
         } catch (Exception e) {
-            log.info("支付宝回调异常:{}", e);
+            log.error("支付宝回调异常", e);
             throw new RuntimeException(e);
         }
-
         return "success";
     }
 
     @Override
     public String wxNotify(WxPayOrderNotifyResult result) {
         log.info("微信回调参数: {}", result);
-        if (!"SUCCESS".equals(result.getReturnCode())){
+        if (!"SUCCESS".equals(result.getReturnCode())) {
             return WxPayNotifyResponse.success("微信回调失败");
         }
-
-        if (!"SUCCESS".equals(result.getResultCode())){
+        if (!"SUCCESS".equals(result.getResultCode())) {
             return WxPayNotifyResponse.success("交易失败");
         }
 
         String[] tradeNoArr = result.getOutTradeNo().split("-");
-        switch (tradeNoArr[0]) {
-            case "inquiry":
-                inquiryOrderService.payConfirm("", tradeNoArr[1],"","",1,result.getTransactionId(),"");
-                break;
-            case "store":
-                storeOrderService.payConfirm("", tradeNoArr[1],"","",1,result.getTransactionId(),"");
-                break;
-            case "package":
-                packageOrderService.payConfirm("", tradeNoArr[1],"","",1,result.getTransactionId(),"");
-                break;
-            case "appvip":
-                vipOrderService.payConfirm("", tradeNoArr[1],"","",1,result.getTransactionId(),"");
-                break;
-            case "course":
-                courseOrderService.payConfirm("", tradeNoArr[1],"","",1,result.getTransactionId(),"");
-                break;
-            case "applive":
-                liveOrderService.payConfirm(1, null, tradeNoArr[1], result.getTransactionId(), result.getTransactionId(), null);
-                break;
+        String bizType = tradeNoArr[0];
+        String payCode = tradeNoArr.length > 1 ? tradeNoArr[1] : null;
+        String tradeNo = result.getTransactionId();
+        try {
+            switch (bizType) {
+                case "inquiry":
+                    inquiryOrderService.payConfirm("", payCode, tradeNo, "", 1, tradeNo, null);
+                    break;
+                case "store":
+                    storeOrderService.payConfirm("", payCode, tradeNo, "", 1, tradeNo, null);
+                    break;
+                case "package":
+                    packageOrderService.payConfirm("", payCode, tradeNo, "", 1, tradeNo, null);
+                    break;
+                case "appvip":
+                    vipOrderService.payConfirm("", payCode, tradeNo, "", 1, tradeNo, null);
+                    break;
+                case "course":
+                    courseOrderService.payConfirm("", payCode, tradeNo, "", 1, tradeNo, null);
+                    break;
+                case "applive":
+                    liveOrderService.payConfirm(1, null, payCode, tradeNo, tradeNo, null);
+                    break;
+                default:
+                    log.warn("未知的APP微信回调业务类型: {}", bizType);
+                    break;
+            }
+            return WxPayNotifyResponse.success("OK");
+        } catch (Exception e) {
+            // 微信已扣款,但本地确认/生单失败:自动退款,避免客户丢钱
+            log.error("APP微信支付确认失败,准备自动退款 outTradeNo={}, transactionId={}, err={}",
+                    result.getOutTradeNo(), tradeNo, e.getMessage(), e);
+            try {
+                autoRefundAfterConfirmFail(result, payCode, e.getMessage());
+                return WxPayNotifyResponse.success("CONFIRM_FAIL_REFUNDED");
+            } catch (Exception refundEx) {
+                log.error("APP微信自动退款失败,请人工处理 outTradeNo={}, transactionId={}",
+                        result.getOutTradeNo(), tradeNo, refundEx);
+                // 退款失败时返回fail,让微信重试回调(或人工补退)
+                return WxPayNotifyResponse.fail("CONFIRM_FAIL_REFUND_FAIL");
+            }
         }
-        return WxPayNotifyResponse.success("OK");
+    }
+
+    /**
+     * 支付成功但业务确认失败时自动原路退款。
+     */
+    private void autoRefundAfterConfirmFail(WxPayOrderNotifyResult notifyResult, String payCode, String reason) throws WxPayException {
+        if (notifyResult == null || StringUtils.isBlank(notifyResult.getOutTradeNo())) {
+            throw new CustomException("自动退款失败:回调参数缺失");
+        }
+        if (StringUtils.isNotBlank(payCode)) {
+            FsStorePayment payment = fsStorePaymentMapper.selectFsStorePaymentByPaymentCode(payCode);
+            if (payment != null && payment.getStatus() != null && payment.getStatus() == -1) {
+                log.info("支付单已退款,跳过重复退款 payCode={}", payCode);
+                return;
+            }
+        }
+
+        WxPayService payService = buildAppWxPayService(notifyResult.getAppid());
+        WxPayRefundRequest refundRequest = new WxPayRefundRequest();
+        refundRequest.setTransactionId(notifyResult.getTransactionId());
+        refundRequest.setOutTradeNo(notifyResult.getOutTradeNo());
+        // 固定退款单号,保证微信重试回调时退款幂等
+        refundRequest.setOutRefundNo("refund-" + notifyResult.getOutTradeNo());
+        Integer totalFee = notifyResult.getTotalFee();
+        if (totalFee == null || totalFee <= 0) {
+            throw new CustomException("自动退款失败:金额异常");
+        }
+        refundRequest.setTotalFee(totalFee);
+        refundRequest.setRefundFee(totalFee);
+        refundRequest.setRefundDesc(StringUtils.left("支付确认失败自动退款:" + StringUtils.defaultString(reason), 80));
+
+        log.info("发起APP微信自动退款 outTradeNo={}, transactionId={}, totalFee={}",
+                notifyResult.getOutTradeNo(), notifyResult.getTransactionId(), totalFee);
+        WxPayRefundResult refundResult = payService.refund(refundRequest);
+        log.info("APP微信自动退款结果: {}", refundResult);
+
+        if (StringUtils.isNotBlank(payCode)) {
+            FsStorePayment payment = fsStorePaymentMapper.selectFsStorePaymentByPaymentCode(payCode);
+            if (payment != null) {
+                FsStorePayment paymentMap = new FsStorePayment();
+                paymentMap.setPaymentId(payment.getPaymentId());
+                paymentMap.setStatus(-1);
+                paymentMap.setTradeNo(notifyResult.getTransactionId());
+                paymentMap.setRefundTime(DateUtils.getNowDate());
+                paymentMap.setRefundMoney(fenToYuan(totalFee));
+                paymentMap.setRemark(StringUtils.left("支付确认失败自动退款:" + StringUtils.defaultString(reason), 200));
+                fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+            }
+        }
+    }
+
+    private WxPayService buildAppWxPayService(String wxAppId) {
+        String realWxAppId = AppPayPlaySourceUtils.toWxAppId(wxAppId);
+        String playSourceAppId = AppPayPlaySourceUtils.toPlaySourceAppId(realWxAppId);
+        FsCoursePlaySourceConfig playSourceConfig =
+                fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(playSourceAppId);
+        if (playSourceConfig == null) {
+            throw new CustomException("自动退款失败:未找到播放源配置 " + playSourceAppId);
+        }
+        MerchantAppConfig merchantAppConfig =
+                merchantAppConfigService.selectMerchantAppConfigById(playSourceConfig.getMerchantConfigId());
+        if (merchantAppConfig == null || StringUtils.isBlank(merchantAppConfig.getDataJson())) {
+            throw new CustomException("自动退款失败:未找到商户配置 " + playSourceAppId);
+        }
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+        if (StringUtils.isBlank(fsPayConfig.getWxAppMchId()) || StringUtils.isBlank(fsPayConfig.getWxAppMchKey())) {
+            throw new CustomException("自动退款失败:APP微信商户号/密钥未配置");
+        }
+        if (StringUtils.isBlank(fsPayConfig.getWxAppKeyPath())) {
+            throw new CustomException("自动退款失败:未配置APP微信退款证书路径(wxAppKeyPath)");
+        }
+
+        WxPayConfig payConfig = new WxPayConfig();
+        payConfig.setAppId(realWxAppId);
+        payConfig.setMchId(fsPayConfig.getWxAppMchId());
+        payConfig.setMchKey(fsPayConfig.getWxAppMchKey());
+        payConfig.setKeyPath(fsPayConfig.getWxAppKeyPath());
+        WxPayServiceImpl payService = new WxPayServiceImpl();
+        payService.setConfig(payConfig);
+        return payService;
+    }
+
+    private BigDecimal fenToYuan(Integer fen) {
+        return BigDecimal.valueOf(fen).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
     }
 
     @Override
@@ -171,5 +262,4 @@ public class AppPayServiceImpl implements AppPayService {
         }
         return R.ok(merchantAppConfig.getMerchantType());
     }
-
 }

+ 90 - 0
fs-service/src/main/java/com/fs/core/utils/AppPayPlaySourceUtils.java

@@ -0,0 +1,90 @@
+package com.fs.core.utils;
+
+import com.fs.common.utils.StringUtils;
+
+/**
+ * APP端支付播放源 appId 解析工具。
+ * <p>
+ * 重要:前缀 "app" 是系统自定义的播放源配置键,<strong>不是</strong>微信真实 appId 的一部分。
+ * 例如:微信 appId = wx66d3e2000b39fbca,播放源配置键 = appwx66d3e2000b39fbca。
+ * <ul>
+ *   <li>微信原生 APP 支付:用 app + 开放平台appId 查播放源,商户类型 appPay</li>
+ *   <li>支付宝(汇付):用汇付绑定的小程序 appId(不加 app 前缀),商户类型 hf</li>
+ *   <li>小程序内支付:直接使用小程序 appId</li>
+ * </ul>
+ */
+public final class AppPayPlaySourceUtils {
+
+    /** 播放源配置键自定义前缀,不要传给微信支付API */
+    public static final String PLAY_SOURCE_PREFIX = "app";
+
+    private AppPayPlaySourceUtils() {
+    }
+
+    /**
+     * 专用于 appPayment 接口:按支付方式选择播放源配置键。
+     */
+    public static String resolveForAppPayment(String appId, String payType) {
+        if (StringUtils.isBlank(appId)) {
+            return appId;
+        }
+        // 微信原生:播放源键 = app + 真实微信appId
+        if ("wx".equals(payType)) {
+            return toPlaySourceAppId(appId);
+        }
+        // 支付宝走汇付:使用客户端传入的汇付小程序appId
+        return appId;
+    }
+
+    /**
+     * 兼容小程序 + APP 的 payment 接口:
+     * 仅当 APP端 + 微信支付 时使用带 app 前缀的播放源配置键。
+     */
+    public static String resolveForMixedPayment(String appId, String payType, String sourceType) {
+        if (StringUtils.isBlank(appId)) {
+            return appId;
+        }
+        if ("APP".equalsIgnoreCase(sourceType) && "wx".equals(payType)) {
+            return toPlaySourceAppId(appId);
+        }
+        return appId;
+    }
+
+    /**
+     * 转为播放源配置键:wx66... -> appwx66... ;appwx66... -> appwx66...
+     */
+    public static String toPlaySourceAppId(String appIdOrKey) {
+        if (StringUtils.isBlank(appIdOrKey)) {
+            return appIdOrKey;
+        }
+        if (isPlaySourceKey(appIdOrKey)) {
+            return appIdOrKey;
+        }
+        return PLAY_SOURCE_PREFIX + appIdOrKey;
+    }
+
+    /**
+     * 转为微信/开放平台真实 appId(用于微信下单、回调验签):
+     * appwx66... -> wx66... ;wx66... -> wx66...
+     */
+    public static String toWxAppId(String appIdOrKey) {
+        if (StringUtils.isBlank(appIdOrKey)) {
+            return appIdOrKey;
+        }
+        if (isPlaySourceKey(appIdOrKey)) {
+            return appIdOrKey.substring(PLAY_SOURCE_PREFIX.length());
+        }
+        return appIdOrKey;
+    }
+
+    /**
+     * 是否为播放源配置键:app + wx...
+     */
+    public static boolean isPlaySourceKey(String appIdOrKey) {
+        if (StringUtils.isBlank(appIdOrKey) || !appIdOrKey.startsWith(PLAY_SOURCE_PREFIX)) {
+            return false;
+        }
+        String maybeWxAppId = appIdOrKey.substring(PLAY_SOURCE_PREFIX.length());
+        return maybeWxAppId.startsWith("wx");
+    }
+}

+ 12 - 5
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseOrderServiceImpl.java

@@ -21,6 +21,7 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.ip.IpUtils;
 import com.fs.core.config.WxPayProperties;
+import com.fs.core.utils.AppPayPlaySourceUtils;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.domain.*;
 import com.fs.course.mapper.*;
@@ -409,9 +410,17 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
             return R.ok().put("isPay",1);
         }
 
-        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        // 微信原生 → app+开放平台appId;支付宝汇付 → 汇付小程序appId(不加前缀)
+        String configAppId = AppPayPlaySourceUtils.resolveForAppPayment(param.getAppId(), param.getPayType());
+        String appId = "wx".equals(param.getPayType())
+                ? AppPayPlaySourceUtils.toWxAppId(param.getAppId())
+                : param.getAppId();
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(configAppId);
         if (fsCoursePlaySourceConfig == null) {
-            throw new CustomException("未找到appId对应的配置: " + param.getAppId());
+            throw new CustomException("未找到appId对应的配置: " + configAppId);
         }
         Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
         if (merchantConfigId == null || merchantConfigId <= 0) {
@@ -421,7 +430,6 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
         MerchantAppConfig merchantAppConfig = merchantAppConfigService.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
         FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
         String openId = null;
-        String appId = param.getAppId();
         if (request.getHeader("sourcetype") != null && "APP".equals(request.getHeader("sourcetype"))) {
             FsUser fsUser = fsUserService.selectFsUserByUserId(param.getUserId().longValue());
             openId = fsUser.getAppOpenId();
@@ -473,7 +481,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
         storePayment.setUserId(user.getUserId());
         storePayment.setBusinessId(order.getOrderId().toString());
         storePayment.setMerchantId(merchantAppConfig.getId());
-        storePayment.setAppId(param.getAppId());
+        storePayment.setAppId(appId);
         if (storePaymentService.insertFsStorePayment(storePayment) > 0) {
             if (!"hf".equals(merchantAppConfig.getMerchantType()) && !"appPay".equals(merchantAppConfig.getMerchantType())) {
                 return R.error("支付暂不可用!");
@@ -486,7 +494,6 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                 o.setAppId(appId);
                 o.setReqSeqId("course-"+storePayment.getPayCode());
                 o.setTransAmt(storePayment.getPayMoney().toString());
-                o.setAppId(param.getAppId());
                 o.setGoodsDesc("课程订单支付");
                 HuifuCreateOrderResult result = huiFuService.createOrder(o);
                 FsStorePayment mt=new FsStorePayment();

+ 12 - 5
fs-service/src/main/java/com/fs/course/service/impl/FsUserVipOrderServiceImpl.java

@@ -27,6 +27,7 @@ import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.spring.SpringUtils;
 import com.fs.common.utils.ip.IpUtils;
 import com.fs.core.config.WxPayProperties;
+import com.fs.core.utils.AppPayPlaySourceUtils;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsUserCourseOrder;
@@ -263,9 +264,17 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
             return R.ok().put("isPay",1);
         }
 
-        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        // 微信原生 → app+开放平台appId;支付宝汇付 → 汇付小程序appId(不加前缀)
+        String configAppId = AppPayPlaySourceUtils.resolveForAppPayment(param.getAppId(), param.getPayType());
+        String appId = "wx".equals(param.getPayType())
+                ? AppPayPlaySourceUtils.toWxAppId(param.getAppId())
+                : param.getAppId();
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(configAppId);
         if (fsCoursePlaySourceConfig == null) {
-            throw new CustomException("未找到appId对应的配置: " + param.getAppId());
+            throw new CustomException("未找到appId对应的配置: " + configAppId);
         }
         Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
         if (merchantConfigId == null || merchantConfigId <= 0) {
@@ -275,7 +284,6 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
         MerchantAppConfig merchantAppConfig = merchantAppConfigService.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
         FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
         String openId = null;
-        String appId = param.getAppId();
         if (request.getHeader("sourcetype") != null && "APP".equals(request.getHeader("sourcetype"))) {
             FsUser fsUser = fsUserService.selectFsUserByUserId(param.getUserId().longValue());
             openId = fsUser.getAppOpenId();
@@ -327,7 +335,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
         storePayment.setUserId(user.getUserId());
         storePayment.setBusinessId(order.getOrderId().toString());
         storePayment.setMerchantId(merchantAppConfig.getId());
-        storePayment.setAppId(param.getAppId());
+        storePayment.setAppId(appId);
         if (storePaymentService.insertFsStorePayment(storePayment) > 0) {
             if (!"hf".equals(merchantAppConfig.getMerchantType()) && !"appPay".equals(merchantAppConfig.getMerchantType())) {
                 return R.error("支付暂不可用!");
@@ -340,7 +348,6 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                 o.setAppId(appId);
                 o.setReqSeqId("appvip-"+storePayment.getPayCode());
                 o.setTransAmt(storePayment.getPayMoney().toString());
-                o.setAppId(param.getAppId());
                 o.setGoodsDesc("会员开通订单支付");
                 HuifuCreateOrderResult result = huiFuService.createOrder(o);
                 FsStorePayment mt=new FsStorePayment();

+ 24 - 11
fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java

@@ -38,6 +38,7 @@ import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.config.WxPayProperties;
+import com.fs.core.utils.AppPayPlaySourceUtils;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
@@ -827,13 +828,20 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         //写入订单
         Map<String,Object> packageJson = (Map)JSON.parse(order.getPackageJson());
         Integer packageSubType = (Integer)packageJson.get("packageSubType");
-        if (packageSubType!=3){
-            inquiryOrderService.createOrderByPackageOrder(order);
-        }
-        if (packageSubType!=1){
-            logger.info("创建订单2");
-            storeOrderService.createOrderByPackageOrder(order);
-            logger.info("创建订单");
+        try {
+            if (packageSubType!=3){
+                inquiryOrderService.createOrderByPackageOrder(order);
+            }
+            if (packageSubType!=1){
+                logger.info("创建订单2");
+                storeOrderService.createOrderByPackageOrder(order);
+                logger.info("创建订单");
+            }
+        } catch (Exception e) {
+            // 后续生单失败会导致整单事务回滚,支付状态也会回滚;必须把原因打出来
+            logger.error("套餐包支付确认后创建关联订单失败, orderId={}, orderSn={}, packageSubType={}",
+                    order.getOrderId(), order.getOrderSn(), packageSubType, e);
+            throw e instanceof RuntimeException ? (RuntimeException) e : new CustomException("创建关联订单失败:" + e.getMessage(), e);
         }
         FsUser fsUser = fsUserService.selectFsUserByUserId(order.getUserId());
         if (fsUser.getIsBuy()==null||fsUser.getIsBuy()==0){
@@ -999,20 +1007,25 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         if (StringUtils.isBlank(param.getAppId())) {
             throw new IllegalArgumentException("appId不能为空");
         }
-        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        // 小程序:原appId;APP微信原生:app+开放平台appId;APP支付宝汇付:汇付小程序appId
+        String configAppId = AppPayPlaySourceUtils.resolveForMixedPayment(
+                param.getAppId(), param.getPayType(), request.getHeader("sourcetype"));
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(configAppId);
         if (fsCoursePlaySourceConfig == null) {
-            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+            throw new CustomException("未找到appId对应的配置: " + configAppId);
         }
         Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
         if (merchantConfigId == null || merchantConfigId <= 0) {
-            throw new CustomException("小程序没有配置商户信息");
+            throw new CustomException("没有配置商户信息");
         }
         MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
         FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
 
         //金牛多小程序支付
         String openId = null;
-        String appId = param.getAppId();
+        String appId = "APP".equalsIgnoreCase(request.getHeader("sourcetype")) && "wx".equals(param.getPayType())
+                ? AppPayPlaySourceUtils.toWxAppId(param.getAppId())
+                : param.getAppId();
         if (request.getHeader("sourcetype") != null && "APP".equals(request.getHeader("sourcetype"))) {
             FsUser fsUser = fsUserService.selectFsUserByUserId(param.getUserId().longValue());
             openId = fsUser.getAppOpenId();

+ 12 - 4
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -862,7 +862,13 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             Long doctorID = iFsDoctorService.selectFsDoctorDoctorByPackage();
             packageOrder.setDoctorId(doctorID);
         }
+        if (packageOrder.getDoctorId() == null) {
+            throw new CustomException("系统未配置可用开方医生(需:执业医生、已审核启用、协议开方医生、已上传签名),支付将自动退款,请联系管理员配置后重新下单");
+        }
         FsPackage fsPackage = fsPackageMapper.selectFsPackageByPackageId(packageOrder.getPackageId());
+        if (fsPackage == null) {
+            throw new CustomException("套餐包不存在, packageId=" + packageOrder.getPackageId());
+        }
         JSONArray objects = JSONUtil.parseArray(fsPackage.getProductJson());
         List<FsPackagePruductDTO> products = JSONUtil.toList(objects, FsPackagePruductDTO.class);
 
@@ -876,7 +882,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         if(CloudHostUtils.hasCloudHostName("九州在线")){
             log.info("跳过生成处方单,处方单id:{}", prescribeId);
         } else {
+            log.info("开始生成处方单, packageOrderSn={}, doctorId={}", packageOrder.getOrderSn(), packageOrder.getDoctorId());
             prescribeId = fsPrescribeService.insertFsPrescribeByPackageOrder(packageOrder);
+            log.info("生成处方单完成, prescribeId={}", prescribeId);
         }
 
         FsStoreOrder order = new FsStoreOrder();
@@ -949,7 +957,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         PackageConfigDTO configDTO = JSONUtil.toBean(json, PackageConfigDTO.class);
         FsPackageOrder fsPackageOrder = new FsPackageOrder();
         //赠品处理
-        if (configDTO.getGiftStoreId() != null && configDTO.getGiftStoreId() == packageOrder.getStoreId() && packageOrder.getCompanyId() != null && packageOrder.getCompanyId() > 0 && packageOrder.getPayType().equals(1) && packageOrder.getPayMoney().compareTo(configDTO.getGiftPrice()) >= 0) {
+        if (configDTO.getGiftStoreId() != null && configDTO.getGiftStoreId() == packageOrder.getStoreId() && packageOrder.getCompanyId() != null && packageOrder.getCompanyId() > 0 && Integer.valueOf(1).equals(packageOrder.getPayType()) && packageOrder.getPayMoney() != null && packageOrder.getPayMoney().compareTo(configDTO.getGiftPrice()) >= 0) {
             if (configDTO.getGift() != null && configDTO.getGift().size() > 0) {
                 for (StoreOrderProductDTO product : configDTO.getGift()) {
                     totalNum = totalNum + product.getCount();
@@ -981,7 +989,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             }
         }
         //物流代收赠品
-        if (configDTO.getGiftStoreId() != null && configDTO.getGiftStoreId() == packageOrder.getStoreId() && packageOrder.getCompanyId() != null && packageOrder.getCompanyId() > 0 && packageOrder.getPayType().equals(2) && packageOrder.getPayPrice().compareTo(configDTO.getGiftPrice()) >= 0) {
+        if (configDTO.getGiftStoreId() != null && configDTO.getGiftStoreId() == packageOrder.getStoreId() && packageOrder.getCompanyId() != null && packageOrder.getCompanyId() > 0 && Integer.valueOf(2).equals(packageOrder.getPayType()) && packageOrder.getPayPrice() != null && packageOrder.getPayPrice().compareTo(configDTO.getGiftPrice()) >= 0) {
             if (configDTO.getDeliveryGift() != null && configDTO.getDeliveryGift().size() > 0) {
                 for (StoreOrderProductDTO product : configDTO.getDeliveryGift()) {
                     totalNum = totalNum + product.getCount();
@@ -4476,7 +4484,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         PackageConfigDTO configDTO = JSONUtil.toBean(json, PackageConfigDTO.class);
         FsPackageOrder fsPackageOrder = new FsPackageOrder();
         //赠品处理
-        if (configDTO.getGiftStoreId() != null && configDTO.getGiftStoreId() == packageOrder.getStoreId() && packageOrder.getCompanyId() != null && packageOrder.getCompanyId() > 0 && packageOrder.getPayType().equals(1) && packageOrder.getPayMoney().compareTo(configDTO.getGiftPrice()) >= 0) {
+        if (configDTO.getGiftStoreId() != null && configDTO.getGiftStoreId() == packageOrder.getStoreId() && packageOrder.getCompanyId() != null && packageOrder.getCompanyId() > 0 && Integer.valueOf(1).equals(packageOrder.getPayType()) && packageOrder.getPayMoney() != null && packageOrder.getPayMoney().compareTo(configDTO.getGiftPrice()) >= 0) {
             if (configDTO.getGift() != null && !configDTO.getGift().isEmpty()) {
                 for (StoreOrderProductDTO product : configDTO.getGift()) {
                     totalNum = totalNum + product.getCount();
@@ -4508,7 +4516,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             }
         }
         //物流代收赠品
-        if (configDTO.getGiftStoreId() != null && configDTO.getGiftStoreId() == packageOrder.getStoreId() && packageOrder.getCompanyId() != null && packageOrder.getCompanyId() > 0 && packageOrder.getPayType().equals(2) && packageOrder.getPayPrice().compareTo(configDTO.getGiftPrice()) >= 0) {
+        if (configDTO.getGiftStoreId() != null && configDTO.getGiftStoreId() == packageOrder.getStoreId() && packageOrder.getCompanyId() != null && packageOrder.getCompanyId() > 0 && Integer.valueOf(2).equals(packageOrder.getPayType()) && packageOrder.getPayPrice() != null && packageOrder.getPayPrice().compareTo(configDTO.getGiftPrice()) >= 0) {
             if (configDTO.getDeliveryGift() != null && !configDTO.getDeliveryGift().isEmpty()) {
                 for (StoreOrderProductDTO product : configDTO.getDeliveryGift()) {
                     totalNum = totalNum + product.getCount();

+ 9 - 7
fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java

@@ -56,6 +56,7 @@ import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.config.WxMaConfiguration;
+import com.fs.core.utils.AppPayPlaySourceUtils;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsUserCompanyUser;
@@ -3852,13 +3853,11 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         if (StringUtils.isBlank(param.getAppId())) {
             throw new IllegalArgumentException("appId不能为空");
         }
-        String appIds = param.getAppId();
-        if (param.getPayType().equals("wx")){
-            appIds = "app" + param.getAppId();
-        }
-        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(appIds);
+        // 微信原生 → app+开放平台appId;支付宝汇付 → 汇付小程序appId(不加前缀)
+        String configAppId = AppPayPlaySourceUtils.resolveForAppPayment(param.getAppId(), param.getPayType());
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(configAppId);
         if (fsCoursePlaySourceConfig == null) {
-            throw new CustomException("未找到appId对应的配置: " + param.getAppId());
+            throw new CustomException("未找到appId对应的配置: " + configAppId);
         }
         Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
         if (merchantConfigId == null || merchantConfigId <= 0) {
@@ -3868,7 +3867,10 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
 
         String openId = null;
-        String appId = param.getAppId();
+        // 微信下单用开放平台appId;汇付用传入的小程序appId
+        String appId = "wx".equals(param.getPayType())
+                ? AppPayPlaySourceUtils.toWxAppId(param.getAppId())
+                : param.getAppId();
         if (request.getHeader("sourcetype") != null && "APP".equals(request.getHeader("sourcetype"))) {
             FsUser fsUser = fsUserService.selectFsUserByUserId(Long.valueOf(order.getUserId()));
             if (fsUser != null) {

+ 74 - 12
fs-user-app/src/main/java/com/fs/app/controller/AppPayController.java

@@ -3,15 +3,20 @@ package com.fs.app.controller;
 
 import com.fs.app.service.AppPayService;
 import com.fs.common.core.domain.R;
+import com.fs.common.exception.CustomException;
+import com.fs.common.utils.StringUtils;
+import com.fs.core.utils.AppPayPlaySourceUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.his.domain.FsPayConfig;
-import com.fs.system.domain.SysConfig;
-import com.fs.system.mapper.SysConfigMapper;
+import com.fs.his.domain.MerchantAppConfig;
+import com.fs.his.service.IMerchantAppConfigService;
 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
-import com.google.gson.Gson;
+import com.hc.openapi.tool.fastjson.JSON;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
@@ -22,6 +27,8 @@ import javax.servlet.http.HttpServletRequest;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 @Slf4j
 @Api("app支付接口")
@@ -31,8 +38,11 @@ public class AppPayController extends AppBaseController {
 
     @Autowired
     private AppPayService appPayService;
+
+    @Autowired
+    private IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
     @Autowired
-    private SysConfigMapper sysConfigMapper;
+    private IMerchantAppConfigService merchantAppConfigService;
 
     @ApiOperation("支付宝回调")
     @PostMapping("/aliNotify")
@@ -46,7 +56,7 @@ public class AppPayController extends AppBaseController {
             for (int i = 0; i < values.length; i++) {
                 valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
             }
-            //乱码解决,这段代码在出现乱码时使用。
+            // 乱码解决:出现乱码时可开启下面这行
             //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
             params.put(name, valueStr);
         }
@@ -58,7 +68,8 @@ public class AppPayController extends AppBaseController {
     @ApiOperation("微信支付回调")
     @PostMapping("/wxNotify")
     public String wxNotify(@RequestBody String xmlData) throws WxPayException {
-        WxPayService payService = getWxPayService();
+        log.info("微信APP支付回调参数:{}", xmlData);
+        WxPayService payService = getWxPayService(xmlData);
         WxPayOrderNotifyResult result = payService.parseOrderNotifyResult(xmlData);
         return appPayService.wxNotify(result);
     }
@@ -66,21 +77,72 @@ public class AppPayController extends AppBaseController {
     @ApiOperation("获取支付配置")
     @GetMapping("/getPayConfig")
     public R getPayConfig(@RequestParam String appId){
-        return appPayService.getPayConfig("app"+ appId);
+        // 客户端传真实微信appId;播放源配置键使用自定义前缀 app
+        return appPayService.getPayConfig(AppPayPlaySourceUtils.toPlaySourceAppId(appId));
     }
 
+    /**
+     * 根据微信回调XML加载APP支付商户配置。
+     * <p>
+     * 回调XML中的 appid 是微信真实 appId(wx...);<br>
+     * 播放源库表配置键是自定义的 app + wxAppId(appwx...);<br>
+     * WxPayConfig.appId 必须使用真实 wxAppId,用于验签/switchover,不能带 app 前缀。
+     */
+    private WxPayService getWxPayService(String xmlData) {
+        // 1) 回调中的微信真实appId,如 wx66d3e2000b39fbca
+        String wxAppId = extractXmlAppId(xmlData);
+        if (StringUtils.isEmpty(wxAppId)) {
+            throw new CustomException("微信回调缺少appid");
+        }
+        wxAppId = AppPayPlaySourceUtils.toWxAppId(wxAppId);
+
+        // 2) 系统播放源配置键,如 appwx66d3e2000b39fbca
+        String playSourceAppId = AppPayPlaySourceUtils.toPlaySourceAppId(wxAppId);
+        log.info("微信APP支付回调解析 wxAppId={}, playSourceAppId={}", wxAppId, playSourceAppId);
+
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig =
+                fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(playSourceAppId);
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的配置: " + playSourceAppId);
+        }
+        MerchantAppConfig merchantAppConfig =
+                merchantAppConfigService.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        if (merchantAppConfig == null || StringUtils.isEmpty(merchantAppConfig.getDataJson())) {
+            throw new CustomException("未找到商户支付配置: " + playSourceAppId);
+        }
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+        if (StringUtils.isEmpty(fsPayConfig.getWxAppMchId()) || StringUtils.isEmpty(fsPayConfig.getWxAppMchKey())) {
+            throw new CustomException("APP微信支付商户配置不完整: " + playSourceAppId);
+        }
 
-    private WxPayService getWxPayService(){
-        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-        FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
+        // 3) 用真实微信appId + APP商户字段验签
         WxPayConfig payConfig = new WxPayConfig();
-        payConfig.setAppId(fsPayConfig.getWxAppAppId());
+        payConfig.setAppId(wxAppId);
         payConfig.setMchId(fsPayConfig.getWxAppMchId());
         payConfig.setMchKey(fsPayConfig.getWxAppMchKey());
+        payConfig.setSubAppId(StringUtils.trimToNull(null));
+        payConfig.setSubMchId(StringUtils.trimToNull(null));
         payConfig.setKeyPath(fsPayConfig.getWxAppKeyPath());
-        payConfig.setNotifyUrl(fsPayConfig.getWxAppNotifyUrl());
+        payConfig.setNotifyUrl(StringUtils.isNotEmpty(fsPayConfig.getWxAppNotifyUrl())
+                ? fsPayConfig.getWxAppNotifyUrl() : fsPayConfig.getNotifyUrlScrm());
         WxPayServiceImpl payService = new WxPayServiceImpl();
         payService.setConfig(payConfig);
         return payService;
     }
+
+    private String extractXmlAppId(String xmlData) {
+        if (StringUtils.isEmpty(xmlData)) {
+            return null;
+        }
+        // 优先取CDATA
+        Matcher cdata = Pattern.compile("<appid><!\\[CDATA\\[(.*?)\\]\\]></appid>", Pattern.CASE_INSENSITIVE)
+                .matcher(xmlData);
+        if (cdata.find()) {
+            return cdata.group(1);
+        }
+        // 兼容无CDATA的节点
+        Matcher plain = Pattern.compile("<appid>(.*?)</appid>", Pattern.CASE_INSENSITIVE)
+                .matcher(xmlData);
+        return plain.find() ? plain.group(1).trim() : null;
+    }
 }

+ 10 - 5
fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java

@@ -22,6 +22,7 @@ import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.ip.IpUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.core.config.WxPayProperties;
+import com.fs.core.utils.AppPayPlaySourceUtils;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.service.IFsCoursePlaySourceConfigService;
@@ -274,13 +275,16 @@ public class InquiryOrderController extends  AppBaseController {
         if (StringUtils.isBlank(param.getAppId())) {
             throw new IllegalArgumentException("appId不能为空");
         }
-        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        // 小程序:原appId;APP微信原生:app+开放平台appId;APP支付宝汇付:汇付小程序appId
+        String configAppId = AppPayPlaySourceUtils.resolveForMixedPayment(
+                param.getAppId(), param.getPayType(), request.getHeader("sourcetype"));
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(configAppId);
         if (fsCoursePlaySourceConfig == null) {
-            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+            throw new CustomException("未找到appId对应的配置: " + configAppId);
         }
         Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
         if (merchantConfigId == null || merchantConfigId <= 0) {
-            throw new CustomException("小程序没有配置商户信息");
+            throw new CustomException("没有配置商户信息");
         }
         MerchantAppConfig merchantAppConfig = merchantAppConfigService.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
         FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
@@ -305,7 +309,9 @@ public class InquiryOrderController extends  AppBaseController {
 //        }
 
         String openId = null;
-        String appId = param.getAppId();
+        String appId = "APP".equalsIgnoreCase(request.getHeader("sourcetype")) && "wx".equals(param.getPayType())
+                ? AppPayPlaySourceUtils.toWxAppId(param.getAppId())
+                : param.getAppId();
         if (request.getHeader("sourcetype") != null && "APP".equals(request.getHeader("sourcetype"))) {
             FsUser fsUser = fsUserService.selectFsUserByUserId(param.getUserId().longValue());
             openId = fsUser.getAppOpenId();
@@ -465,7 +471,6 @@ public class InquiryOrderController extends  AppBaseController {
                     o.setAppId(appId);
                     o.setReqSeqId("inquiry-"+storePayment.getPayCode());
                     o.setTransAmt(storePayment.getPayMoney().toString());
-                    o.setAppId(param.getAppId());
                     o.setGoodsDesc("问诊订单支付");
                     HuifuCreateOrderResult result = huiFuService.createOrder(o);
                     FsStorePayment mt=new FsStorePayment();

+ 1 - 0
fs-user-app/src/main/java/com/fs/app/exception/FSExceptionHandler.java

@@ -81,6 +81,7 @@ public class FSExceptionHandler {
 	}
 	@ExceptionHandler(CustomException.class)
 	public R handleException(CustomException e){
+		logger.error(e.getMessage(), e);
 		return R.error(e.getMessage());
 	}