Commit f198f6ea by Jony.L

新支付功能-api模块支付重构

parent fdb05415
package com.luhu.computility.module.apihub.controller.admin.notify;
import cn.hutool.core.util.StrUtil;
import com.luhu.computility.framework.common.pojo.CommonResult;
import com.luhu.computility.framework.common.util.json.JsonUtils;
import com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO;
import com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyRespDTO;
import com.luhu.computility.module.apihub.service.apiorder.ApiOrderService;
import com.luhu.computility.module.pay.enums.WpgjOrderStatusEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestBody;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
/**
* APIHub模块 - WPGJ旺铺聚合支付回调Controller
*
* 独立处理WPGJ支付回调,直接更新API订单状态
*
* @author jony
*/
@Tag(name = "管理后台 - APIHub WPGJ旺铺聚合支付回调")
@RestController
@RequestMapping("/apihub/wpgj")
@Slf4j
public class ApihubWpgjPayController {
@Resource
private ApiOrderService apiOrderService;
@Resource
private WpgjPayProperties wpgjPayProperties;
@PostMapping("/notify")
@PermitAll
@Operation(summary = "WPGJ支付异步回调通知 - APIHub模块")
public CommonResult<WpgjPayNotifyRespDTO> notifyWpgjPayNew(@RequestBody WpgjPayNotifyDTO notifyDTO) {
log.info("[notifyWpgjPayNew][APIHub] 收到WPGJ支付回调(新): {}", JsonUtils.toJsonString(notifyDTO));
WpgjPayNotifyRespDTO response = new WpgjPayNotifyRespDTO();
try {
log.info("[notifyWpgjPayNew][APIHub] 收到WPGJ支付回调(新): {}", JsonUtils.toJsonString(notifyDTO));
// 1. 验证签名(对所有出现的非空字段,按 ASCII 升序拼接,排除 sign)
if (!verifyWpgjSignature(toPayloadMap(notifyDTO))) {
log.error("[notifyWpgjPayNew][APIHub] WPGJ回调签名验证失败");
response.setCode("99");
response.setMsg("签名验证失败");
response.setTimestamp(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")));
return CommonResult.success(response);
}
String merOrderId = notifyDTO.getMerOrderId();
String orderStatus = notifyDTO.getOrderStatus();
log.info("[notifyWpgjPayNew][APIHub] 处理WPGJ支付结果,商户订单号: {}, 订单状态: {}", merOrderId, orderStatus);
// 2. 幂等处理:根据订单状态更新(与算力资源模块保持一致逻辑)
if (WpgjOrderStatusEnum.isSuccess(orderStatus)) {
apiOrderService.updateOrderPaidByWpgj(Long.parseLong(merOrderId), notifyDTO);
log.info("[notifyWpgjPayNew][APIHub] 支付成功处理完成,商户订单号: {}", merOrderId);
} else if (WpgjOrderStatusEnum.isFailedOrClosed(orderStatus)) {
apiOrderService.updateOrderFailedByWpgj(Long.parseLong(merOrderId), notifyDTO);
log.info("[notifyWpgjPayNew][APIHub] 支付失败/关闭处理完成,商户订单号: {}", merOrderId);
} else {
log.info("[notifyWpgjPayNew][APIHub] 订单状态无需处理,商户订单号: {}, 状态: {}", merOrderId, orderStatus);
}
// 3. 返回成功应答
response.setCode("00");
response.setMsg("成功");
response.setTimestamp(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")));
return CommonResult.success(response);
} catch (Exception e) {
log.error("[notifyWpgjPayNew][APIHub] WPGJ支付回调处理失败", e);
response.setCode("99");
response.setMsg("处理失败");
response.setTimestamp(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")));
return CommonResult.success(response);
}
}
/**
* Map 形式的回调请求验签:对所有出现的非空字段(排除 sign)进行 ASCII 排序拼接后 + key,再 MD5(UTF-8) 大写
*/
private boolean verifyWpgjSignature(Map<String, Object> payload) {
try {
Object signObj = payload.get("sign");
String originSign = signObj == null ? null : String.valueOf(signObj);
if (StrUtil.isBlank(originSign)) {
log.warn("[verifyWpgjSignature][APIHub] 回调缺少 sign 字段");
return false;
}
// 过滤掉 sign、自身为空的字段,按 ASCII 升序
TreeMap<String, String> sorted = new TreeMap<>();
for (Map.Entry<String, Object> e : payload.entrySet()) {
String k = e.getKey();
if ("sign".equals(k)) {
continue;
}
String v = e.getValue() == null ? null : String.valueOf(e.getValue());
if (StrUtil.isBlank(v)) {
continue;
}
sorted.put(k, v);
}
String dataStr = sorted.entrySet().stream()
.map(en -> en.getKey() + "=" + en.getValue())
.collect(Collectors.joining("&"));
String signStr = dataStr + "&key=" + wpgjPayProperties.getSignKey();
String calculatedSign = DigestUtil.md5Hex(signStr).toUpperCase();
log.info("[verifyWpgjSignature][APIHub-New] 待签名字符串: {}", dataStr);
log.info("[verifyWpgjSignature][APIHub-New] 加签前(带key): {}", signStr);
log.info("[verifyWpgjSignature][APIHub-New] 计算签名: {},原始签名: {}", calculatedSign, originSign);
return calculatedSign.equalsIgnoreCase(originSign);
} catch (Exception e) {
log.error("[verifyWpgjSignature][APIHub-New] 验签异常", e);
return false;
}
}
/**
* 将 DTO 转换为 Map(以供应商字段名 snake_case 作为 key),便于统一验签
*/
private Map<String, Object> toPayloadMap(WpgjPayNotifyDTO dto) {
TreeMap<String, Object> map = new TreeMap<>();
map.put("device_no", dto.getDeviceNo());
map.put("mer_no", dto.getMerNo());
map.put("mer_code", dto.getMerCode());
map.put("payway_code", dto.getPaywayCode());
map.put("order_id", dto.getOrderId());
map.put("mer_order_id", dto.getMerOrderId());
map.put("gateway_mer_order_id", dto.getGatewayMerOrderId());
map.put("order_time", dto.getOrderTime());
map.put("order_amt", dto.getOrderAmt());
map.put("order_status", dto.getOrderStatus());
map.put("trade_no", dto.getTradeNo());
map.put("trade_time", dto.getTradeTime());
map.put("order_title", dto.getOrderTitle());
map.put("fee", dto.getFee());
map.put("act_amt", dto.getActAmt());
map.put("buyer_id", dto.getBuyerId());
map.put("trade_top_no", dto.getTradeTopNo());
map.put("card_type", dto.getCardType());
map.put("sign", dto.getSign());
return map;
}
}
\ No newline at end of file
...@@ -8,6 +8,7 @@ import com.luhu.computility.framework.common.util.object.BeanUtils; ...@@ -8,6 +8,7 @@ import com.luhu.computility.framework.common.util.object.BeanUtils;
import com.luhu.computility.framework.security.core.util.SecurityFrameworkUtils; import com.luhu.computility.framework.security.core.util.SecurityFrameworkUtils;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderCreateReqVO; import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderCreateReqVO;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderCreateRespVO; import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderCreateRespVO;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiWpgjPayOrderSubmitRespVO;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderInvoiceReqVO; import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderInvoiceReqVO;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderPageReqVO; import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderPageReqVO;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderRespVO; import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderRespVO;
...@@ -53,6 +54,14 @@ public class AppApiOrderController { ...@@ -53,6 +54,14 @@ public class AppApiOrderController {
return success(new AppApiOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId())); return success(new AppApiOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
} }
@PostMapping("/create-wpgj")
@Operation(summary = "创建api订单(旺铺聚合支付)")
public CommonResult<AppApiWpgjPayOrderSubmitRespVO> createApiOrderWithWpgj(@Valid @RequestBody AppApiOrderCreateReqVO createReqVO) {
Long userId = SecurityFrameworkUtils.getLoginUser().getId();
AppApiWpgjPayOrderSubmitRespVO respVO = apiOrderService.createUserApiOrderWithWpgj(userId, createReqVO);
return success(respVO);
}
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得api订单分页") @Operation(summary = "获得api订单分页")
......
package com.luhu.computility.module.apihub.controller.app.apiorder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 用户 APP - API订单 WPGJ旺铺聚合支付订单提交 Response VO
* 独立于老支付系统的WPGJ支付响应
*
* @author jony
*/
@Schema(description = "用户 APP - API订单 WPGJ旺铺聚合支付订单提交 Response VO")
@Data
public class AppApiWpgjPayOrderSubmitRespVO {
@Schema(description = "订单ID(WPGJ订单ID,用于前端轮询支付状态)", requiredMode = Schema.RequiredMode.REQUIRED, example = "202510301436330934307677")
@NotNull(message = "订单ID不能为空")
private Long id;
@Schema(description = "支付状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
@NotNull(message = "支付状态不能为空")
private String status;
@Schema(description = "展示模式", example = "url")
private String displayMode;
@Schema(description = "展示内容(支付链接等)", example = "https://example.com/pay")
private String displayContent;
}
\ No newline at end of file
...@@ -4,12 +4,14 @@ import java.util.*; ...@@ -4,12 +4,14 @@ import java.util.*;
import javax.validation.*; import javax.validation.*;
import com.luhu.computility.module.apihub.controller.admin.apiorder.vo.*; import com.luhu.computility.module.apihub.controller.admin.apiorder.vo.*;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderCreateReqVO; import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderCreateReqVO;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiWpgjPayOrderSubmitRespVO;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderInvoiceReqVO; import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderInvoiceReqVO;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderPageReqVO; import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderPageReqVO;
import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderRespVO; import com.luhu.computility.module.apihub.controller.app.apiorder.vo.AppApiOrderRespVO;
import com.luhu.computility.module.apihub.dal.dataobject.apiorder.ApiOrderDO; import com.luhu.computility.module.apihub.dal.dataobject.apiorder.ApiOrderDO;
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;
import com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO;
/** /**
* api订单 Service 接口 * api订单 Service 接口
...@@ -103,4 +105,29 @@ public interface ApiOrderService { ...@@ -103,4 +105,29 @@ public interface ApiOrderService {
* @return * @return
*/ */
boolean updateRequestInvoice(AppApiOrderInvoiceReqVO reqVO); boolean updateRequestInvoice(AppApiOrderInvoiceReqVO reqVO);
/**
* 创建用户API订单(旺铺聚合支付)
*
* @param userId 用户ID
* @param createReqVO 创建请求
* @return WPGJ支付订单提交响应
*/
AppApiWpgjPayOrderSubmitRespVO createUserApiOrderWithWpgj(Long userId, AppApiOrderCreateReqVO createReqVO);
/**
* WPGJ支付成功回调处理
*
* @param apiOrderId API订单ID
* @param notifyDTO WPGJ回调数据
*/
void updateOrderPaidByWpgj(Long apiOrderId, WpgjPayNotifyDTO notifyDTO);
/**
* WPGJ支付失败/关闭回调处理
*
* @param apiOrderId API订单ID
* @param notifyDTO WPGJ回调数据
*/
void updateOrderFailedByWpgj(Long apiOrderId, WpgjPayNotifyDTO notifyDTO);
} }
\ No newline at end of file
...@@ -45,10 +45,10 @@ public class ComputeWpgjPayController { ...@@ -45,10 +45,10 @@ public class ComputeWpgjPayController {
@Resource @Resource
private WpgjPayProperties wpgjPayProperties; private WpgjPayProperties wpgjPayProperties;
@PostMapping("/new-notify") @PostMapping("/notify")
@PermitAll @PermitAll
@Operation(summary = "WPGJ支付异步回调通知(新) - 按文档通用验签") @Operation(summary = "WPGJ支付异步回调通知(新) - 按文档通用验签")
public CommonResult<WpgjPayNotifyRespDTO> notifyWpgjPayNew(@RequestBody WpgjPayNotifyDTO notifyDTO) { public CommonResult<WpgjPayNotifyRespDTO> notifyWpgjPay(@RequestBody WpgjPayNotifyDTO notifyDTO) {
log.info("[notifyWpgjPayNew][Compute] 收到WPGJ支付回调(新): {}", "new-notify进来了进来了————————————————————————————————————————————————————————————————————————————————————————————————"); log.info("[notifyWpgjPayNew][Compute] 收到WPGJ支付回调(新): {}", "new-notify进来了进来了————————————————————————————————————————————————————————————————————————————————————————————————");
WpgjPayNotifyRespDTO response = new WpgjPayNotifyRespDTO(); WpgjPayNotifyRespDTO response = new WpgjPayNotifyRespDTO();
try { try {
......
...@@ -25,9 +25,9 @@ import com.luhu.computility.module.compute.service.resourcespu.ResourceSpuServic ...@@ -25,9 +25,9 @@ import com.luhu.computility.module.compute.service.resourcespu.ResourceSpuServic
import com.luhu.computility.module.pay.api.order.PayOrderApi; import com.luhu.computility.module.pay.api.order.PayOrderApi;
import com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO; import com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO;
import com.luhu.computility.module.pay.api.order.dto.PayOrderRespDTO; import com.luhu.computility.module.pay.api.order.dto.PayOrderRespDTO;
import com.luhu.computility.module.pay.api.wpgj.PayOrderWpgjApi; import com.luhu.computility.module.pay.api.wpgj.CommonWpgjPayApi;
import com.luhu.computility.module.pay.api.wpgj.dto.PayOrderWpgjCreateReqDTO; import com.luhu.computility.module.pay.api.wpgj.dto.CommonWpgjCreateReqDTO;
import com.luhu.computility.module.pay.api.wpgj.vo.WpgjPayOrderSubmitReqVO; import com.luhu.computility.module.pay.api.wpgj.vo.CommonWpgjPayOrderSubmitRespVO;
import com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO; import com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO;
import com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; import com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
import com.luhu.computility.module.pay.dal.dataobject.wpgj.PayOrderWpgjDO; import com.luhu.computility.module.pay.dal.dataobject.wpgj.PayOrderWpgjDO;
...@@ -86,7 +86,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -86,7 +86,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
private PayOrderApi payOrderApi; private PayOrderApi payOrderApi;
@Resource @Resource
private PayOrderWpgjApi payOrderWpgjApi; private CommonWpgjPayApi commonWpgjPayApi;
@Resource @Resource
private ResourceOrderProperties resourceOrderProperties; private ResourceOrderProperties resourceOrderProperties;
...@@ -476,45 +476,38 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -476,45 +476,38 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
} }
/** /**
* 创建WPGJ旺铺聚合支付订单(完全独立实现 * 创建WPGJ旺铺聚合支付订单(使用通用服务
*/ */
private AppWpgjPayOrderSubmitRespVO createWpgjPayOrder(ResourceOrderDO order) { private AppWpgjPayOrderSubmitRespVO createWpgjPayOrder(ResourceOrderDO order) {
try { try {
log.info("[createWpgjPayOrder] 开始创建WPGJ支付订单,资源订单ID: {}, 支付金额: {}", log.info("[createWpgjPayOrder] 开始创建WPGJ支付订单,资源订单ID: {}, 支付金额: {}",
order.getId(), order.getPaymentPrice()); order.getId(), order.getPaymentPrice());
// 1. 创建WPGJ支付订单记录 // 1. 构建通用WPGJ创建请求
PayOrderWpgjCreateReqDTO wpgjCreateReqDTO = new PayOrderWpgjCreateReqDTO(); CommonWpgjCreateReqDTO createReqDTO = new CommonWpgjCreateReqDTO();
wpgjCreateReqDTO.setBusinessType(1); // 1-算力资源订单 createReqDTO.setBusinessType(1); // 1-算力资源订单
wpgjCreateReqDTO.setMerOrderId(String.valueOf(order.getId())); createReqDTO.setBusinessOrderId(order.getId());
String subject = order.getSpuName() + " - " + getDurationDaysFromSku(order.getSkuId()) + "天"; String orderTitle = order.getSpuName() + " - " + getDurationDaysFromSku(order.getSkuId()) + "天";
subject = StrUtils.maxLength(subject, 64); // WPGJ订单标题最大64位 createReqDTO.setOrderTitle(orderTitle);
wpgjCreateReqDTO.setOrderTitle(subject); createReqDTO.setPayAmount(order.getPaymentPrice().intValue());
wpgjCreateReqDTO.setOrderAmt(String.valueOf(order.getPaymentPrice() / 100.0)); // 转换为元
Long wpgjOrderId = payOrderWpgjApi.createOrderWpgj(wpgjCreateReqDTO);
log.info("[createWpgjPayOrder] WPGJ订单创建成功,资源订单ID: {}, WPGJ订单ID: {}", order.getId(), wpgjOrderId);
// 2. 更新算力资源订单的WPGJ订单ID
resourceOrderMapper.updateById(new ResourceOrderDO().setId(order.getId()).setPayOrderId(wpgjOrderId));
// 3. 调用WPGJ支付提交API获取支付链接 // 2. 调用通用WPGJ服务
WpgjPayOrderSubmitReqVO submitReqVO = new WpgjPayOrderSubmitReqVO(); CommonWpgjPayOrderSubmitRespVO commonRespVO = commonWpgjPayApi.createCommonWpgjOrder(createReqDTO);
submitReqVO.setId(wpgjOrderId); log.info("[createWpgjPayOrder] 通用WPGJ服务调用成功,资源订单ID: {}, WPGJ订单ID: {}",
order.getId(), commonRespVO.getWpgjOrderId());
AppPayOrderSubmitRespVO submitRespVO = payOrderApi.submitWpgjOrder(submitReqVO); // 3. 更新算力资源订单的WPGJ订单ID
log.info("[createWpgjPayOrder] WPGJ支付提交成功,资源订单ID: {}, WPGJ订单ID: {}, 支付状态: {}", resourceOrderMapper.updateById(new ResourceOrderDO().setId(order.getId()).setPayOrderId(commonRespVO.getWpgjOrderId()));
order.getId(), wpgjOrderId, submitRespVO.getStatus());
// 4. 构建返回数据 - 包含支付链接 // 4. 构建算力资源专用的返回数据
AppWpgjPayOrderSubmitRespVO respVO = new AppWpgjPayOrderSubmitRespVO(); AppWpgjPayOrderSubmitRespVO respVO = new AppWpgjPayOrderSubmitRespVO();
respVO.setId(wpgjOrderId); // 返回WPGJ订单ID,用于前端轮询 respVO.setId(commonRespVO.getWpgjOrderId()); // 返回WPGJ订单ID,用于前端轮询
respVO.setStatus(submitRespVO.getStatus()); respVO.setStatus(Integer.parseInt(commonRespVO.getStatus()));
respVO.setDisplayMode(submitRespVO.getDisplayMode()); respVO.setDisplayMode(commonRespVO.getDisplayMode());
respVO.setDisplayContent(submitRespVO.getDisplayContent()); // 支付链接 respVO.setDisplayContent(commonRespVO.getDisplayContent()); // 支付链接
log.info("[createWpgjPayOrder] WPGJ支付订单创建完成,资源订单ID: {}, WPGJ订单ID: {}, 支付链接: {}", log.info("[createWpgjPayOrder] WPGJ支付订单创建完成,资源订单ID: {}, WPGJ订单ID: {}, 支付链接: {}",
order.getId(), wpgjOrderId, submitRespVO.getDisplayContent()); order.getId(), commonRespVO.getWpgjOrderId(), commonRespVO.getDisplayContent());
return respVO; return respVO;
......
...@@ -129,8 +129,11 @@ public class PayOrderApiImpl implements PayOrderApi { ...@@ -129,8 +129,11 @@ public class PayOrderApiImpl implements PayOrderApi {
businessData.set("organiz_no", wpgjPayProperties.getOrganizNo()); businessData.set("organiz_no", wpgjPayProperties.getOrganizNo());
businessData.set("cashier_type", "1"); businessData.set("cashier_type", "1");
businessData.set("return_url", ""); // WPGJ订单暂不使用return_url businessData.set("return_url", ""); // WPGJ订单暂不使用return_url
businessData.set("notifyurl", wpgjPayProperties.getNotifyUrl());
log.error("[callWpgjApi] 开始调用WPGJ支付NotifyUrl: {}", wpgjPayProperties.getNotifyUrl()); // 根据业务类型选择回调地址
String notifyUrl = getNotifyUrlByBusinessType(wpgjOrder.getBusinessType());
businessData.set("notifyurl", notifyUrl);
log.error("[callWpgjApi] 开始调用WPGJ支付NotifyUrl: {}, 业务类型: {}", notifyUrl, wpgjOrder.getBusinessType());
// 2. 构建加密请求数据 // 2. 构建加密请求数据
String encryptedRequest = WpgjCryptoUtils.buildEncryptedRequest( String encryptedRequest = WpgjCryptoUtils.buildEncryptedRequest(
...@@ -221,4 +224,35 @@ public class PayOrderApiImpl implements PayOrderApi { ...@@ -221,4 +224,35 @@ public class PayOrderApiImpl implements PayOrderApi {
log.info("[updateWpgjOrderAfterSubmit] WPGJ订单提交完成,订单ID: {}", wpgjOrder.getId()); log.info("[updateWpgjOrderAfterSubmit] WPGJ订单提交完成,订单ID: {}", wpgjOrder.getId());
} }
/**
* 根据业务类型获取回调地址
*
* @param businessType 业务类型 1-算力资源订单 2-API订单
* @return 回调地址
*/
private String getNotifyUrlByBusinessType(Integer businessType) {
if (businessType == null) {
return wpgjPayProperties.getNotifyUrl();
}
switch (businessType) {
case 1:
String computeNotifyUrl = wpgjPayProperties.getNotifyUrlCompute();
if (computeNotifyUrl != null && !computeNotifyUrl.trim().isEmpty()) {
return computeNotifyUrl;
}
break;
case 2:
String apiNotifyUrl = wpgjPayProperties.getNotifyUrlApi();
if (apiNotifyUrl != null && !apiNotifyUrl.trim().isEmpty()) {
return apiNotifyUrl;
}
break;
default:
break;
}
return wpgjPayProperties.getNotifyUrl();
}
} }
package com.luhu.computility.module.pay.api.wpgj;
import com.luhu.computility.module.pay.api.wpgj.dto.CommonWpgjCreateReqDTO;
import com.luhu.computility.module.pay.api.wpgj.vo.CommonWpgjPayOrderSubmitRespVO;
import javax.validation.Valid;
/**
* 通用WPGJ支付 API 接口
* 支持算力资源订单和API订单等多种业务类型
*
* @author jony
*/
public interface CommonWpgjPayApi {
/**
* 创建通用WPGJ支付订单
* 支持算力资源订单和API订单等多种业务类型
*
* @param createReqDTO 创建请求
* @return WPGJ支付订单提交响应
*/
CommonWpgjPayOrderSubmitRespVO createCommonWpgjOrder(@Valid CommonWpgjCreateReqDTO createReqDTO);
}
\ No newline at end of file
package com.luhu.computility.module.pay.api.wpgj.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 通用WPGJ支付创建请求 DTO
* 支持算力资源订单和API订单等多种业务类型
*
* @author jony
*/
@Schema(description = "通用WPGJ支付创建请求 DTO")
@Data
public class CommonWpgjCreateReqDTO {
@Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "业务类型不能为空")
private Integer businessType;
@Schema(description = "业务订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
@NotNull(message = "业务订单ID不能为空")
private Long businessOrderId;
@Schema(description = "订单标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "API服务 - 基础包")
@NotBlank(message = "订单标题不能为空")
private String orderTitle;
@Schema(description = "支付金额(分)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
@NotNull(message = "支付金额不能为空")
private Integer payAmount;
}
\ No newline at end of file
package com.luhu.computility.module.pay.api.wpgj.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 通用WPGJ支付订单提交响应 VO
* 支持算力资源订单和API订单等多种业务类型
*
* @author jony
*/
@Schema(description = "通用WPGJ支付订单提交响应 VO")
@Data
public class CommonWpgjPayOrderSubmitRespVO {
@Schema(description = "WPGJ订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "202510301436330934307677")
private Long wpgjOrderId;
@Schema(description = "支付状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private String status;
@Schema(description = "展示模式", example = "QR_CODE")
private String displayMode;
@Schema(description = "展示内容(支付链接或二维码内容)", example = "https://pay.example.com/qr/123")
private String displayContent;
}
\ No newline at end of file
...@@ -40,7 +40,17 @@ public class WpgjPayProperties { ...@@ -40,7 +40,17 @@ public class WpgjPayProperties {
private String apiUrl; private String apiUrl;
/** /**
* 回调地址 * 算力资源模块回调地址
*/
private String notifyUrlCompute;
/**
* APIHub模块回调地址
*/
private String notifyUrlApi;
/**
* 兼容旧的notifyUrl字段
*/ */
private String notifyUrl; private String notifyUrl;
......
package com.luhu.computility.module.pay.service.wpgj;
import cn.hutool.core.util.ObjectUtil;
import com.luhu.computility.framework.common.exception.ServiceException;
import com.luhu.computility.module.pay.api.wpgj.CommonWpgjPayApi;
import com.luhu.computility.module.pay.api.wpgj.PayOrderWpgjApi;
import com.luhu.computility.module.pay.api.wpgj.dto.CommonWpgjCreateReqDTO;
import com.luhu.computility.module.pay.api.wpgj.dto.PayOrderWpgjCreateReqDTO;
import com.luhu.computility.module.pay.api.wpgj.vo.CommonWpgjPayOrderSubmitRespVO;
import com.luhu.computility.module.pay.api.wpgj.vo.WpgjPayOrderSubmitReqVO;
import com.luhu.computility.module.pay.api.order.PayOrderApi;
import com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
import com.luhu.computility.framework.common.util.string.StrUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.Valid;
import static com.luhu.computility.module.pay.enums.order.PayOrderStatusEnum.SUCCESS;
/**
* 通用WPGJ支付服务实现
* 支持算力资源订单和API订单等多种业务类型
*
* @author jony
*/
@Service
@Slf4j
public class CommonWpgjPayServiceImpl implements CommonWpgjPayApi {
@Resource
private PayOrderWpgjApi payOrderWpgjApi;
@Resource
private PayOrderApi payOrderApi;
@Override
public CommonWpgjPayOrderSubmitRespVO createCommonWpgjOrder(@Valid CommonWpgjCreateReqDTO createReqDTO) {
try {
log.info("[createCommonWpgjOrder] 开始创建通用WPGJ支付订单,业务类型: {}, 业务订单ID: {}, 支付金额: {}",
createReqDTO.getBusinessType(), createReqDTO.getBusinessOrderId(), createReqDTO.getPayAmount());
// 1. 创建WPGJ支付订单记录
PayOrderWpgjCreateReqDTO wpgjCreateReqDTO = new PayOrderWpgjCreateReqDTO();
wpgjCreateReqDTO.setBusinessType(createReqDTO.getBusinessType());
wpgjCreateReqDTO.setMerOrderId(String.valueOf(createReqDTO.getBusinessOrderId()));
wpgjCreateReqDTO.setOrderTitle(StrUtils.maxLength(createReqDTO.getOrderTitle(), 64)); // WPGJ订单标题最大64位
wpgjCreateReqDTO.setOrderAmt(String.valueOf(createReqDTO.getPayAmount() / 100.0)); // 转换为元
Long wpgjOrderId = payOrderWpgjApi.createOrderWpgj(wpgjCreateReqDTO);
log.info("[createCommonWpgjOrder] WPGJ订单创建成功,业务类型: {}, 业务订单ID: {}, WPGJ订单ID: {}",
createReqDTO.getBusinessType(), createReqDTO.getBusinessOrderId(), wpgjOrderId);
// 2. 调用WPGJ支付提交API获取支付链接
WpgjPayOrderSubmitReqVO submitReqVO = new WpgjPayOrderSubmitReqVO();
submitReqVO.setId(wpgjOrderId);
AppPayOrderSubmitRespVO submitRespVO = payOrderApi.submitWpgjOrder(submitReqVO);
log.info("[createCommonWpgjOrder] WPGJ支付提交成功,业务类型: {}, 业务订单ID: {}, WPGJ订单ID: {}, 支付状态: {}",
createReqDTO.getBusinessType(), createReqDTO.getBusinessOrderId(), wpgjOrderId, submitRespVO.getStatus());
// 3. 构建返回数据 - 包含支付链接
CommonWpgjPayOrderSubmitRespVO respVO = new CommonWpgjPayOrderSubmitRespVO();
respVO.setWpgjOrderId(wpgjOrderId); // 返回WPGJ订单ID,用于前端轮询
respVO.setStatus(ObjectUtil.toString(submitRespVO.getStatus()));
respVO.setDisplayMode(submitRespVO.getDisplayMode());
respVO.setDisplayContent(submitRespVO.getDisplayContent()); // 支付链接
log.info("[createCommonWpgjOrder] 通用WPGJ支付订单创建完成,业务类型: {}, 业务订单ID: {}, WPGJ订单ID: {}, 支付链接: {}",
createReqDTO.getBusinessType(), createReqDTO.getBusinessOrderId(), wpgjOrderId, submitRespVO.getDisplayContent());
return respVO;
} catch (Exception e) {
log.error("[createCommonWpgjOrder] 创建通用WPGJ支付订单失败", e);
throw new ServiceException("创建支付订单失败: " + e.getMessage());
}
}
}
\ No newline at end of file
...@@ -175,7 +175,8 @@ computility: ...@@ -175,7 +175,8 @@ computility:
mer-code: K20241200111267 mer-code: K20241200111267
term-code: 1011215692596 term-code: 1011215692596
api-url: https://stg5-qr.wpgjcs.com/industrial/payment/dynamic api-url: https://stg5-qr.wpgjcs.com/industrial/payment/dynamic
notify-url: https://phslgld.hnluchuan.com/admin-api/compute/wpgj/new-notify notify-url-compute: https://phslgld.hnluchuan.com/admin-api/compute/wpgj/notify # 算力资源模块WPGJ回调地址
notify-url-api: https://phslgld.hnluchuan.com/admin-api/apihub/wpgj/notify # APIHub模块WPGJ回调地址
sign-key: 07714583f82b4db8b675b32cd5e0969743 # WPGJ回调签名密钥(测试用,实际需要向WPGJ确认) sign-key: 07714583f82b4db8b675b32cd5e0969743 # WPGJ回调签名密钥(测试用,实际需要向WPGJ确认)
public-key: | public-key: |
-----BEGIN PUBLIC KEY----- -----BEGIN PUBLIC KEY-----
......
...@@ -281,7 +281,8 @@ computility: ...@@ -281,7 +281,8 @@ computility:
- /admin-api/infra/file/preview - /admin-api/infra/file/preview
- /app-api/infra/file/preview - /app-api/infra/file/preview
- /open-api/external/** - /open-api/external/**
- /admin-api/compute/wpgj/new-notify - /admin-api/compute/wpgj/notify
- /admin-api/apihub/wpgj/notify
ignore-visit-urls: ignore-visit-urls:
- /admin-api/system/user/profile/** - /admin-api/system/user/profile/**
- /admin-api/system/auth/** - /admin-api/system/auth/**
......
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