Bladeren bron

fix: 新增微信支付分 /pay 接口,修复退款 404 的问题

支付分退款接口 /pay/refund 是 /pay 的子资源,必须先调用 /pay 发起
支付扣款,该资源才会存在。之前只调用了 /complete 完结服务但未调用
/pay 扣款,导致退款时微信返回 404。

修改内容:
- PayScoreStrategy 新增 payServiceOrder 方法
- WxPayScoreStrategy 实现 /pay 接口调用
- PayScoreService/PayScoreServiceImpl 新增 payPayScoreOrder
- refundPayScoreOrder 退款前先调 /pay 确保支付资源存在

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 2 weken geleden
bovenliggende
commit
311d2132b8

+ 9 - 0
haha-service/src/main/java/com/haha/service/payment/payscore/PayScoreService.java

@@ -89,6 +89,15 @@ public interface PayScoreService {
      */
     PayScoreResult syncPayScoreStatus(Long orderId);
 
+    /**
+     * 发起支付扣款(调用微信支付分 /pay 接口)
+     * 在服务完结后调用,触发实际扣款,成功后退款接口才可用
+     *
+     * @param orderId 本地订单ID
+     * @return 支付扣款结果
+     */
+    PayScoreResult payPayScoreOrder(Long orderId);
+
     /**
      * 创建支付分服务订单(含权限校验)
      *

+ 6 - 0
haha-service/src/main/java/com/haha/service/payment/payscore/PayScoreStrategy.java

@@ -44,6 +44,12 @@ public interface PayScoreStrategy {
      */
     PayScoreResult syncServiceOrder(PayScoreSyncRequest request);
 
+    /**
+     * 发起支付扣款(创单结单)
+     * 在服务完结后调用,触发微信支付分扣款,成功后 /pay/refund 才能使用
+     */
+    PayScoreResult payServiceOrder(String outOrderNo);
+
     /**
      * 申请退款
      */

+ 38 - 0
haha-service/src/main/java/com/haha/service/payment/payscore/impl/PayScoreServiceImpl.java

@@ -381,6 +381,35 @@ public class PayScoreServiceImpl implements PayScoreService {
         return result;
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public PayScoreResult payPayScoreOrder(Long orderId) {
+        log.info("[支付分服务] 发起支付扣款 - orderId: {}", orderId);
+
+        PayScoreResult checkResult = checkServiceAvailable();
+        if (checkResult != null) {
+            return checkResult;
+        }
+
+        Order order = validateAndGetOrder(orderId);
+
+        if (order.getPayScoreOrderId() == null) {
+            return PayScoreResult.fail("ORDER_NOT_CREATED", "该订单未创建支付分服务订单");
+        }
+
+        // 调用微信支付分 /pay 接口发起扣款
+        PayScoreResult result = payScoreStrategy.payServiceOrder(order.getPayScoreOrderId());
+
+        if (result.isSuccess()) {
+            log.info("[支付分服务] 支付扣款成功 - orderId: {}, outOrderNo: {}", orderId, order.getPayScoreOrderId());
+        } else {
+            log.error("[支付分服务] 支付扣款失败 - orderId: {}, errorCode: {}, errorMsg: {}",
+                    orderId, result.getErrorCode(), result.getErrorMsg());
+        }
+
+        return result;
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public PayScoreResult modifyPayScoreOrder(Long orderId, BigDecimal totalAmount,
@@ -496,6 +525,15 @@ public class PayScoreServiceImpl implements PayScoreService {
         BigDecimal actualRefundAmount = refundAmount != null ? refundAmount
                 : (order.getPaidAmount() != null ? order.getPaidAmount() : order.getTotalAmount());
 
+        // 先调用 /pay 接口确保支付资源存在,否则 /pay/refund 会返回 404
+        log.info("[支付分服务] 退款前先确保支付已发起 - orderId: {}", orderId);
+        PayScoreResult payResult = payScoreStrategy.payServiceOrder(order.getPayScoreOrderId());
+        if (!payResult.isSuccess()) {
+            // /pay 失败可能是已经扣款成功,记录日志后继续尝试退款
+            log.warn("[支付分服务] /pay 调用未成功(可能已自动扣款),继续尝试退款: code={}, msg={}",
+                    payResult.getErrorCode(), payResult.getErrorMsg());
+        }
+
         PayScoreRefundRequest request = new PayScoreRefundRequest();
         request.setOutOrderNo(order.getPayScoreOrderId());
         request.setRefundAmount(actualRefundAmount);

+ 44 - 0
haha-service/src/main/java/com/haha/service/payment/payscore/impl/WxPayScoreStrategy.java

@@ -550,6 +550,50 @@ public class WxPayScoreStrategy implements PayScoreStrategy {
         }
     }
 
+    @Override
+    public PayScoreResult payServiceOrder(String outOrderNo) {
+        log.info("[微信支付分] 发起支付扣款 - 订单号: {}", outOrderNo);
+
+        PayScoreResult checkResult = checkServiceAvailable();
+        if (checkResult != null) {
+            return checkResult;
+        }
+
+        try {
+            ObjectNode body = objectMapper.createObjectNode();
+            body.put("appid", wxPayConfig.getAppId());
+            body.put("service_id", wxPayConfig.getServiceId());
+
+            String requestBody = objectMapper.writeValueAsString(body);
+            String url = PAY_SCORE_BASE_URL + "/" + outOrderNo + "/pay";
+            log.info("[微信支付分] 支付请求: url={}, body={}", url, requestBody);
+
+            HttpRequest httpRequest = new HttpRequest.Builder()
+                    .httpMethod(HttpMethod.POST)
+                    .url(url)
+                    .body(new JsonRequestBody.Builder().body(requestBody).build())
+                    .addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue())
+                    .addHeader("Accept", MediaType.APPLICATION_JSON.getValue())
+                    .build();
+
+            HttpResponse<Map> response = wxPayHttpClient.execute(httpRequest, Map.class);
+            Map<String, Object> responseMap = response.getServiceResponse();
+            JsonNode respJson = objectMapper.valueToTree(responseMap);
+
+            String respOrderNo = getJsonString(respJson, "out_order_no");
+            log.info("[微信支付分] 支付扣款成功 - 订单号: {}", respOrderNo);
+
+            return PayScoreResult.success(respOrderNo, null);
+
+        } catch (ServiceException e) {
+            log.error("[微信支付分] 支付扣款业务异常: code={}, msg={}", e.getErrorCode(), e.getErrorMessage(), e);
+            return PayScoreResult.fail(e.getErrorCode(), e.getErrorMessage());
+        } catch (Exception e) {
+            log.error("[微信支付分] 支付扣款异常", e);
+            return PayScoreResult.fail("UNKNOWN_ERROR", "支付扣款失败: " + e.getMessage());
+        }
+    }
+
     @Override
     public PayScoreResult refundServiceOrder(PayScoreRefundRequest request) {
         log.info("[微信支付分] 申请退款 - 订单号: {}, 金额: {}元", request.getOutOrderNo(), request.getRefundAmount());