Quellcode durchsuchen

🐛 fix(payment): 增强支付参数验证与错误处理

- 在支付页面添加路由参数安全解析,防止NaN值
- 改进获取支付参数API的错误响应处理,尝试解析JSON错误消息
- 在重试支付前增加订单ID和金额的验证
- 优化支付重试的错误处理逻辑,对特定错误消息进行用户友好转换
- 在支付服务中细化重复支付检查逻辑,区分已支付和已退款状态
- 更新集成测试以匹配新的错误消息

♻️ refactor(payment): 重构重复支付检查逻辑

- 将支付服务中的重复支付检查从笼统的"状态不正确"细化为具体状态检查
- 明确已支付(PAID)状态不允许重复支付
- 允许已退款(REFUNDED)状态的订单重新支付并删除旧记录
- 添加日志记录以跟踪支付记录状态变更
yourname vor 1 Monat
Ursprung
Commit
37e3248169

+ 34 - 5
mini/src/pages/payment/index.tsx

@@ -49,8 +49,8 @@ const PaymentPage = () => {
   // 使用useRouter钩子获取路由参数
   const router = useRouter()
   const routerParams = router.params
-  const orderId = routerParams?.orderId ? parseInt(routerParams.orderId) : 0
-  const amount = routerParams?.amount ? parseFloat(routerParams.amount) : 0
+  const orderId = routerParams?.orderId && !isNaN(parseInt(routerParams.orderId)) ? parseInt(routerParams.orderId) : 0
+  const amount = routerParams?.amount && !isNaN(parseFloat(routerParams.amount)) ? parseFloat(routerParams.amount) : 0
   const orderNo = routerParams?.orderNo
 
   // 获取用户额度信息
@@ -118,7 +118,16 @@ const PaymentPage = () => {
       })
 
       if (response.status !== 200) {
-        throw new Error(`获取支付参数失败: ${response.status}`)
+        let errorMessage = `获取支付参数失败: ${response.status}`
+        try {
+          const errorData = await response.json()
+          if (errorData.message) {
+            errorMessage = errorData.message
+          }
+        } catch {
+          // 忽略JSON解析错误,使用默认错误消息
+        }
+        throw new Error(errorMessage)
       }
 
       const responseData = await response.json()
@@ -282,7 +291,17 @@ const PaymentPage = () => {
       return
     }
 
-    if (!orderId) return
+    if (!orderId) {
+      setErrorMessage('订单ID无效')
+      return
+    }
+
+    if (!amount || amount <= 0) {
+      setErrorMessage('支付金额无效')
+      return
+    }
+
+    console.debug('重试支付开始,orderId:', orderId, 'amount:', amount)
 
     setIsProcessing(true)
     setErrorMessage('')
@@ -320,7 +339,17 @@ const PaymentPage = () => {
     } catch (error: any) {
       console.error('支付重试异常:', error)
       setPaymentStatus(PaymentStatus.FAILED)
-      setErrorMessage(error.message || '支付重试异常')
+
+      let errorMsg = error.message || '支付重试异常'
+      // 特定错误处理
+      if (errorMsg.includes('该订单已存在支付记录且状态不正确') || errorMsg.includes('该订单已支付成功,请勿重复支付')) {
+        errorMsg = '订单支付状态异常,请联系客服或稍后重试'
+      } else if (errorMsg.includes('参数错误')) {
+        errorMsg = '支付参数错误,请检查订单信息'
+      } else if (errorMsg.includes('用户OpenID不能为空')) {
+        errorMsg = '用户信息不完整,请重新登录'
+      }
+      setErrorMessage(errorMsg)
     } finally {
       setIsProcessing(false)
     }

+ 12 - 3
packages/mini-payment-mt/src/services/payment.mt.service.ts

@@ -126,11 +126,20 @@ export class PaymentMtService extends GenericCrudService<PaymentMtEntity> {
     });
 
     if (existingPayment) {
-      if (existingPayment.paymentStatus !== PaymentStatus.PENDING) {
-        throw new Error('该订单已存在支付记录且状态不正确');
+      // 如果支付记录状态是PAID(已支付),不允许重新支付
+      if (existingPayment.paymentStatus === PaymentStatus.PAID) {
+        throw new Error('该订单已支付成功,请勿重复支付');
       }
-      // 如果存在待支付的记录,可以更新或重新创建,这里选择重新创建
+
+      // 如果支付记录状态是REFUNDED(已退款),根据业务需求决定是否允许重新支付
+      // 这里暂时允许重新支付,删除旧记录
+      if (existingPayment.paymentStatus === PaymentStatus.REFUNDED) {
+        console.log(`租户${tenantId}订单${externalOrderId}存在已退款的支付记录,允许重新支付`);
+      }
+
+      // 删除旧支付记录,创建新的支付记录
       await paymentRepository.remove(existingPayment);
+      console.log(`删除租户${tenantId}订单${externalOrderId}的旧支付记录,状态: ${existingPayment.paymentStatus}`);
     }
 
     if (!openid) {

+ 1 - 1
packages/mini-payment-mt/tests/integration/payment.integration.test.ts

@@ -231,7 +231,7 @@ describe('支付API集成测试', () => {
       expect(response.status).toBe(500);
       if (response.status === 500) {
         const result = await response.json();
-        expect(result.message).toContain('该订单已存在支付记录且状态不正确');
+        expect(result.message).toContain('该订单已支付成功,请勿重复支付');
       }
     });
 

+ 12 - 3
packages/mini-payment/src/services/payment.service.ts

@@ -67,11 +67,20 @@ export class PaymentService {
     });
 
     if (existingPayment) {
-      if (existingPayment.paymentStatus !== PaymentStatus.PENDING) {
-        throw new Error('该订单已存在支付记录且状态不正确');
+      // 如果支付记录状态是PAID(已支付),不允许重新支付
+      if (existingPayment.paymentStatus === PaymentStatus.PAID) {
+        throw new Error('该订单已支付成功,请勿重复支付');
       }
-      // 如果存在待支付的记录,可以更新或重新创建,这里选择重新创建
+
+      // 如果支付记录状态是REFUNDED(已退款),根据业务需求决定是否允许重新支付
+      // 这里暂时允许重新支付,删除旧记录
+      if (existingPayment.paymentStatus === PaymentStatus.REFUNDED) {
+        console.log(`订单${externalOrderId}存在已退款的支付记录,允许重新支付`);
+      }
+
+      // 删除旧支付记录,创建新的支付记录
       await paymentRepository.remove(existingPayment);
+      console.log(`删除订单${externalOrderId}的旧支付记录,状态: ${existingPayment.paymentStatus}`);
     }
 
     if (!openid) {

+ 1 - 1
packages/mini-payment/tests/integration/payment.integration.test.ts

@@ -220,7 +220,7 @@ describe('支付API集成测试', () => {
       expect(response.status).toBe(500);
       if (response.status === 500) {
         const result = await response.json();
-        expect(result.message).toContain('该订单已存在支付记录且状态不正确');
+        expect(result.message).toContain('该订单已支付成功,请勿重复支付');
       }
     });