|
@ -1,9 +1,11 @@ |
|
|
package com.gxwebsoft.payment.strategy; |
|
|
package com.gxwebsoft.payment.strategy; |
|
|
|
|
|
|
|
|
import com.gxwebsoft.common.core.utils.CommonUtil; |
|
|
import com.gxwebsoft.common.core.utils.CommonUtil; |
|
|
|
|
|
import com.gxwebsoft.common.system.entity.Payment; |
|
|
import com.gxwebsoft.payment.constants.PaymentConstants; |
|
|
import com.gxwebsoft.payment.constants.PaymentConstants; |
|
|
import com.gxwebsoft.payment.dto.PaymentRequest; |
|
|
import com.gxwebsoft.payment.dto.PaymentRequest; |
|
|
import com.gxwebsoft.payment.dto.PaymentResponse; |
|
|
import com.gxwebsoft.payment.dto.PaymentResponse; |
|
|
|
|
|
import com.gxwebsoft.payment.enums.PaymentStatus; |
|
|
import com.gxwebsoft.payment.enums.PaymentType; |
|
|
import com.gxwebsoft.payment.enums.PaymentType; |
|
|
import com.gxwebsoft.payment.exception.PaymentException; |
|
|
import com.gxwebsoft.payment.exception.PaymentException; |
|
|
import com.gxwebsoft.payment.service.WxPayConfigService; |
|
|
import com.gxwebsoft.payment.service.WxPayConfigService; |
|
@ -13,6 +15,8 @@ import com.wechat.pay.java.service.payments.nativepay.NativePayService; |
|
|
import com.wechat.pay.java.service.payments.nativepay.model.Amount; |
|
|
import com.wechat.pay.java.service.payments.nativepay.model.Amount; |
|
|
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest; |
|
|
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest; |
|
|
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse; |
|
|
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse; |
|
|
|
|
|
import com.wechat.pay.java.service.payments.nativepay.model.QueryOrderByOutTradeNoRequest; |
|
|
|
|
|
import com.wechat.pay.java.service.payments.model.Transaction; |
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
import org.springframework.stereotype.Component; |
|
|
import org.springframework.stereotype.Component; |
|
|
import org.springframework.util.StringUtils; |
|
|
import org.springframework.util.StringUtils; |
|
@ -96,11 +100,14 @@ public class WechatNativeStrategy implements PaymentStrategy { |
|
|
// 生成订单号
|
|
|
// 生成订单号
|
|
|
String orderNo = generateOrderNo(request); |
|
|
String orderNo = generateOrderNo(request); |
|
|
|
|
|
|
|
|
|
|
|
// 获取Native支付的Payment配置(包含appId等信息)
|
|
|
|
|
|
Payment paymentConfig = wxPayConfigService.getPaymentConfigForStrategy(request.getTenantId()); |
|
|
|
|
|
|
|
|
// 获取微信支付配置
|
|
|
// 获取微信支付配置
|
|
|
Config wxPayConfig = wxPayConfigService.getWxPayConfig(request.getTenantId()); |
|
|
Config wxPayConfig = wxPayConfigService.getWxPayConfig(request.getTenantId()); |
|
|
|
|
|
|
|
|
// 构建预支付请求
|
|
|
// 构建预支付请求
|
|
|
PrepayRequest prepayRequest = buildPrepayRequest(request, orderNo); |
|
|
|
|
|
|
|
|
PrepayRequest prepayRequest = buildPrepayRequest(request, orderNo, paymentConfig); |
|
|
|
|
|
|
|
|
// 调用微信支付API
|
|
|
// 调用微信支付API
|
|
|
PrepayResponse prepayResponse = callWechatPayApi(prepayRequest, wxPayConfig); |
|
|
PrepayResponse prepayResponse = callWechatPayApi(prepayRequest, wxPayConfig); |
|
@ -131,8 +138,34 @@ public class WechatNativeStrategy implements PaymentStrategy { |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public PaymentResponse queryPayment(String orderNo, Integer tenantId) throws PaymentException { |
|
|
public PaymentResponse queryPayment(String orderNo, Integer tenantId) throws PaymentException { |
|
|
// TODO: 实现微信支付查询逻辑
|
|
|
|
|
|
throw PaymentException.unsupportedPayment("暂不支持微信支付查询", PaymentType.WECHAT_NATIVE); |
|
|
|
|
|
|
|
|
log.info("开始查询微信Native支付状态, 订单号: {}, 租户ID: {}", orderNo, tenantId); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
// 参数验证
|
|
|
|
|
|
if (!StringUtils.hasText(orderNo)) { |
|
|
|
|
|
throw PaymentException.paramError("订单号不能为空"); |
|
|
|
|
|
} |
|
|
|
|
|
if (tenantId == null) { |
|
|
|
|
|
throw PaymentException.paramError("租户ID不能为空"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 获取支付配置(包含商户号等信息)
|
|
|
|
|
|
Payment paymentConfig = wxPayConfigService.getPaymentConfigForStrategy(tenantId); |
|
|
|
|
|
|
|
|
|
|
|
// 获取微信支付配置
|
|
|
|
|
|
Config wxPayConfig = wxPayConfigService.getWxPayConfig(tenantId); |
|
|
|
|
|
|
|
|
|
|
|
// 调用微信支付查询API
|
|
|
|
|
|
return queryWechatPaymentStatus(orderNo, tenantId, paymentConfig, wxPayConfig); |
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
if (e instanceof PaymentException) { |
|
|
|
|
|
throw e; |
|
|
|
|
|
} |
|
|
|
|
|
log.error("查询微信Native支付状态失败, 订单号: {}, 租户ID: {}, 错误: {}", |
|
|
|
|
|
orderNo, tenantId, e.getMessage(), e); |
|
|
|
|
|
throw PaymentException.systemError("查询微信支付状态失败: " + e.getMessage(), e); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
@ -200,12 +233,18 @@ public class WechatNativeStrategy implements PaymentStrategy { |
|
|
return CommonUtil.createOrderNo(); |
|
|
return CommonUtil.createOrderNo(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 构建微信预支付请求 |
|
|
* 构建微信预支付请求 |
|
|
*/ |
|
|
*/ |
|
|
private PrepayRequest buildPrepayRequest(PaymentRequest request, String orderNo) { |
|
|
|
|
|
|
|
|
private PrepayRequest buildPrepayRequest(PaymentRequest request, String orderNo, Payment paymentConfig) { |
|
|
PrepayRequest prepayRequest = new PrepayRequest(); |
|
|
PrepayRequest prepayRequest = new PrepayRequest(); |
|
|
|
|
|
|
|
|
|
|
|
// 设置应用ID和商户号(关键修复)
|
|
|
|
|
|
prepayRequest.setAppid(paymentConfig.getAppId()); |
|
|
|
|
|
prepayRequest.setMchid(paymentConfig.getMchId()); |
|
|
|
|
|
|
|
|
// 设置金额
|
|
|
// 设置金额
|
|
|
Amount amount = new Amount(); |
|
|
Amount amount = new Amount(); |
|
|
amount.setTotal(request.getAmountInCents()); |
|
|
amount.setTotal(request.getAmountInCents()); |
|
@ -216,17 +255,109 @@ public class WechatNativeStrategy implements PaymentStrategy { |
|
|
prepayRequest.setOutTradeNo(orderNo); |
|
|
prepayRequest.setOutTradeNo(orderNo); |
|
|
prepayRequest.setDescription(request.getEffectiveDescription()); |
|
|
prepayRequest.setDescription(request.getEffectiveDescription()); |
|
|
|
|
|
|
|
|
// 设置回调URL
|
|
|
|
|
|
|
|
|
// 设置回调URL(必填字段)
|
|
|
|
|
|
String notifyUrl = null; |
|
|
if (StringUtils.hasText(request.getNotifyUrl())) { |
|
|
if (StringUtils.hasText(request.getNotifyUrl())) { |
|
|
prepayRequest.setNotifyUrl(request.getNotifyUrl()); |
|
|
|
|
|
|
|
|
// 优先使用请求中的回调URL
|
|
|
|
|
|
notifyUrl = request.getNotifyUrl(); |
|
|
|
|
|
} else if (StringUtils.hasText(paymentConfig.getNotifyUrl())) { |
|
|
|
|
|
// 使用配置中的回调URL
|
|
|
|
|
|
notifyUrl = paymentConfig.getNotifyUrl(); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 如果都没有,抛出异常
|
|
|
|
|
|
throw new RuntimeException("回调通知地址不能为空,请在支付请求中设置notifyUrl或在支付配置中设置notifyUrl"); |
|
|
} |
|
|
} |
|
|
|
|
|
prepayRequest.setNotifyUrl(notifyUrl); |
|
|
|
|
|
|
|
|
log.debug("构建微信预支付请求完成, 订单号: {}, 金额: {}分", |
|
|
|
|
|
orderNo, request.getAmountInCents()); |
|
|
|
|
|
|
|
|
log.debug("构建微信预支付请求完成, 订单号: {}, 金额: {}分, AppID: {}, 商户号: {}, 回调URL: {}", |
|
|
|
|
|
orderNo, request.getAmountInCents(), paymentConfig.getAppId(), paymentConfig.getMchId(), notifyUrl); |
|
|
|
|
|
|
|
|
return prepayRequest; |
|
|
return prepayRequest; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 查询微信支付状态 |
|
|
|
|
|
*/ |
|
|
|
|
|
private PaymentResponse queryWechatPaymentStatus(String orderNo, Integer tenantId, Payment paymentConfig, Config wxPayConfig) throws PaymentException { |
|
|
|
|
|
try { |
|
|
|
|
|
// 构建查询请求
|
|
|
|
|
|
QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest(); |
|
|
|
|
|
queryRequest.setOutTradeNo(orderNo); |
|
|
|
|
|
queryRequest.setMchid(paymentConfig.getMchId()); |
|
|
|
|
|
|
|
|
|
|
|
// 构建服务
|
|
|
|
|
|
NativePayService service = new NativePayService.Builder().config(wxPayConfig).build(); |
|
|
|
|
|
|
|
|
|
|
|
// 调用查询接口
|
|
|
|
|
|
Transaction transaction = service.queryOrderByOutTradeNo(queryRequest); |
|
|
|
|
|
|
|
|
|
|
|
if (transaction == null) { |
|
|
|
|
|
throw PaymentException.systemError("微信支付查询返回空结果", null); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 转换支付状态
|
|
|
|
|
|
PaymentStatus paymentStatus = convertWechatPaymentStatus(transaction.getTradeState()); |
|
|
|
|
|
|
|
|
|
|
|
// 构建响应
|
|
|
|
|
|
PaymentResponse response = new PaymentResponse(); |
|
|
|
|
|
response.setSuccess(true); |
|
|
|
|
|
response.setOrderNo(orderNo); |
|
|
|
|
|
response.setPaymentStatus(paymentStatus); |
|
|
|
|
|
response.setTenantId(tenantId); |
|
|
|
|
|
response.setPaymentType(PaymentType.WECHAT_NATIVE); |
|
|
|
|
|
|
|
|
|
|
|
if (transaction.getAmount() != null) { |
|
|
|
|
|
// 微信返回的金额是分,需要转换为元
|
|
|
|
|
|
BigDecimal amount = new BigDecimal(transaction.getAmount().getTotal()).divide(new BigDecimal("100")); |
|
|
|
|
|
response.setAmount(amount); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (transaction.getTransactionId() != null) { |
|
|
|
|
|
response.setTransactionId(transaction.getTransactionId()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log.info("微信Native支付状态查询成功, 订单号: {}, 状态: {}, 微信交易号: {}", |
|
|
|
|
|
orderNo, paymentStatus, transaction.getTransactionId()); |
|
|
|
|
|
|
|
|
|
|
|
return response; |
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
if (e instanceof PaymentException) { |
|
|
|
|
|
throw e; |
|
|
|
|
|
} |
|
|
|
|
|
log.error("查询微信支付状态失败, 订单号: {}, 错误: {}", orderNo, e.getMessage(), e); |
|
|
|
|
|
throw PaymentException.networkError("查询微信支付状态失败: " + e.getMessage(), PaymentType.WECHAT_NATIVE, e); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 转换微信支付状态 |
|
|
|
|
|
*/ |
|
|
|
|
|
private PaymentStatus convertWechatPaymentStatus(Transaction.TradeStateEnum tradeState) { |
|
|
|
|
|
if (tradeState == null) { |
|
|
|
|
|
return PaymentStatus.PENDING; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
switch (tradeState) { |
|
|
|
|
|
case SUCCESS: |
|
|
|
|
|
return PaymentStatus.SUCCESS; |
|
|
|
|
|
case REFUND: |
|
|
|
|
|
return PaymentStatus.REFUNDED; |
|
|
|
|
|
case NOTPAY: |
|
|
|
|
|
return PaymentStatus.PENDING; |
|
|
|
|
|
case CLOSED: |
|
|
|
|
|
return PaymentStatus.CANCELLED; |
|
|
|
|
|
case REVOKED: |
|
|
|
|
|
return PaymentStatus.CANCELLED; |
|
|
|
|
|
case USERPAYING: |
|
|
|
|
|
return PaymentStatus.PROCESSING; |
|
|
|
|
|
case PAYERROR: |
|
|
|
|
|
return PaymentStatus.FAILED; |
|
|
|
|
|
default: |
|
|
|
|
|
return PaymentStatus.PENDING; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 调用微信支付API |
|
|
* 调用微信支付API |
|
|
*/ |
|
|
*/ |
|
|