Explorar o código

fix(cfc-backend): PaymentService testMode mock + WeChat JSAPI payer.openid

Ultraworked with Sisyphus

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
User hai 2 meses
pai
achega
ae07ac454b

+ 29 - 14
cfc-backend/src/main/java/com/etotem/cfc/service/PaymentService.java

@@ -23,9 +23,7 @@ import javax.annotation.Resource;
 import javax.crypto.Cipher;
 import javax.crypto.spec.GCMParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.InputStreamReader;
+import java.io.*;
 import java.nio.charset.StandardCharsets;
 import java.security.KeyFactory;
 import java.security.MessageDigest;
@@ -97,15 +95,20 @@ public class PaymentService implements PaymentServiceInterface {
             return;
         }
         if (privateKeyPath != null && !privateKeyPath.isEmpty()) {
-            try (BufferedReader reader = new BufferedReader(new InputStreamReader(
-                    new FileInputStream(privateKeyPath), StandardCharsets.UTF_8))) {
-                String keyContent = reader.lines()
-                        .filter(line -> !line.startsWith("-----"))
-                        .collect(Collectors.joining());
-                byte[] keyBytes = Base64.getDecoder().decode(keyContent);
-                PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
-                KeyFactory kf = KeyFactory.getInstance("RSA");
-                privateKey = kf.generatePrivate(spec);
+            try (InputStream is = getClass().getClassLoader().getResourceAsStream(
+                    privateKeyPath.replace("\\", "/"))) {
+                if (is == null) {
+                    throw new FileNotFoundException("私钥文件未在classpath中找到: " + privateKeyPath);
+                }
+                try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
+                    String keyContent = reader.lines()
+                            .filter(line -> !line.startsWith("-----"))
+                            .collect(Collectors.joining());
+                    byte[] keyBytes = Base64.getDecoder().decode(keyContent);
+                    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
+                    KeyFactory kf = KeyFactory.getInstance("RSA");
+                    privateKey = kf.generatePrivate(spec);
+                }
             } catch (Exception e) {
                 log.error("加载微信支付私钥失败: {}", e.getMessage());
             }
@@ -114,7 +117,7 @@ public class PaymentService implements PaymentServiceInterface {
 
     @Override
     public Map<String, Object> createWechatPayOrder(String orderNo, String description, Integer amount) {
-        return createWechatPrepay(orderNo, description, amount);
+        return createWechatPrepay(orderNo, description, amount, "");
     }
 
     @Override
@@ -161,7 +164,7 @@ public class PaymentService implements PaymentServiceInterface {
         return true;
     }
 
-    public Map<String, Object> createWechatPrepay(String orderNo, String description, Integer totalFee) {
+    public Map<String, Object> createWechatPrepay(String orderNo, String description, Integer totalFee, String openid) {
         try {
             JSONObject body = new JSONObject();
             body.put("appid", appid);
@@ -170,6 +173,10 @@ public class PaymentService implements PaymentServiceInterface {
             body.put("out_trade_no", orderNo);
             body.put("notify_url", notifyUrl);
 
+            JSONObject payer = new JSONObject();
+            payer.put("openid", openid);
+            body.put("payer", payer);
+
             JSONObject amount = new JSONObject();
             amount.put("total", totalFee);
             amount.put("currency", "CNY");
@@ -317,6 +324,10 @@ public class PaymentService implements PaymentServiceInterface {
     }
 
     private String doGet(String path) throws Exception {
+        if (testMode) {
+            log.info("【测试模式】跳过微信API请求: GET {}", path);
+            return "{\"code\":\"TEST\",\"message\":\"mock\"}";
+        }
         String url = WECHAT_API_BASE + path;
         String auth = buildAuthHeader("GET", path, "");
 
@@ -338,6 +349,10 @@ public class PaymentService implements PaymentServiceInterface {
     }
 
     private String doPost(String path, String body) throws Exception {
+        if (testMode) {
+            log.info("【测试模式】跳过微信API请求: POST {}", path);
+            return "{\"code\":\"TEST\",\"message\":\"mock\",\"prepay_id\":\"mock_prepay_id_" + System.currentTimeMillis() + "\"}";
+        }
         String url = WECHAT_API_BASE + path;
         String auth = buildAuthHeader("POST", path, body);
 

+ 5 - 1
cfc-backend/src/main/java/com/etotem/cfc/service/ProductOrderService.java

@@ -175,8 +175,12 @@ public class ProductOrderService {
         if (!"pending".equals(order.getStatus())) {
             return Result.error("订单状态异常");
         }
+        User user = userMapper.selectById(userId);
+        if (user == null || user.getOpenid() == null || user.getOpenid().isEmpty()) {
+            return Result.error("用户openid不存在,无法支付");
+        }
         Map<String, Object> wechatPayParams = paymentService.createWechatPrepay(
-                orderNo, order.getProductName(), order.getTotalAmount());
+                orderNo, order.getProductName(), order.getTotalAmount(), user.getOpenid());
         // Do NOT change status or deduct stock here — WeChat callback confirms payment
         Map<String, Object> result = new HashMap<>();
         result.put("wechatPayParams", wechatPayParams);