Commit 0381c12b by Jony.L

新支付功能测试2.0

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