Commit 0381c12b by Jony.L

新支付功能测试2.0

parent 09884fa0
......@@ -7,6 +7,7 @@ import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppRe
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderPageReqVO;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderRespVO;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderInvoiceReqVO;
import com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
import com.luhu.computility.module.compute.service.resourceorder.ResourceOrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
......@@ -41,9 +42,9 @@ public class AppResourceOrderController {
@PostMapping("/create-wpgj")
@Operation(summary = "创建算力资源订单(旺铺聚合支付)")
public CommonResult<AppResourceOrderCreateRespVO> createResourceOrderWithWpgj(@Valid @RequestBody AppResourceOrderCreateReqVO createReqVO) {
public CommonResult<AppPayOrderSubmitRespVO> createResourceOrderWithWpgj(@Valid @RequestBody AppResourceOrderCreateReqVO createReqVO) {
Long userId = getLoginUserId();
AppResourceOrderCreateRespVO respVO = resourceOrderService.createUserResourceOrderWithWpgj(userId, createReqVO);
AppPayOrderSubmitRespVO respVO = resourceOrderService.createUserResourceOrderWithWpgj(userId, createReqVO);
return success(respVO);
}
......
......@@ -13,7 +13,13 @@ public class AppResourceOrderCreateRespVO {
@Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED)
private String orderNo;
@Schema(description = "支付订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "15798")
@Schema(description = "支付订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "15798")
private Long payOrderId;
@Schema(description = "支付二维码URL(WPGJ聚合支付)")
private String payQrCode;
@Schema(description = "支付展示模式(qr_code=二维码,pay_url=支付链接)")
private String displayMode;
}
\ No newline at end of file
......@@ -8,6 +8,7 @@ import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppRe
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderPageReqVO;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderRespVO;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderInvoiceReqVO;
import com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
import com.luhu.computility.module.compute.dal.dataobject.resourceorder.ResourceOrderDO;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.framework.common.pojo.PageParam;
......@@ -78,9 +79,9 @@ public interface ResourceOrderService {
*
* @param userId 用户ID
* @param createReqVO 创建信息
* @return 创建响应
* @return 支付提交响应
*/
AppResourceOrderCreateRespVO createUserResourceOrderWithWpgj(Long userId, @Valid AppResourceOrderCreateReqVO createReqVO);
AppPayOrderSubmitRespVO createUserResourceOrderWithWpgj(Long userId, @Valid AppResourceOrderCreateReqVO createReqVO);
/**
* 更新订单为已支付(支付回调使用)
......
......@@ -443,7 +443,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
@Override
@Transactional(rollbackFor = Exception.class)
public AppResourceOrderCreateRespVO createUserResourceOrderWithWpgj(Long userId, AppResourceOrderCreateReqVO createReqVO) {
public AppPayOrderSubmitRespVO createUserResourceOrderWithWpgj(Long userId, AppResourceOrderCreateReqVO createReqVO) {
// 1. 构建订单
ResourceOrderDO order = buildResourceOrder(userId, createReqVO);
......@@ -451,23 +451,22 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
resourceOrderMapper.insert(order);
// 3. 创建旺铺聚合支付订单
AppPayOrderSubmitRespVO payRespVO = null;
if (order.getPaymentPrice() > 0) {
createPayOrderWithWpgj(order);
payRespVO = createPayOrderWithWpgj(order);
} else {
// 如果价格为0,返回成功状态
payRespVO = new AppPayOrderSubmitRespVO();
payRespVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
}
// 4. 返回结果
AppResourceOrderCreateRespVO respVO = new AppResourceOrderCreateRespVO();
respVO.setId(order.getId());
respVO.setOrderNo(order.getOrderNo());
respVO.setPayOrderId(order.getPayOrderId());
return respVO;
return payRespVO;
}
/**
* 创建旺铺聚合支付订单
*/
private void createPayOrderWithWpgj(ResourceOrderDO order) {
private AppPayOrderSubmitRespVO createPayOrderWithWpgj(ResourceOrderDO order) {
try {
// 1. 创建支付订单(用于数据库记录)
PayOrderCreateReqDTO payOrderCreateReqDTO = new PayOrderCreateReqDTO()
......@@ -495,6 +494,8 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
log.info("[createPayOrderWithWpgj] 旺铺聚合支付订单创建成功,订单ID: {}, 支付订单ID: {}", order.getId(), payOrderId);
return submitRespVO;
} catch (Exception e) {
log.error("[createPayOrderWithWpgj] 创建旺铺聚合支付订单失败", e);
throw new ServiceException("创建支付订单失败: " + e.getMessage());
......
......@@ -7,6 +7,7 @@ import com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjC
import com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties;
import com.luhu.computility.module.pay.service.order.PayOrderService;
import cn.hutool.json.JSONUtil;
import cn.hutool.json.JSONObject;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
......@@ -24,9 +25,9 @@ import static com.luhu.computility.framework.common.pojo.CommonResult.success;
*/
@Tag(name = "管理后台 - WPGJ旺铺聚合支付回调")
@RestController
@RequestMapping("/pay/wpgj")
@RequestMapping("/admin-api/pay/wpgj")
@Slf4j
public class AdminWpgjPayController {
public class WpgjPayController {
@Resource
private PayOrderService payOrderService;
......@@ -41,8 +42,9 @@ public class AdminWpgjPayController {
log.info("[notifyWpgjPay] 收到WPGJ支付回调,加密数据: {}", encryptedData);
// 1. 解密回调数据
String decryptedJson = WpgjCryptoUtils.decryptResponse(encryptedData, wpgjPayProperties.getPrivateKey());
Map<String, Object> decryptedData = JSONUtil.parseObj(decryptedJson);
JSONObject decryptedResponse = WpgjCryptoUtils.decryptResponse(encryptedData, wpgjPayProperties.getPrivateKey());
Map<String, Object> decryptedData = decryptedResponse.get("data") != null ?
(Map<String, Object>) decryptedResponse.get("data") : decryptedResponse;
log.info("[notifyWpgjPay] 解密后的回调数据: {}", JsonUtils.toJsonString(decryptedData));
......@@ -69,7 +71,7 @@ public class AdminWpgjPayController {
PayOrderRespDTO notify = new PayOrderRespDTO();
// 根据WPGJ回调文档解析字段
notify.setOutTradeNo((String) data.get("out_trade_no")); // 商户订单号
notify.setOutTradeNo((String) data.get("mer_order_id")); // 商户订单号
notify.setChannelOrderNo((String) data.get("transaction_id")); // 第三方交易号
notify.setStatus(parseWpgjStatus((String) data.get("trade_state"))); // 交易状态
......
......@@ -228,52 +228,65 @@ public class PayOrderServiceImpl implements PayOrderService {
}
/**
* 调用WPGJ支付API
* 调用WPGJ支付API - 按照demo代码标准实现动态支付序列码接口
*/
private PayOrderRespDTO callWpgjApi(PayOrderDO order, PayOrderExtensionDO orderExtension,
AppPayOrderSubmitReqVO reqVO, String userIp) {
try {
log.info("[callWpgjApi] 开始调用WPGJ支付API,订单号: {}", orderExtension.getNo());
// 1. 构建业务数据
// 1. 构建业务数据 - 按照demo的testDynamicOrder方法
JSONObject businessData = new JSONObject();
businessData.set("mer_no", wpgjPayProperties.getMerNo());
businessData.set("mer_code", wpgjPayProperties.getMerCode());
businessData.set("term_code", wpgjPayProperties.getTermCode());
businessData.set("out_trade_no", orderExtension.getNo());
businessData.set("pay_amount", order.getPrice());
businessData.set("goods_name", order.getSubject());
businessData.set("goods_desc", order.getBody());
businessData.set("notify_url", wpgjPayProperties.getNotifyUrl());
businessData.set("mer_order_id", orderExtension.getNo()); // 商户唯一订单号
businessData.set("order_amt", String.valueOf(order.getPrice() / 100.0)); // 转换为元,保留两位小数
businessData.set("organiz_no", wpgjPayProperties.getOrganizNo());
businessData.set("cashier_type", "1"); // 收银台模板
businessData.set("return_url", reqVO.getReturnUrl());
businessData.set("time_expire", order.getExpireTime());
businessData.set("notifyurl", wpgjPayProperties.getNotifyUrl());
// 2. 构建完整请求数据
String requestData = WpgjCryptoUtils.buildRequestData(businessData, wpgjPayProperties.getOrganizNo());
String encryptedRequest = WpgjCryptoUtils.encryptRequest(requestData, wpgjPayProperties.getPublicKey());
// 2. 构建加密请求数据 - 按照demo标准
String encryptedRequest = WpgjCryptoUtils.buildEncryptedRequest(
businessData,
wpgjPayProperties.getOrganizNo(),
wpgjPayProperties.getPublicKey()
);
// 3. 发送HTTP请求
// 3. URL编码 - 按照demo要求
String encodedRequest = java.net.URLEncoder.encode(encryptedRequest, "UTF-8");
log.info("[callWpgjApi] 发送加密请求数据: {}", encryptedRequest);
log.info("[callWpgjApi] 请求URL: {}", wpgjPayProperties.getApiUrl());
// 4. 发送HTTP请求 - 按照demo方式
HttpResponse response = HttpRequest.post(wpgjPayProperties.getApiUrl())
.header("Content-Type", "application/json")
.body(encryptedRequest)
.header("Content-Type", "application/x-www-form-urlencoded")
.body(encodedRequest)
.timeout(30000)
.execute();
// 4. 处理响应
// 5. 处理响应
if (!response.isOk()) {
log.error("[callWpgjApi] WPGJ API调用失败,HTTP状态码: {}, 响应: {}",
response.getStatus(), response.body());
throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, "HTTP_ERROR", "支付网关调用失败");
throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, "HTTP_ERROR", "支付网关调用失败,状态码: " + response.getStatus());
}
String encryptedResponse = response.body();
String decryptedResponse = WpgjCryptoUtils.decryptResponse(encryptedResponse, wpgjPayProperties.getPrivateKey());
JSONObject responseData = JSONUtil.parseObj(decryptedResponse);
log.info("[callWpgjApi] WPGJ API调用成功,响应: {}", decryptedResponse);
// 5. 解析响应结果
return parseWpgjApiResponse(responseData, orderExtension.getNo());
String responseData = response.body();
log.info("[callWpgjApi] WPGJ API调用成功,响应: {}", responseData);
// 6. 解析响应结果 - 需要解密
JSONObject responseJson = new JSONObject(responseData);
if ("0000".equals(responseJson.getStr("code"))) {
// 解密响应数据
JSONObject decryptedResponse = WpgjCryptoUtils.decryptResponse(responseData, wpgjPayProperties.getPrivateKey());
return parseWpgjApiResponse(decryptedResponse, orderExtension.getNo());
} else {
// 处理错误响应
return parseWpgjError(responseJson, orderExtension.getNo());
}
} catch (Exception e) {
log.error("[callWpgjApi] WPGJ API调用异常,订单号: {}", orderExtension.getNo(), e);
......@@ -282,33 +295,48 @@ public class PayOrderServiceImpl implements PayOrderService {
}
/**
* 解析WPGJ API响应
* 解析WPGJ API成功响应 - 根据demo动态支付接口
*/
private PayOrderRespDTO parseWpgjApiResponse(JSONObject response, String outTradeNo) {
PayOrderRespDTO respDTO = new PayOrderRespDTO();
// 根据WPGJ API文档解析响应字段
respDTO.setOutTradeNo(outTradeNo);
respDTO.setChannelCode("wpgj_dynamic");
respDTO.setStatus(PayOrderStatusEnum.WAITING.getStatus());
// 解析二维码信息(假设WPGJ返回二维码URL)
if (response.containsKey("qr_code")) {
respDTO.setDisplayMode("qr_code");
respDTO.setDisplayContent(response.getStr("qr_code"));
} else if (response.containsKey("pay_url")) {
// 解析data字段中的payUrl(动态支付URL)
JSONObject data = response.getJSONObject("data");
if (data != null && data.containsKey("payUrl")) {
String payUrl = data.getStr("payUrl");
respDTO.setDisplayMode("pay_url");
respDTO.setDisplayContent(response.getStr("pay_url"));
respDTO.setDisplayContent(payUrl);
log.info("[parseWpgjApiResponse] 获取到支付URL: {}", payUrl);
}
// 检查是否有错误码
if (response.containsKey("resp_code") && !"00".equals(response.getStr("resp_code"))) {
respDTO.setChannelErrorCode(response.getStr("resp_code"));
respDTO.setChannelErrorMsg(response.getStr("resp_msg"));
}
respDTO.setRawData(JSONUtil.toJsonStr(response));
return respDTO;
}
/**
* 解析WPGJ API错误响应
*/
private PayOrderRespDTO parseWpgjError(JSONObject response, String outTradeNo) {
PayOrderRespDTO respDTO = new PayOrderRespDTO();
respDTO.setOutTradeNo(outTradeNo);
respDTO.setChannelCode("wpgj_dynamic");
respDTO.setStatus(PayOrderStatusEnum.CLOSED.getStatus()); // 错误时设置为关闭状态
// 设置错误信息
respDTO.setChannelErrorCode(response.getStr("code"));
respDTO.setChannelErrorMsg(response.getStr("msg"));
respDTO.setRawData(JSONUtil.toJsonStr(response));
log.error("[parseWpgjError] WPGJ API返回错误: code={}, msg={}",
response.getStr("code"), response.getStr("msg"));
return respDTO;
}
......
......@@ -165,16 +165,16 @@ computility:
captcha:
enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试;
pay:
# order-notify-url: https://phslgld.hnluchuan.com/admin-api/pay/notify/order # 支付渠道的【支付】回调地址
# refund-notify-url: https://phslgld.hnluchuan.com/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址
# transfer-notify-url: https://phslgld.hnluchuan.com/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址
order-notify-url: https://phslgld.hnluchuan.com/admin-api/pay/notify/order # 支付渠道的【支付】回调地址
refund-notify-url: https://phslgld.hnluchuan.com/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址
transfer-notify-url: https://phslgld.hnluchuan.com/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址
wpgj-pay:
# WPGJ旺铺聚合支付配置
organiz-no: 105549
mer-no: 99911325651RE1R
mer-code: K20241200111267
term-code: 1011215692596
api-url: https://stg5-qr.wpgjcs.com
api-url: https://stg5-qr.wpgjcs.com/industrial/payment/dynamic
notify-url: https://phslgld.hnluchuan.com/admin-api/pay/wpgj/notify
public-key: |
-----BEGIN PUBLIC KEY-----
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment