fix(openalipay): 修复支付宝角色ID配置及押金解冻功能

- 将支付宝控制器中用户角色ID硬编码替换为配置读取,默认角色ID为81,配置存在时使用配置值
- 修正用户角色保存时使用动态角色ID,支持多租户配置
- 修改数据源配置,切换本地MySQL连接地址以便开发调试
- 新增押金冻结订单修复与解冻工具类UnfreezeToolTest.java,支持数据库中auth_no为空的冻结订单修复
- 实现基于支付宝Java SDK的证书模式解冻接口调用,避免Python调用时根证书问题
- 设计并完善押金冻结订单解冻的运维手册,指导正确操作及错误处理
- 优化解冻流程,支持自动修复冻结订单状态并更新数据库状态为UNFREEZE
- 添加FixFreezeOrderTest.java辅助测试工具类,用于根据订单号或冻结订单号进行押金解冻测试和修复
This commit is contained in:
2026-05-11 13:52:52 +08:00
parent 948a8afec1
commit 93c2a57a86
7 changed files with 569 additions and 4 deletions

View File

@@ -85,8 +85,14 @@ public class OpenAlipayController extends BaseController {
// if (setting == null) {
// throw new BusinessException("请先配置注册设置");
// }
JSONObject jsonObject = JSONObject.parseObject(setting);
String roleId = jsonObject.getString("roleId");
int roleId = 81;
if (StrUtil.isNotBlank(setting)) {
JSONObject jsonObject = JSONObject.parseObject(setting);
Integer configRoleId = jsonObject == null ? null : jsonObject.getInteger("roleId");
if (configRoleId != null) {
roleId = configRoleId;
}
}
// 实例化客户端
DefaultAlipayClient alipayClient = alipayConfig.alipayClient(param.getTenantId());
try {
@@ -141,7 +147,7 @@ public class OpenAlipayController extends BaseController {
UserRole userRole = new UserRole();
userRole.setUserId(user.getUserId());
userRole.setTenantId(param.getTenantId());
userRole.setRoleId(Integer.valueOf(81));
userRole.setRoleId(roleId);
userRoleService.save(userRole);
// 添加第三方用户信息
UserOauth userOauth2 = new UserOauth();

View File

@@ -3,7 +3,7 @@
# 数据源配置
spring:
datasource:
url: jdbc:mysql://47.107.122.174:3318/yunxinwei?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
url: jdbc:mysql://127.0.0.1:3308/yunxinwei?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: yunxinwei
password: A56sK6aW2FA3wBy2
driver-class-name: com.mysql.cj.jdbc.Driver

View File

@@ -0,0 +1,205 @@
package com.gxwebsoft.test;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayFundAuthOrderUnfreezeRequest;
import com.alipay.api.response.AlipayFundAuthOrderUnfreezeResponse;
import com.gxwebsoft.common.core.utils.AlipayConfigUtil;
import com.gxwebsoft.shop.entity.FreezeOrder;
import com.gxwebsoft.shop.entity.Order;
import com.gxwebsoft.shop.service.FreezeOrderService;
import com.gxwebsoft.shop.service.OrderService;
import cn.hutool.core.util.IdUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.math.BigDecimal;
/**
* 押金冻结订单修复工具
* 用于处理客户押金无法解冻的问题
*
* 使用场景:
* 1. 客户反馈押金被冻结无法退款
* 2. 数据库中freeze_order记录状态异常
* 3. 需要手动触发支付宝解冻接口
*/
@SpringBootTest
public class FixFreezeOrderTest {
@Resource
private FreezeOrderService freezeOrderService;
@Resource
private OrderService orderService;
@Resource
private AlipayConfigUtil alipayConfig;
/**
* 根据订单号修复并解冻押金
*
* @param orderNo 订单号20260416262053226505
*/
@Test
public void fixAndUnfreezeByOrderNo(String orderNo) {
// 1. 查询订单
Order order = orderService.lambdaQuery()
.eq(Order::getOrderNo, orderNo)
.last("limit 1")
.one();
if (order == null) {
System.out.println("订单不存在:" + orderNo);
return;
}
System.out.println("找到订单:" + order);
fixAndUnfreeze(order);
}
/**
* 根据商户冻结订单号修复并解冻
*
* @param freezeOrderNo 商户冻结订单号2044685513146597377
*/
@Test
public void fixAndUnfreezeByFreezeOrderNo(String freezeOrderNo) {
// 1. 查询冻结订单
FreezeOrder freezeOrder = freezeOrderService.lambdaQuery()
.eq(FreezeOrder::getOutOrderNo, freezeOrderNo)
.last("limit 1")
.one();
if (freezeOrder == null) {
System.out.println("冻结订单不存在:" + freezeOrderNo);
return;
}
System.out.println("找到冻结订单:" + freezeOrder);
// 2. 查询关联的正式订单
Order order = orderService.getById(freezeOrder.getRelOrderId());
if (order == null) {
System.out.println("关联订单不存在relOrderId" + freezeOrder.getRelOrderId());
return;
}
System.out.println("找到关联订单:" + order);
fixAndUnfreeze(order);
}
/**
* 修复并执行解冻
*/
private void fixAndUnfreeze(Order order) {
try {
// 1. 检查并修复订单表的freeze_order_no
if (order.getFreezeOrderNo() == null || order.getFreezeOrderNo().isEmpty()) {
System.out.println("订单缺少freeze_order_no字段尝试从freeze_order表查找...");
FreezeOrder freezeOrder = freezeOrderService.lambdaQuery()
.eq(FreezeOrder::getRelOrderId, order.getOrderId())
.last("limit 1")
.one();
if (freezeOrder != null) {
order.setFreezeOrderNo(freezeOrder.getOutOrderNo());
order.setOutRequestNo(freezeOrder.getOutRequestNo());
order.setIsFreeze(1);
orderService.updateById(order);
System.out.println("已修复订单freeze_order_no" + freezeOrder.getOutOrderNo());
}
}
// 2. 检查并修复freeze_order表的状态
FreezeOrder freezeOrder = freezeOrderService.lambdaQuery()
.eq(FreezeOrder::getOutOrderNo, order.getFreezeOrderNo())
.orderByDesc(FreezeOrder::getCreateTime)
.last("limit 1")
.one();
if (freezeOrder == null) {
System.out.println("没有找到冻结订单记录,需要先创建!");
return;
}
System.out.println("冻结订单状态:" + freezeOrder.getStatus());
System.out.println("冻结金额:" + freezeOrder.getAmount());
System.out.println("授权号:" + freezeOrder.getAuthNo());
// 如果状态不是SUCCESS修复它
if (!"SUCCESS".equals(freezeOrder.getStatus())) {
System.out.println("修复冻结订单状态INIT -> SUCCESS");
freezeOrder.setStatus("SUCCESS");
freezeOrderService.updateById(freezeOrder);
}
// 3. 执行解冻
System.out.println("\n========== 开始执行解冻 ==========");
unfreeze(order.getOrderId());
} catch (Exception e) {
System.err.println("修复失败:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 执行支付宝解冻接口
*/
private void unfreeze(Integer orderId) throws Exception {
Order order = orderService.getById(orderId);
FreezeOrder freezeOrder = freezeOrderService.lambdaQuery()
.eq(FreezeOrder::getOutOrderNo, order.getFreezeOrderNo())
.eq(FreezeOrder::getStatus, "SUCCESS")
.orderByDesc(FreezeOrder::getCreateTime)
.last("limit 1")
.one();
if (freezeOrder == null) {
throw new RuntimeException("没有找到已成功冻结的订单!");
}
DefaultAlipayClient alipayClient = alipayConfig.alipayClient(6);
AlipayFundAuthOrderUnfreezeRequest request = new AlipayFundAuthOrderUnfreezeRequest();
JSONObject bizContent = new JSONObject();
bizContent.put("auth_no", freezeOrder.getAuthNo());
bizContent.put("out_request_no", IdUtil.getSnowflakeNextId());
bizContent.put("amount", freezeOrder.getAmount());
bizContent.put("remark", "用户申请退款解冻");
JSONObject extraParam = new JSONObject();
JSONObject unfreezeBizInfo = new JSONObject();
unfreezeBizInfo.put("bizComplete", true);
extraParam.put("unfreezeBizInfo", unfreezeBizInfo);
bizContent.put("extra_param", extraParam);
request.setBizContent(bizContent.toString());
AlipayFundAuthOrderUnfreezeResponse response = alipayClient.certificateExecute(request);
if (response.isSuccess()) {
System.out.println("✅ 解冻成功!");
System.out.println("解冻金额:" + freezeOrder.getAmount());
System.out.println("授权号:" + freezeOrder.getAuthNo());
} else {
System.out.println("❌ 解冻失败:" + response.getSubMsg());
System.out.println("错误码:" + response.getSubCode());
}
}
// ==================== 快捷测试方法 ====================
@Test
public void testFixCustomerFreezeOrder() {
// 根据客户订单号修复
// fixAndUnfreezeByOrderNo("20260416262053226505");
// 根据商户冻结订单号修复
fixAndUnfreezeByFreezeOrderNo("2044685513146597377");
}
}

View File

@@ -0,0 +1,154 @@
package com.gxwebsoft.test;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.*;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.gxwebsoft.common.core.utils.AlipayConfigUtil;
import com.gxwebsoft.shop.entity.FreezeOrder;
import com.gxwebsoft.shop.entity.Order;
import com.gxwebsoft.shop.service.FreezeOrderService;
import com.gxwebsoft.shop.service.OrderService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
/**
* 押金冻结订单修复 & 解冻工具
* 用于处理 shop_freeze_order 表中 auth_no 为空的问题
*/
@SpringBootTest
public class UnfreezeToolTest {
@Resource
private FreezeOrderService freezeOrderService;
@Resource
private OrderService orderService;
@Resource
private AlipayConfigUtil alipayConfig;
private static final String AUTH_NO = "2026041610002001650571764471";
private static final String OUT_ORDER_NO = "2044685513146597377";
private static final BigDecimal AMOUNT = new BigDecimal("200.00");
/**
* 一键修复并解冻
* 运行此方法即可完成修复 + 解冻
*/
@Test
public void fixAndUnfreeze() throws AlipayApiException {
System.out.println("========================================");
System.out.println("押金修复 & 解冻工具");
System.out.println("========================================");
// 1. 查找冻结订单
System.out.println("\n[1] 查找冻结订单...");
List<FreezeOrder> freezeOrders = freezeOrderService.lambdaQuery()
.eq(FreezeOrder::getOutOrderNo, OUT_ORDER_NO)
.list();
if (freezeOrders.isEmpty()) {
System.out.println("❌ 未找到冻结订单: " + OUT_ORDER_NO);
return;
}
FreezeOrder freezeOrder = freezeOrders.get(0);
System.out.println("✅ 找到冻结订单: id=" + freezeOrder.getId());
System.out.println(" out_order_no: " + freezeOrder.getOutOrderNo());
System.out.println(" status: " + freezeOrder.getStatus());
System.out.println(" auth_no: " + freezeOrder.getAuthNo());
// 2. 修复 auth_no如果为空
if (freezeOrder.getAuthNo() == null || freezeOrder.getAuthNo().isEmpty()) {
System.out.println("\n[2] 修复 auth_no...");
freezeOrder.setAuthNo(AUTH_NO);
freezeOrder.setStatus("SUCCESS");
freezeOrderService.updateById(freezeOrder);
System.out.println("✅ auth_no 已修复: " + AUTH_NO);
}
// 3. 查找关联订单
System.out.println("\n[3] 查找关联订单...");
List<Order> orders = orderService.lambdaQuery()
.eq(Order::getFreezeOrderNo, OUT_ORDER_NO)
.list();
if (orders.isEmpty()) {
System.out.println("❌ 未找到关联订单!");
return;
}
Order order = orders.get(0);
System.out.println("✅ 找到关联订单: id=" + order.getOrderId());
System.out.println(" order_no: " + order.getOrderNo());
System.out.println(" is_freeze: " + order.getIsFreeze());
System.out.println(" freeze_order_no: " + order.getFreezeOrderNo());
// 4. 修复订单表的 freeze_order_no如果不一致
if (!OUT_ORDER_NO.equals(order.getFreezeOrderNo())) {
System.out.println("\n[4] 修复订单 freeze_order_no...");
order.setFreezeOrderNo(OUT_ORDER_NO);
orderService.updateById(order);
System.out.println("✅ freeze_order_no 已修复");
}
// 5. 调用解冻接口
System.out.println("\n[5] 调用支付宝解冻接口...");
try {
DefaultAlipayClient alipayClient = alipayConfig.alipayClient(6);
AlipayFundAuthOrderUnfreezeRequest request = new AlipayFundAuthOrderUnfreezeRequest();
JSONObject bizContent = new JSONObject();
bizContent.put("auth_no", AUTH_NO);
bizContent.put("out_request_no", IdUtil.getSnowflakeNextIdStr());
bizContent.put("amount", AMOUNT);
bizContent.put("remark", "客户申请退款解冻");
JSONObject extraParam = new JSONObject();
JSONObject unfreezeBizInfo = new JSONObject();
unfreezeBizInfo.put("bizComplete", true);
extraParam.put("unfreezeBizInfo", unfreezeBizInfo);
bizContent.put("extra_param", extraParam);
request.setBizContent(bizContent.toJSONString());
AlipayFundAuthOrderUnfreezeResponse response = alipayClient.certificateExecute(request);
System.out.println("----------------------------------------");
System.out.println("支付宝返回:");
System.out.println(JSON.toJSONString(response, true));
System.out.println("----------------------------------------");
if (response.isSuccess() && "10000".equals(response.getCode())) {
System.out.println("\n🎉 解冻成功!");
System.out.println(" 解冻金额: " + response.getAmount());
System.out.println(" 授权号: " + response.getAuthNo());
System.out.println(" 订单号: " + response.getOutOrderNo());
// 更新数据库
System.out.println("\n[6] 更新数据库状态...");
freezeOrder.setUnfreezeAmount(AMOUNT);
freezeOrder.setStatus("UNFREEZE");
freezeOrderService.updateById(freezeOrder);
System.out.println("✅ 数据库已更新");
System.out.println("\n⏰ 资金将在1-7个工作日内退回客户农业银行储蓄卡");
} else {
System.out.println("\n❌ 解冻失败!");
System.out.println(" 错误码: " + response.getSubCode());
System.out.println(" 错误信息: " + response.getSubMsg());
}
} catch (Exception e) {
System.out.println("\n❌ 解冻异常: " + e.getMessage());
e.printStackTrace();
}
}
}