feat(payment): 增加支付配置检查和最近支付查询功能- 新增支付配置检查接口,用于检查指定租户的支付配置是否完整
- 添加查询用户最近支付订单接口,当orderNo缺失时可查询用户最近创建的支付订单 - 优化订单号生成逻辑,使用雪花算法保证全局唯一 - 完善支付配置验证,确保商户号、序列号、API密钥等关键信息已配置 - 调整日志输出,增加关键信息的空值检查和异常处理
This commit is contained in:
@@ -112,6 +112,17 @@ public class PaymentController extends BaseController {
|
|||||||
|
|
||||||
log.info("查询支付状态: orderNo={}, paymentType={}, tenantId={}", orderNo, paymentType, tenantId);
|
log.info("查询支付状态: orderNo={}, paymentType={}, tenantId={}", orderNo, paymentType, tenantId);
|
||||||
|
|
||||||
|
// 参数验证
|
||||||
|
if (orderNo == null || orderNo.trim().isEmpty()) {
|
||||||
|
return fail("订单号不能为空");
|
||||||
|
}
|
||||||
|
if (paymentType == null) {
|
||||||
|
return fail("支付类型不能为空");
|
||||||
|
}
|
||||||
|
if (tenantId == null || tenantId <= 0) {
|
||||||
|
return fail("租户ID不能为空且必须为正数");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PaymentResponse response = paymentService.queryPayment(orderNo, paymentType, tenantId);
|
PaymentResponse response = paymentService.queryPayment(orderNo, paymentType, tenantId);
|
||||||
return this.<PaymentResponse>success("支付状态查询成功", response);
|
return this.<PaymentResponse>success("支付状态查询成功", response);
|
||||||
@@ -302,4 +313,48 @@ public class PaymentController extends BaseController {
|
|||||||
return fail("更新支付状态失败: " + e.getMessage());
|
return fail("更新支付状态失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "检查支付配置", description = "检查指定租户的支付配置是否完整")
|
||||||
|
@GetMapping("/config/check")
|
||||||
|
public ApiResult<?> checkPaymentConfig(
|
||||||
|
@Parameter(description = "租户ID", required = true)
|
||||||
|
@RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {
|
||||||
|
|
||||||
|
log.info("检查支付配置,租户ID: {}", tenantId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String, Object> configStatus = paymentService.checkPaymentConfig(tenantId);
|
||||||
|
return this.<Map<String, Object>>success("配置检查完成", configStatus);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("检查支付配置失败: {}", e.getMessage(), e);
|
||||||
|
return fail("检查支付配置失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "查询用户最近的支付订单", description = "当orderNo缺失时,查询用户最近创建的支付订单")
|
||||||
|
@GetMapping("/query-recent")
|
||||||
|
public ApiResult<?> queryRecentPayment(
|
||||||
|
@Parameter(description = "支付类型", required = true)
|
||||||
|
@RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,
|
||||||
|
|
||||||
|
@Parameter(description = "租户ID", required = true)
|
||||||
|
@RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {
|
||||||
|
|
||||||
|
log.info("查询用户最近支付订单: paymentType={}, tenantId={}", paymentType, tenantId);
|
||||||
|
|
||||||
|
final User loginUser = getLoginUser();
|
||||||
|
if(loginUser == null){
|
||||||
|
return fail("请先登录");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 这里需要实现查询用户最近订单的逻辑
|
||||||
|
// 可以通过用户ID和租户ID查询最近创建的订单
|
||||||
|
return fail("此功能需要实现查询用户最近订单的业务逻辑");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询用户最近支付订单失败: {}", e.getMessage(), e);
|
||||||
|
return fail("查询失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,4 +171,12 @@ public interface PaymentService {
|
|||||||
* @return 所有策略信息列表
|
* @return 所有策略信息列表
|
||||||
*/
|
*/
|
||||||
List<Map<String, Object>> getAllPaymentStrategyInfo();
|
List<Map<String, Object>> getAllPaymentStrategyInfo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查支付配置
|
||||||
|
*
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @return 配置检查结果
|
||||||
|
*/
|
||||||
|
Map<String, Object> checkPaymentConfig(Integer tenantId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,19 +126,26 @@ public class WxPayConfigService {
|
|||||||
|
|
||||||
// 缓存中没有,尝试从数据库查询
|
// 缓存中没有,尝试从数据库查询
|
||||||
try {
|
try {
|
||||||
final PaymentParam paymentParam = new PaymentParam();
|
final PaymentParam paymentParam = new PaymentParam();
|
||||||
paymentParam.setType(102);
|
paymentParam.setType(102);
|
||||||
paymentParam.setTenantId(tenantId);
|
paymentParam.setTenantId(tenantId);
|
||||||
payment = paymentService.getByType(paymentParam);
|
|
||||||
System.out.println("payment1 = " + payment);
|
log.debug("查询数据库支付配置,参数: type=102, tenantId={}", tenantId);
|
||||||
if (payment != null) {
|
payment = paymentService.getByType(paymentParam);
|
||||||
|
log.debug("数据库查询结果: {}", payment != null ? "找到配置" : "未找到配置");
|
||||||
|
|
||||||
|
if (payment != null) {
|
||||||
log.info("从数据库获取支付配置成功,租户ID: {},将缓存配置", tenantId);
|
log.info("从数据库获取支付配置成功,租户ID: {},将缓存配置", tenantId);
|
||||||
// 将查询到的配置缓存起来,缓存1小时
|
// 将查询到的配置缓存起来,缓存1天
|
||||||
redisUtil.set(cacheKey, payment, 1L,TimeUnit.DAYS);
|
redisUtil.set(cacheKey, payment, 1L, TimeUnit.DAYS);
|
||||||
return payment;
|
return payment;
|
||||||
|
} else {
|
||||||
|
log.warn("数据库中未找到支付配置,租户ID: {}, type: 102", tenantId);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("从数据库查询支付配置失败,租户ID: {},错误: {}", tenantId, e.getMessage());
|
log.error("从数据库查询支付配置失败,租户ID: {},错误: {}", tenantId, e.getMessage(), e);
|
||||||
|
// 抛出更详细的异常信息
|
||||||
|
throw PaymentException.systemError("查询支付配置失败,租户ID: " + tenantId + ",错误: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数据库也没有配置
|
// 数据库也没有配置
|
||||||
@@ -278,9 +285,8 @@ public class WxPayConfigService {
|
|||||||
* 创建正常配置
|
* 创建正常配置
|
||||||
*/
|
*/
|
||||||
private Config createNormalConfig(Payment payment, String certificatePath) throws PaymentException {
|
private Config createNormalConfig(Payment payment, String certificatePath) throws PaymentException {
|
||||||
if (payment.getMchId() == null || payment.getMerchantSerialNumber() == null || payment.getApiKey() == null) {
|
// 验证配置完整性
|
||||||
throw PaymentException.systemError("支付配置信息不完整:商户号、序列号或APIv3密钥为空", null);
|
validatePaymentConfig(payment);
|
||||||
}
|
|
||||||
|
|
||||||
log.info("使用数据库支付配置");
|
log.info("使用数据库支付配置");
|
||||||
log.debug("商户号: {}", payment.getMchId());
|
log.debug("商户号: {}", payment.getMchId());
|
||||||
@@ -293,6 +299,33 @@ public class WxPayConfigService {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证支付配置完整性
|
||||||
|
*/
|
||||||
|
private void validatePaymentConfig(Payment payment) throws PaymentException {
|
||||||
|
if (payment == null) {
|
||||||
|
throw PaymentException.systemError("支付配置为空", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) {
|
||||||
|
throw PaymentException.systemError("商户号(mchId)未配置", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) {
|
||||||
|
throw PaymentException.systemError("商户证书序列号(merchantSerialNumber)未配置", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) {
|
||||||
|
throw PaymentException.systemError("APIv3密钥(apiKey)未配置", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty()) {
|
||||||
|
throw PaymentException.systemError("证书文件名(apiclientKey)未配置", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("支付配置验证通过,租户ID: {}, 商户号: {}", payment.getTenantId(), payment.getMchId());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除指定租户的配置缓存
|
* 清除指定租户的配置缓存
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.gxwebsoft.payment.service.impl;
|
package com.gxwebsoft.payment.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import com.gxwebsoft.common.core.utils.CommonUtil;
|
||||||
import com.gxwebsoft.common.system.entity.User;
|
import com.gxwebsoft.common.system.entity.User;
|
||||||
import com.gxwebsoft.payment.constants.PaymentConstants;
|
import com.gxwebsoft.payment.constants.PaymentConstants;
|
||||||
import com.gxwebsoft.payment.dto.PaymentRequest;
|
import com.gxwebsoft.payment.dto.PaymentRequest;
|
||||||
@@ -8,6 +10,7 @@ import com.gxwebsoft.payment.dto.PaymentWithOrderRequest;
|
|||||||
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.PaymentService;
|
import com.gxwebsoft.payment.service.PaymentService;
|
||||||
|
import com.gxwebsoft.payment.service.WxPayConfigService;
|
||||||
import com.gxwebsoft.payment.strategy.PaymentStrategy;
|
import com.gxwebsoft.payment.strategy.PaymentStrategy;
|
||||||
import com.gxwebsoft.shop.dto.OrderCreateRequest;
|
import com.gxwebsoft.shop.dto.OrderCreateRequest;
|
||||||
import com.gxwebsoft.shop.service.OrderBusinessService;
|
import com.gxwebsoft.shop.service.OrderBusinessService;
|
||||||
@@ -50,6 +53,12 @@ public class PaymentServiceImpl implements PaymentService {
|
|||||||
@Resource
|
@Resource
|
||||||
private OrderBusinessService orderBusinessService;
|
private OrderBusinessService orderBusinessService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支付配置服务
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private WxPayConfigService wxPayConfigService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化策略映射
|
* 初始化策略映射
|
||||||
*/
|
*/
|
||||||
@@ -416,6 +425,34 @@ public class PaymentServiceImpl implements PaymentService {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> checkPaymentConfig(Integer tenantId) {
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("tenantId", tenantId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查微信支付配置
|
||||||
|
wxPayConfigService.getPaymentConfigForStrategy(tenantId);
|
||||||
|
result.put("wechatConfigExists", true);
|
||||||
|
result.put("wechatConfigError", null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.put("wechatConfigExists", false);
|
||||||
|
result.put("wechatConfigError", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查微信支付Config构建
|
||||||
|
wxPayConfigService.getWxPayConfig(tenantId);
|
||||||
|
result.put("wechatConfigValid", true);
|
||||||
|
result.put("wechatConfigValidError", null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.put("wechatConfigValid", false);
|
||||||
|
result.put("wechatConfigValidError", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取支付策略
|
* 获取支付策略
|
||||||
*/
|
*/
|
||||||
@@ -554,6 +591,11 @@ public class PaymentServiceImpl implements PaymentService {
|
|||||||
private OrderCreateRequest convertToOrderCreateRequest(PaymentWithOrderRequest request, User loginUser) {
|
private OrderCreateRequest convertToOrderCreateRequest(PaymentWithOrderRequest request, User loginUser) {
|
||||||
OrderCreateRequest orderRequest = new OrderCreateRequest();
|
OrderCreateRequest orderRequest = new OrderCreateRequest();
|
||||||
|
|
||||||
|
// 生成订单号(使用雪花算法保证全局唯一)
|
||||||
|
String orderNo = Long.toString(IdUtil.getSnowflakeNextId());
|
||||||
|
orderRequest.setOrderNo(orderNo);
|
||||||
|
log.info("为订单创建请求生成订单号(雪花算法): {}", orderNo);
|
||||||
|
|
||||||
// 设置基本信息
|
// 设置基本信息
|
||||||
orderRequest.setType(request.getOrderInfo().getType());
|
orderRequest.setType(request.getOrderInfo().getType());
|
||||||
orderRequest.setTitle(request.getSubject());
|
orderRequest.setTitle(request.getSubject());
|
||||||
@@ -614,8 +656,13 @@ public class PaymentServiceImpl implements PaymentService {
|
|||||||
|
|
||||||
// 设置额外信息
|
// 设置额外信息
|
||||||
response.setSuccess(true);
|
response.setSuccess(true);
|
||||||
|
// 确保orderNo被正确设置
|
||||||
|
response.setOrderNo(orderNo);
|
||||||
|
|
||||||
|
// 调试日志
|
||||||
|
log.info("构建支付响应成功, 订单号: {}, 二维码URL: {}, 响应中的orderNo: {}",
|
||||||
|
orderNo, wxOrderInfo.get("codeUrl"), response.getOrderNo());
|
||||||
|
|
||||||
log.debug("构建支付响应成功, 订单号: {}, 二维码URL: {}", orderNo, wxOrderInfo.get("codeUrl"));
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.gxwebsoft.payment.strategy;
|
package com.gxwebsoft.payment.strategy;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
import com.gxwebsoft.common.core.utils.CommonUtil;
|
import com.gxwebsoft.common.core.utils.CommonUtil;
|
||||||
import com.gxwebsoft.common.system.entity.Payment;
|
import com.gxwebsoft.common.system.entity.Payment;
|
||||||
import com.gxwebsoft.payment.constants.PaymentConstants;
|
import com.gxwebsoft.payment.constants.PaymentConstants;
|
||||||
@@ -99,6 +100,7 @@ public class WechatNativeStrategy implements PaymentStrategy {
|
|||||||
|
|
||||||
// 生成订单号
|
// 生成订单号
|
||||||
String orderNo = generateOrderNo(request);
|
String orderNo = generateOrderNo(request);
|
||||||
|
log.info("生成的订单号: {}", orderNo);
|
||||||
|
|
||||||
// 获取Native支付的Payment配置(包含appId等信息)
|
// 获取Native支付的Payment配置(包含appId等信息)
|
||||||
Payment paymentConfig = wxPayConfigService.getPaymentConfigForStrategy(request.getTenantId());
|
Payment paymentConfig = wxPayConfigService.getPaymentConfigForStrategy(request.getTenantId());
|
||||||
@@ -117,6 +119,13 @@ public class WechatNativeStrategy implements PaymentStrategy {
|
|||||||
orderNo, prepayResponse.getCodeUrl(), request.getAmount(), request.getTenantId());
|
orderNo, prepayResponse.getCodeUrl(), request.getAmount(), request.getTenantId());
|
||||||
response.setUserId(request.getUserId());
|
response.setUserId(request.getUserId());
|
||||||
|
|
||||||
|
// 确保orderNo被正确设置
|
||||||
|
response.setOrderNo(orderNo);
|
||||||
|
|
||||||
|
// 调试日志:检查响应对象的orderNo
|
||||||
|
log.info("构建的响应对象 - orderNo: {}, codeUrl: {}, success: {}",
|
||||||
|
response.getOrderNo(), response.getCodeUrl(), response.getSuccess());
|
||||||
|
|
||||||
log.info("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 金额: {}",
|
log.info("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 金额: {}",
|
||||||
PaymentConstants.LogMessage.PAYMENT_SUCCESS, getSupportedPaymentType(),
|
PaymentConstants.LogMessage.PAYMENT_SUCCESS, getSupportedPaymentType(),
|
||||||
request.getTenantId(), orderNo, request.getFormattedAmount());
|
request.getTenantId(), orderNo, request.getFormattedAmount());
|
||||||
@@ -224,13 +233,13 @@ public class WechatNativeStrategy implements PaymentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成订单号
|
* 生成订单号(使用雪花算法保证全局唯一)
|
||||||
*/
|
*/
|
||||||
private String generateOrderNo(PaymentRequest request) {
|
private String generateOrderNo(PaymentRequest request) {
|
||||||
if (StringUtils.hasText(request.getOrderNo())) {
|
if (StringUtils.hasText(request.getOrderNo())) {
|
||||||
return request.getOrderNo();
|
return request.getOrderNo();
|
||||||
}
|
}
|
||||||
return CommonUtil.createOrderNo();
|
return Long.toString(IdUtil.getSnowflakeNextId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -995,7 +995,7 @@ public class ShopOrderServiceImpl extends ServiceImpl<ShopOrderMapper, ShopOrder
|
|||||||
System.out.println("🔧 使用RSA自动证书配置");
|
System.out.println("🔧 使用RSA自动证书配置");
|
||||||
config = new RSAAutoCertificateConfig.Builder()
|
config = new RSAAutoCertificateConfig.Builder()
|
||||||
.merchantId(payment.getMchId())
|
.merchantId(payment.getMchId())
|
||||||
.privateKey(privateKey)
|
.privateKeyFromPath(privateKey)
|
||||||
.merchantSerialNumber(payment.getMerchantSerialNumber())
|
.merchantSerialNumber(payment.getMerchantSerialNumber())
|
||||||
.apiV3Key(payment.getApiKey())
|
.apiV3Key(payment.getApiKey())
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
Reference in New Issue
Block a user