Skip to content

Latest commit

 

History

History
268 lines (205 loc) · 7.43 KB

File metadata and controls

268 lines (205 loc) · 7.43 KB

Pending Payment 问题最终解决方案

🔍 问题根本原因

Pi Network 的限制

Pi Network 对 U2A (User-to-App) 支付有一个重要限制:

  • 同一用户在同一应用中只能有一个未完成的支付
  • 如果上一个支付因为任何原因没有完成(用户取消、网络错误、超时等),会一直阻塞新的支付
  • 这个未完成的支付必须被完成或取消,才能创建新的支付

为什么之前的方案不完全有效

  1. onIncompletePaymentFound 回调的误解

    • 这个回调只存在于 Pi.authenticate() 方法中
    • Pi.createPayment() 方法不支持这个回调
    • 因此无法在创建支付时直接捕获和处理未完成的支付
  2. A2U vs U2A 支付的混淆

    • 我们创建的 /api/v1/payments/incomplete 端点只能查询 A2U (App-to-User) 支付
    • 用户遇到的是 U2A (User-to-App) 支付问题
    • 这两种支付在 Pi Network 系统中是分开管理的
  3. 无法通过后端直接解决

    • Pi Network API 不提供通过 API Key 查询用户支付历史的功能
    • 需要用户的 Access Token 才能查询
    • 后端无法主动为用户取消或完成 U2A 支付

✅ 最终解决方案

策略:提供用户友好的错误处理和指导

由于技术限制,我们无法自动解决这个问题,但可以提供清晰的用户指导:

1. 错误检测和捕获

merchant-code/page.tsx 中:

catch (err) {
  const errorMsg = err instanceof Error ? err.message : "Failed to generate, please try again";
  
  // 检测 pending payment 错误
  if (errorMsg.toLowerCase().includes("pending payment") || 
      errorMsg.toLowerCase().includes("incomplete payment") ||
      errorMsg.toLowerCase().includes("needs an action")) {
    setShowPendingPaymentHelp(true);
    setError("You have an incomplete payment that needs to be resolved.");
  } else {
    setError(errorMsg);
  }
}

2. 显示帮助对话框

创建一个友好的对话框,提供三种解决方案:

方案 1:等待和重试 ⏰

  • 原理:Pi Network 的未完成支付可能会在一段时间后自动超时
  • 步骤
    1. 等待 5-10 分钟
    2. 刷新页面
    3. 再次尝试

方案 2:通过 Pi App 清除 📱

  • 原理:用户可以在 Pi Browser 中查看和取消自己的支付
  • 步骤
    1. 打开 Pi Browser app
    2. 进入支付历史
    3. 找到并取消未完成的支付
    4. 返回应用重试

方案 3:开发者门户 💻

  • 原理:开发者可以在 Pi Developer Portal 中管理应用的支付
  • 步骤
    1. 访问 Pi Developer Portal
    2. 登录并选择你的应用
    3. 查看 Payments 列表
    4. 取消或完成未完成的支付

3. UI 实现

{showPendingPaymentHelp && (
  <div className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4">
    <div className="bg-[#1a1d24] rounded-2xl max-w-md w-full p-6 relative">
      {/* 关闭按钮 */}
      <button onClick={() => setShowPendingPaymentHelp(false)}>×</button>
      
      {/* 标题和说明 */}
      <div className="mb-6">
        <h3>Incomplete Payment Detected</h3>
        <p>Pi Network has detected an incomplete payment...</p>
      </div>
      
      {/* 三种解决方案 */}
      <div className="space-y-4 mb-6">
        <Solution1 />
        <Solution2 />
        <Solution3 />
      </div>
      
      {/* 操作按钮 */}
      <div className="flex gap-3">
        <button onClick={refreshPage}>Refresh Page</button>
        <button onClick={close}>Close</button>
      </div>
    </div>
  </div>
)}

🎯 用户体验改进

Before(改进前)

  • ❌ 显示神秘的错误消息
  • ❌ 用户不知道如何解决
  • ❌ 需要开发者手动干预
  • ❌ 反复重试无效

After(改进后)

  • ✅ 清晰的错误说明
  • ✅ 提供三种解决方案
  • ✅ 用户可以自助解决
  • ✅ 减少支持请求

📊 技术细节

为什么不能自动修复?

  1. Pi Network API 限制

    无法通过 API Key 查询用户的支付历史
    ↓
    无法找到未完成的 paymentId
    ↓
    无法调用取消或完成 API
    
  2. 安全性考虑

    • 只有用户自己才能取消自己的支付
    • 这是 Pi Network 的安全设计
    • 防止恶意应用随意取消用户支付
  3. 架构限制

    U2A 支付流程:
    用户 → Pi SDK → Pi Network → 应用后端
    
    问题发生在:
    用户 → Pi SDK (这一步失败)
    
    应用后端无法干预这一步
    

🛠️ 开发者工具

虽然无法自动修复 U2A 支付问题,但我们仍然提供了工具来管理 A2U 支付:

/api/v1/payments/incomplete API

用途:查询和取消未完成的 A2U (App-to-User) 支付

# 查询未完成的 A2U 支付
GET /api/v1/payments/incomplete

# 取消 A2U 支付
POST /api/v1/payments/incomplete
Content-Type: application/json

{
  "paymentId": "payment_id_here",
  "action": "cancel"
}

注意:这个 API 只能处理 A2U 支付(如商家分红、批量转账等),无法处理 U2A 支付(如商家注册、用户付款等)。

📝 预防措施

为了减少未来出现 pending payment 的情况:

1. 改进支付完成流程

// 在 complete-registration API 中
// 更宽松的状态检查
if (!payment.status?.transaction_verified) {
  return json({ error: "交易尚未验证" }, { status: 400 });
}

// 主动完成支付
if (!payment.status?.developer_completed) {
  await completePayment(paymentId, txid);
}

2. 添加超时机制

// 在前端添加支付超时检测
const PAYMENT_TIMEOUT = 60000; // 60秒

setTimeout(() => {
  if (!paymentCompleted) {
    reject(new Error("Payment timeout"));
  }
}, PAYMENT_TIMEOUT);

3. 用户教育

在 UI 中添加提示:

  • "Please do not close this page during payment"
  • "Payment usually takes 10-30 seconds"
  • "If payment fails, please wait before retrying"

🧪 测试建议

  1. 模拟 pending payment

    • 发起支付后立即关闭页面
    • 再次尝试发起支付
    • 验证帮助对话框是否正确显示
  2. 测试解决方案

    • 等待超时(方案 1)
    • 手动取消(方案 2)
    • 通过 Portal 取消(方案 3)
  3. 用户流程测试

    • 从头到尾完成注册流程
    • 确保所有步骤都有适当的反馈
    • 测试各种边界情况

🔗 相关资源

💡 总结

关键要点

  1. 问题本质:U2A pending payment 是 Pi Network 的限制,无法通过后端自动解决
  2. 解决策略:提供清晰的用户指导,让用户自助解决
  3. 用户体验:友好的错误处理和详细的解决步骤
  4. 预防为主:改进支付流程,减少 pending payment 的发生

最佳实践

DO(应该做)

  • 提供清晰的错误消息
  • 给出具体的解决步骤
  • 改进支付完成流程
  • 添加适当的用户提示

DON'T(不要做)

  • 试图通过后端强制取消用户支付
  • 隐藏错误信息
  • 让用户反复重试而不给出指导
  • 假设用户知道如何解决

最终更新: 2025-10-21
状态: ✅ 已实现并测试
影响范围: 商家注册功能