chore: 恢复PAYMENT系列文件
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -126,7 +126,10 @@ backend/cmd/server/server
|
|||||||
deploy/docker-compose.override.yml
|
deploy/docker-compose.override.yml
|
||||||
.gocache/
|
.gocache/
|
||||||
vite.config.js
|
vite.config.js
|
||||||
docs/
|
docs/*
|
||||||
|
!docs/PAYMENT.md
|
||||||
|
!docs/PAYMENT_CN.md
|
||||||
|
!docs/ADMIN_PAYMENT_INTEGRATION_API.md
|
||||||
.serena/
|
.serena/
|
||||||
.codex/
|
.codex/
|
||||||
frontend/coverage/
|
frontend/coverage/
|
||||||
|
|||||||
243
docs/ADMIN_PAYMENT_INTEGRATION_API.md
Normal file
243
docs/ADMIN_PAYMENT_INTEGRATION_API.md
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
# ADMIN_PAYMENT_INTEGRATION_API
|
||||||
|
|
||||||
|
> 单文件中英双语文档 / Single-file bilingual documentation (Chinese + English)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 中文
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
本文档用于对接外部支付系统(如 `sub2apipay`)与 Sub2API 的 Admin API,覆盖:
|
||||||
|
- 支付成功后充值
|
||||||
|
- 用户查询
|
||||||
|
- 人工余额修正
|
||||||
|
- 前端购买页参数透传
|
||||||
|
|
||||||
|
### 基础地址
|
||||||
|
- 生产:`https://<your-domain>`
|
||||||
|
- Beta:`http://<your-server-ip>:8084`
|
||||||
|
|
||||||
|
### 认证
|
||||||
|
推荐使用:
|
||||||
|
- `x-api-key: admin-<64hex>`
|
||||||
|
- `Content-Type: application/json`
|
||||||
|
- 幂等接口额外传:`Idempotency-Key`
|
||||||
|
|
||||||
|
说明:管理员 JWT 也可访问 admin 路由,但服务间调用建议使用 Admin API Key。
|
||||||
|
|
||||||
|
### 1) 一步完成创建并兑换
|
||||||
|
`POST /api/v1/admin/redeem-codes/create-and-redeem`
|
||||||
|
|
||||||
|
用途:原子完成“创建兑换码 + 兑换到指定用户”。
|
||||||
|
|
||||||
|
请求头:
|
||||||
|
- `x-api-key`
|
||||||
|
- `Idempotency-Key`
|
||||||
|
|
||||||
|
请求体示例:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": "s2p_cm1234567890",
|
||||||
|
"type": "balance",
|
||||||
|
"value": 100.0,
|
||||||
|
"user_id": 123,
|
||||||
|
"notes": "sub2apipay order: cm1234567890"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
幂等语义:
|
||||||
|
- 同 `code` 且 `used_by` 一致:`200`
|
||||||
|
- 同 `code` 但 `used_by` 不一致:`409`
|
||||||
|
- 缺少 `Idempotency-Key`:`400`(`IDEMPOTENCY_KEY_REQUIRED`)
|
||||||
|
|
||||||
|
curl 示例:
|
||||||
|
```bash
|
||||||
|
curl -X POST "${BASE}/api/v1/admin/redeem-codes/create-and-redeem" \
|
||||||
|
-H "x-api-key: ${KEY}" \
|
||||||
|
-H "Idempotency-Key: pay-cm1234567890-success" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"code":"s2p_cm1234567890",
|
||||||
|
"type":"balance",
|
||||||
|
"value":100.00,
|
||||||
|
"user_id":123,
|
||||||
|
"notes":"sub2apipay order: cm1234567890"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2) 查询用户(可选前置校验)
|
||||||
|
`GET /api/v1/admin/users/:id`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s "${BASE}/api/v1/admin/users/123" \
|
||||||
|
-H "x-api-key: ${KEY}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3) 余额调整(已有接口)
|
||||||
|
`POST /api/v1/admin/users/:id/balance`
|
||||||
|
|
||||||
|
用途:人工补偿 / 扣减,支持 `set` / `add` / `subtract`。
|
||||||
|
|
||||||
|
请求体示例(扣减):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"balance": 100.0,
|
||||||
|
"operation": "subtract",
|
||||||
|
"notes": "manual correction"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "${BASE}/api/v1/admin/users/123/balance" \
|
||||||
|
-H "x-api-key: ${KEY}" \
|
||||||
|
-H "Idempotency-Key: balance-subtract-cm1234567890" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"balance":100.00,
|
||||||
|
"operation":"subtract",
|
||||||
|
"notes":"manual correction"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4) 购买页 / 自定义页面 URL Query 透传(iframe / 新窗口一致)
|
||||||
|
当 Sub2API 打开 `purchase_subscription_url` 或用户侧自定义页面 iframe URL 时,会统一追加:
|
||||||
|
- `user_id`
|
||||||
|
- `token`
|
||||||
|
- `theme`(`light` / `dark`)
|
||||||
|
- `lang`(例如 `zh` / `en`,用于向嵌入页传递当前界面语言)
|
||||||
|
- `ui_mode`(固定 `embedded`)
|
||||||
|
|
||||||
|
示例:
|
||||||
|
```text
|
||||||
|
https://pay.example.com/pay?user_id=123&token=<jwt>&theme=light&lang=zh&ui_mode=embedded
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5) 失败处理建议
|
||||||
|
- 支付成功与充值成功分状态落库
|
||||||
|
- 回调验签成功后立即标记“支付成功”
|
||||||
|
- 支付成功但充值失败的订单允许后续重试
|
||||||
|
- 重试保持相同 `code`,并使用新的 `Idempotency-Key`
|
||||||
|
|
||||||
|
### 6) `doc_url` 配置建议
|
||||||
|
- 查看链接:`https://github.com/Wei-Shaw/sub2api/blob/main/ADMIN_PAYMENT_INTEGRATION_API.md`
|
||||||
|
- 下载链接:`https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/ADMIN_PAYMENT_INTEGRATION_API.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## English
|
||||||
|
|
||||||
|
### Purpose
|
||||||
|
This document describes the minimal Sub2API Admin API surface for external payment integrations (for example, `sub2apipay`), including:
|
||||||
|
- Recharge after payment success
|
||||||
|
- User lookup
|
||||||
|
- Manual balance correction
|
||||||
|
- Purchase page query parameter forwarding
|
||||||
|
|
||||||
|
### Base URL
|
||||||
|
- Production: `https://<your-domain>`
|
||||||
|
- Beta: `http://<your-server-ip>:8084`
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
Recommended headers:
|
||||||
|
- `x-api-key: admin-<64hex>`
|
||||||
|
- `Content-Type: application/json`
|
||||||
|
- `Idempotency-Key` for idempotent endpoints
|
||||||
|
|
||||||
|
Note: Admin JWT can also access admin routes, but Admin API Key is recommended for server-to-server integration.
|
||||||
|
|
||||||
|
### 1) Create and Redeem in one step
|
||||||
|
`POST /api/v1/admin/redeem-codes/create-and-redeem`
|
||||||
|
|
||||||
|
Use case: atomically create a redeem code and redeem it to a target user.
|
||||||
|
|
||||||
|
Headers:
|
||||||
|
- `x-api-key`
|
||||||
|
- `Idempotency-Key`
|
||||||
|
|
||||||
|
Request body:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": "s2p_cm1234567890",
|
||||||
|
"type": "balance",
|
||||||
|
"value": 100.0,
|
||||||
|
"user_id": 123,
|
||||||
|
"notes": "sub2apipay order: cm1234567890"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Idempotency behavior:
|
||||||
|
- Same `code` and same `used_by`: `200`
|
||||||
|
- Same `code` but different `used_by`: `409`
|
||||||
|
- Missing `Idempotency-Key`: `400` (`IDEMPOTENCY_KEY_REQUIRED`)
|
||||||
|
|
||||||
|
curl example:
|
||||||
|
```bash
|
||||||
|
curl -X POST "${BASE}/api/v1/admin/redeem-codes/create-and-redeem" \
|
||||||
|
-H "x-api-key: ${KEY}" \
|
||||||
|
-H "Idempotency-Key: pay-cm1234567890-success" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"code":"s2p_cm1234567890",
|
||||||
|
"type":"balance",
|
||||||
|
"value":100.00,
|
||||||
|
"user_id":123,
|
||||||
|
"notes":"sub2apipay order: cm1234567890"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2) Query User (optional pre-check)
|
||||||
|
`GET /api/v1/admin/users/:id`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s "${BASE}/api/v1/admin/users/123" \
|
||||||
|
-H "x-api-key: ${KEY}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3) Balance Adjustment (existing API)
|
||||||
|
`POST /api/v1/admin/users/:id/balance`
|
||||||
|
|
||||||
|
Use case: manual correction with `set` / `add` / `subtract`.
|
||||||
|
|
||||||
|
Request body example (`subtract`):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"balance": 100.0,
|
||||||
|
"operation": "subtract",
|
||||||
|
"notes": "manual correction"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "${BASE}/api/v1/admin/users/123/balance" \
|
||||||
|
-H "x-api-key: ${KEY}" \
|
||||||
|
-H "Idempotency-Key: balance-subtract-cm1234567890" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"balance":100.00,
|
||||||
|
"operation":"subtract",
|
||||||
|
"notes":"manual correction"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4) Purchase / Custom Page URL query forwarding (iframe and new tab)
|
||||||
|
When Sub2API opens `purchase_subscription_url` or a user-facing custom page iframe URL, it appends:
|
||||||
|
- `user_id`
|
||||||
|
- `token`
|
||||||
|
- `theme` (`light` / `dark`)
|
||||||
|
- `lang` (for example `zh` / `en`, used to pass the current UI language to the embedded page)
|
||||||
|
- `ui_mode` (fixed: `embedded`)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```text
|
||||||
|
https://pay.example.com/pay?user_id=123&token=<jwt>&theme=light&lang=zh&ui_mode=embedded
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5) Failure handling recommendations
|
||||||
|
- Persist payment success and recharge success as separate states
|
||||||
|
- Mark payment as successful immediately after verified callback
|
||||||
|
- Allow retry for orders with payment success but recharge failure
|
||||||
|
- Keep the same `code` for retry, and use a new `Idempotency-Key`
|
||||||
|
|
||||||
|
### 6) Recommended `doc_url`
|
||||||
|
- View URL: `https://github.com/Wei-Shaw/sub2api/blob/main/ADMIN_PAYMENT_INTEGRATION_API.md`
|
||||||
|
- Download URL: `https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/ADMIN_PAYMENT_INTEGRATION_API.md`
|
||||||
287
docs/PAYMENT.md
Normal file
287
docs/PAYMENT.md
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
# Payment System Configuration Guide
|
||||||
|
|
||||||
|
Sub2API has a built-in payment system that enables user self-service top-up without deploying a separate payment service.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Supported Payment Methods](#supported-payment-methods)
|
||||||
|
- [Quick Start](#quick-start)
|
||||||
|
- [System Settings](#system-settings)
|
||||||
|
- [Provider Configuration](#provider-configuration)
|
||||||
|
- [Provider Instance Management](#provider-instance-management)
|
||||||
|
- [Webhook Configuration](#webhook-configuration)
|
||||||
|
- [Payment Flow](#payment-flow)
|
||||||
|
- [Migrating from Sub2ApiPay](#migrating-from-sub2apipay)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Supported Payment Methods
|
||||||
|
|
||||||
|
| Provider | Payment Methods | Description |
|
||||||
|
|----------|----------------|-------------|
|
||||||
|
| **EasyPay** | Alipay, WeChat Pay | Third-party aggregation via EasyPay protocol |
|
||||||
|
| **Alipay (Direct)** | Desktop QR code, mobile Alipay redirect | Direct integration with Alipay Open Platform, returning desktop QR codes and mobile WAP/app launch links |
|
||||||
|
| **WeChat Pay (Direct)** | Native QR, H5, MP/JSAPI Pay | Direct integration with WeChat Pay APIv3 with environment-aware routing |
|
||||||
|
| **Stripe** | Card, Alipay, WeChat Pay, Link, etc. | International payments, multi-currency support |
|
||||||
|
|
||||||
|
> Alipay/WeChat Pay direct and EasyPay can both exist as backend provider instances, but the frontend always exposes only two visible buttons: `Alipay` and `WeChat Pay`. Admins choose exactly one source for each visible method: direct or EasyPay. Direct channels connect to payment APIs directly with lower fees; EasyPay aggregates through third-party platforms with easier setup.
|
||||||
|
|
||||||
|
> **EasyPay Provider Recommendations**: Both options below are third-party aggregators compatible with the EasyPay protocol. Pick based on the funding channel and settlement currency you need:
|
||||||
|
>
|
||||||
|
> - **Domestic channel / CNY settlement** — [ZPay](https://z-pay.cn/?uid=23808) (`https://z-pay.cn/?uid=23808`): direct integration with official Alipay / WeChat Pay APIs, fee **1.6%**; funds go straight to the merchant account with **T+1 automatic settlement**. Supports **individual users** (no business license required) with up to 10,000 CNY daily transactions; business-licensed accounts have no limit. Link contains the referral code of [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) original author [@touwaeriol](https://github.com/touwaeriol) — feel free to remove it.
|
||||||
|
> - **International channel / USDT or USD settlement** — [Kyren Topup](https://kyren.top/?code=SUB2API) (`https://kyren.top/?code=SUB2API`): a ready-to-launch global payment stack for AI startups with WeChat Pay and Alipay support, local-currency checkout, and USD settlement. Fees: WeChat 2%, Alipay 2.5%; withdrawal 0.1% (min $40, max $150), settled in **USDT or USD**. No qualification review required — sign up and use immediately, making it the lowest barrier to entry. Withdrawal threshold is relatively high, recommended for users **who do not use domestic Chinese payment channels, cannot tolerate Stripe's 6%+ fees, have high transaction volume, and have USD or USDT channels to receive withdrawn funds**. Kyren Topup charges a $200 account opening fee; signing up via this link (which contains Sub2Api author [@Wei-Shaw](https://github.com/Wei-Shaw)'s referral code) **waives the opening fee**. Feel free to remove it if you prefer.
|
||||||
|
>
|
||||||
|
> Please evaluate the security, reliability, and compliance of any third-party payment provider on your own — this project does not endorse or guarantee any of them.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
1. Go to Admin Dashboard → **Settings** → **Payment Settings** tab
|
||||||
|
2. Enable **Payment**
|
||||||
|
3. Configure basic parameters (amount range, timeout, etc.)
|
||||||
|
4. Add at least one provider instance in **Provider Management**
|
||||||
|
5. Users can now top up from the frontend
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## System Settings
|
||||||
|
|
||||||
|
Configure the following in Admin Dashboard **Settings → Payment Settings**:
|
||||||
|
|
||||||
|
### Basic Settings
|
||||||
|
|
||||||
|
| Setting | Description | Default |
|
||||||
|
|---------|-------------|---------|
|
||||||
|
| **Enable Payment** | Enable or disable the payment system | Off |
|
||||||
|
| **Product Name Prefix** | Prefix shown on payment page | - |
|
||||||
|
| **Product Name Suffix** | Suffix (e.g., "Credits") | - |
|
||||||
|
| **Minimum Amount** | Minimum single top-up amount | 1 |
|
||||||
|
| **Maximum Amount** | Maximum single top-up amount (empty = unlimited) | - |
|
||||||
|
| **Daily Limit** | Per-user daily cumulative limit (empty = unlimited) | - |
|
||||||
|
| **Order Timeout** | Order timeout in minutes (minimum 1) | 30 |
|
||||||
|
| **Max Pending Orders** | Maximum concurrent pending orders per user | 3 |
|
||||||
|
| **Load Balance Strategy** | Strategy for selecting provider instances | Round Robin |
|
||||||
|
|
||||||
|
### Frontend Visible Method Routing
|
||||||
|
|
||||||
|
The current payment UX keeps the frontend method list unified and does not expose provider brands directly:
|
||||||
|
|
||||||
|
- **Alipay**: when enabled, this button must be routed to either `Alipay (Direct)` or `EasyPay Alipay`
|
||||||
|
- **WeChat Pay**: when enabled, this button must be routed to either `WeChat Pay (Direct)` or `EasyPay WeChat`
|
||||||
|
- Each visible method can route to only one source at a time
|
||||||
|
- If a visible method is enabled without a selected source, the frontend will not expose that method
|
||||||
|
|
||||||
|
### Load Balance Strategies
|
||||||
|
|
||||||
|
| Strategy | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| **Round Robin** | Distribute orders to instances in rotation |
|
||||||
|
| **Least Amount** | Prefer instances with the lowest daily cumulative amount |
|
||||||
|
|
||||||
|
### Cancel Rate Limiting
|
||||||
|
|
||||||
|
Prevents users from repeatedly creating and canceling orders:
|
||||||
|
|
||||||
|
| Setting | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| **Enable Limit** | Toggle |
|
||||||
|
| **Window Mode** | Sliding / Fixed window |
|
||||||
|
| **Time Window** | Window duration |
|
||||||
|
| **Window Unit** | Minutes / Hours |
|
||||||
|
| **Max Cancels** | Maximum cancellations allowed within the window |
|
||||||
|
|
||||||
|
### Help Information
|
||||||
|
|
||||||
|
| Setting | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| **Help Image** | Customer service QR code or help image (supports upload) |
|
||||||
|
| **Help Text** | Instructions displayed on the payment page |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Provider Configuration
|
||||||
|
|
||||||
|
Each provider type requires different credentials. Select the type when adding a new provider instance in **Provider Management → Add Provider**.
|
||||||
|
|
||||||
|
> **Callback URLs are auto-generated**: When adding a provider, the Notify URL and Return URL are automatically constructed from your site domain. You only need to confirm the domain is correct.
|
||||||
|
|
||||||
|
### EasyPay
|
||||||
|
|
||||||
|
Compatible with any payment service that implements the EasyPay protocol.
|
||||||
|
|
||||||
|
| Parameter | Description | Required |
|
||||||
|
|-----------|-------------|----------|
|
||||||
|
| **Merchant ID (PID)** | EasyPay merchant ID | Yes |
|
||||||
|
| **Merchant Key (PKey)** | EasyPay merchant secret key | Yes |
|
||||||
|
| **API Base URL** | EasyPay API base address | Yes |
|
||||||
|
| **Alipay Channel ID** | Specify Alipay channel (optional) | No |
|
||||||
|
| **WeChat Channel ID** | Specify WeChat channel (optional) | No |
|
||||||
|
|
||||||
|
### Alipay (Direct)
|
||||||
|
|
||||||
|
Direct integration with Alipay Open Platform. Desktop flows return a QR code for in-page display, while mobile flows return an Alipay WAP/app redirect URL.
|
||||||
|
|
||||||
|
| Parameter | Description | Required |
|
||||||
|
|-----------|-------------|----------|
|
||||||
|
| **AppID** | Alipay application AppID | Yes |
|
||||||
|
| **Private Key** | RSA2 application private key | Yes |
|
||||||
|
| **Alipay Public Key** | Alipay public key | Yes |
|
||||||
|
|
||||||
|
### WeChat Pay (Direct)
|
||||||
|
|
||||||
|
Direct integration with WeChat Pay APIv3. Supports Native QR code payment, H5 payment, and MP/JSAPI payment inside the WeChat environment.
|
||||||
|
|
||||||
|
| Parameter | Description | Required |
|
||||||
|
|-----------|-------------|----------|
|
||||||
|
| **AppID** | WeChat Pay AppID | Yes |
|
||||||
|
| **Merchant ID (MchID)** | WeChat Pay merchant ID | Yes |
|
||||||
|
| **Merchant API Private Key** | Merchant API private key (PEM format) | Yes |
|
||||||
|
| **APIv3 Key** | 32-byte APIv3 key | Yes |
|
||||||
|
| **WeChat Pay Public Key** | WeChat Pay public key (PEM format) | Yes |
|
||||||
|
| **WeChat Pay Public Key ID** | WeChat Pay public key ID | Yes |
|
||||||
|
| **Certificate Serial Number** | Merchant certificate serial number | Yes |
|
||||||
|
|
||||||
|
### Stripe
|
||||||
|
|
||||||
|
International payment platform supporting multiple payment methods and currencies.
|
||||||
|
|
||||||
|
| Parameter | Description | Required |
|
||||||
|
|-----------|-------------|----------|
|
||||||
|
| **Secret Key** | Stripe secret key (`sk_live_...` or `sk_test_...`) | Yes |
|
||||||
|
| **Publishable Key** | Stripe publishable key (`pk_live_...` or `pk_test_...`) | Yes |
|
||||||
|
| **Webhook Secret** | Stripe Webhook signing secret (`whsec_...`) | Yes |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Provider Instance Management
|
||||||
|
|
||||||
|
You can create **multiple instances** of the same provider type for load balancing and risk control:
|
||||||
|
|
||||||
|
- **Multi-instance load balancing** — Distribute orders via round-robin or least-amount strategy
|
||||||
|
- **Independent limits** — Each instance can have its own min/max amount and daily limit
|
||||||
|
- **Independent toggle** — Enable/disable individual instances without affecting others
|
||||||
|
- **Refund control** — Enable or disable refunds per instance
|
||||||
|
- **Payment methods** — Each instance can support a subset of payment methods
|
||||||
|
- **Ordering** — Drag to reorder instances
|
||||||
|
|
||||||
|
### Instance Limit Configuration
|
||||||
|
|
||||||
|
Each instance supports these limits:
|
||||||
|
|
||||||
|
| Limit | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| **Minimum Amount** | Minimum order amount accepted by this instance |
|
||||||
|
| **Maximum Amount** | Maximum order amount accepted by this instance |
|
||||||
|
| **Daily Limit** | Daily cumulative transaction limit for this instance |
|
||||||
|
|
||||||
|
> During load balancing, instances that exceed their limits are automatically skipped.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Webhook Configuration
|
||||||
|
|
||||||
|
Payment callbacks are essential for the payment system to work correctly.
|
||||||
|
|
||||||
|
### Callback URL Format
|
||||||
|
|
||||||
|
When adding a provider, the system auto-generates callback URLs from your site domain:
|
||||||
|
|
||||||
|
| Provider | Callback Path |
|
||||||
|
|----------|-------------|
|
||||||
|
| **EasyPay** | `https://your-domain.com/api/v1/payment/webhook/easypay` |
|
||||||
|
| **Alipay (Direct)** | `https://your-domain.com/api/v1/payment/webhook/alipay` |
|
||||||
|
| **WeChat Pay (Direct)** | `https://your-domain.com/api/v1/payment/webhook/wxpay` |
|
||||||
|
| **Stripe** | `https://your-domain.com/api/v1/payment/webhook/stripe` |
|
||||||
|
|
||||||
|
> Replace `your-domain.com` with your actual domain. For EasyPay / Alipay / WeChat Pay, the callback URL is auto-filled when adding the provider — no manual configuration needed.
|
||||||
|
|
||||||
|
### Stripe Webhook Setup
|
||||||
|
|
||||||
|
1. Log in to [Stripe Dashboard](https://dashboard.stripe.com/)
|
||||||
|
2. Go to **Developers → Webhooks**
|
||||||
|
3. Add an endpoint with the callback URL
|
||||||
|
4. Subscribe to events: `payment_intent.succeeded`, `payment_intent.payment_failed`
|
||||||
|
5. Copy the generated Webhook Secret (`whsec_...`) to your provider configuration
|
||||||
|
|
||||||
|
### Important Notes
|
||||||
|
|
||||||
|
- Callback URLs must use **HTTPS** (required by Stripe, strongly recommended for others)
|
||||||
|
- Ensure your firewall allows callback requests from payment platforms
|
||||||
|
- The system automatically verifies callback signatures to prevent forgery
|
||||||
|
- Balance top-up is processed automatically upon successful payment — no manual intervention needed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Payment Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
User selects amount and payment method
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Create Order (PENDING)
|
||||||
|
├─ Validate amount range, pending order count, daily limit
|
||||||
|
├─ Load balance to select provider instance
|
||||||
|
└─ Call provider to get payment info
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
User completes payment
|
||||||
|
├─ EasyPay → QR code / H5 redirect
|
||||||
|
├─ Alipay → Desktop QR / mobile Alipay redirect
|
||||||
|
├─ WeChat Pay → Desktop Native QR / non-WeChat H5 / in-WeChat JSAPI
|
||||||
|
└─ Stripe → Payment Element (card/Alipay/WeChat/etc.)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Webhook callback verified → Order PAID
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Auto top-up to user balance → Order COMPLETED
|
||||||
|
```
|
||||||
|
|
||||||
|
### Order Status Reference
|
||||||
|
|
||||||
|
| Status | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| `PENDING` | Waiting for user to complete payment |
|
||||||
|
| `PAID` | Payment confirmed, awaiting balance credit |
|
||||||
|
| `COMPLETED` | Balance credited successfully |
|
||||||
|
| `EXPIRED` | Timed out without payment |
|
||||||
|
| `CANCELLED` | Cancelled by user |
|
||||||
|
| `FAILED` | Balance credit failed, admin can retry |
|
||||||
|
| `REFUND_REQUESTED` | Refund requested |
|
||||||
|
| `REFUNDING` | Refund in progress |
|
||||||
|
| `REFUNDED` | Refund completed |
|
||||||
|
|
||||||
|
### Timeout and Fallback
|
||||||
|
|
||||||
|
- Before marking an order as expired, the background job queries the upstream payment status first
|
||||||
|
- If the user has actually paid but the callback was delayed, the system will reconcile automatically
|
||||||
|
- The background job runs every 60 seconds to check for timed-out orders
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migrating from Sub2ApiPay
|
||||||
|
|
||||||
|
If you previously used [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) as an external payment system, you can migrate to the built-in payment system:
|
||||||
|
|
||||||
|
### Key Differences
|
||||||
|
|
||||||
|
| Aspect | Sub2ApiPay | Built-in Payment |
|
||||||
|
|--------|-----------|-----------------|
|
||||||
|
| Deployment | Separate service (Next.js + PostgreSQL) | Built into Sub2API, no extra deployment |
|
||||||
|
| Payment Methods | EasyPay, Alipay, WeChat, Stripe | Same |
|
||||||
|
| Configuration | Environment variables + separate admin UI | Unified in Sub2API admin dashboard |
|
||||||
|
| Top-up Integration | Via Admin API callback | Internal processing, more reliable |
|
||||||
|
| Subscription Plans | Supported | Not yet (planned) |
|
||||||
|
| Order Management | Separate admin interface | Integrated in Sub2API admin dashboard |
|
||||||
|
|
||||||
|
### Migration Steps
|
||||||
|
|
||||||
|
1. Enable payment in Sub2API admin dashboard and configure providers (use the same payment credentials)
|
||||||
|
2. Update webhook callback URLs to Sub2API's callback endpoints
|
||||||
|
3. Verify that new orders are processed correctly via built-in payment
|
||||||
|
4. Decommission the Sub2ApiPay service
|
||||||
|
|
||||||
|
> **Note**: Historical order data from Sub2ApiPay will not be automatically migrated. Keep Sub2ApiPay running for a while to access historical records.
|
||||||
287
docs/PAYMENT_CN.md
Normal file
287
docs/PAYMENT_CN.md
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
# 支付系统配置指南
|
||||||
|
|
||||||
|
Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支付服务。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [支持的支付方式](#支持的支付方式)
|
||||||
|
- [快速开始](#快速开始)
|
||||||
|
- [系统设置](#系统设置)
|
||||||
|
- [服务商配置](#服务商配置)
|
||||||
|
- [服务商实例管理](#服务商实例管理)
|
||||||
|
- [Webhook 配置](#webhook-配置)
|
||||||
|
- [支付流程](#支付流程)
|
||||||
|
- [从 Sub2ApiPay 迁移](#从-sub2apipay-迁移)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 支持的支付方式
|
||||||
|
|
||||||
|
| 服务商 | 支付方式 | 说明 |
|
||||||
|
|--------|---------|------|
|
||||||
|
| **EasyPay(易支付)** | 支付宝、微信支付 | 兼容易支付协议的第三方聚合支付 |
|
||||||
|
| **支付宝官方** | 桌面二维码扫码、移动端支付宝跳转 | 直接对接支付宝开放平台,桌面端返回二维码,移动端返回 WAP/唤起链接 |
|
||||||
|
| **微信官方** | Native 扫码、H5、公众号/JSAPI 支付 | 直接对接微信支付 APIv3,按终端环境自动分流 |
|
||||||
|
| **Stripe** | 银行卡、支付宝、微信支付、Link 等 | 国际支付,支持多币种 |
|
||||||
|
|
||||||
|
> 支付宝官方 / 微信官方与易支付可以同时作为后台服务商实例存在,但前台始终只展示 `支付宝`、`微信支付` 两个可见按钮。管理员需要分别为这两个按钮选择唯一支付来源:官方或易支付。官方渠道直接对接 API,资金直达商户账户,手续费更低;易支付通过第三方平台聚合,接入门槛更低。
|
||||||
|
|
||||||
|
> **易支付服务商推荐**:以下两家均为兼容易支付协议的第三方聚合支付,按资金通道与结算方式选择:
|
||||||
|
>
|
||||||
|
> - **国内渠道 / 人民币结算** — [ZPay](https://z-pay.cn/?uid=23808)(`https://z-pay.cn/?uid=23808`):支付宝 / 微信官方 API 直连,手续费 **1.6%**;资金直达商家账户,**T+1 自动到账**。支持**个人用户**(无营业执照)每日 1 万元以内交易;拥有营业执照则无限额。链接含 [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) 原作者 [@touwaeriol](https://github.com/touwaeriol) 的邀请码,介意可去掉。
|
||||||
|
> - **国际渠道 / USDT 或美元结算** — [启润支付](https://kyren.top/?code=SUB2API)(`https://kyren.top/?code=SUB2API`):为 AI 项目提供低门槛国际收款通道,支持国际版微信支付与支付宝,本地货币支付、美元结算。手续费:微信 2%、支付宝 2.5%;提现 0.1%(最低 40 美元、最高 150 美元),以 **USDT 或美元**到账。无资质审核、注册即用,使用门槛最低;提现门槛略高,适合**不使用国内支付渠道、无法接受 Stripe 高达 6%+ 手续费、流水较大,且拥有美元或 USDT 渠道可接收提现资金**的用户。启润支付开户费 200 美元,通过本链接注册(含 Sub2Api 作者 [@Wei-Shaw](https://github.com/Wei-Shaw) 邀请码)可**免开户费**,介意可去掉。
|
||||||
|
>
|
||||||
|
> 支付渠道的安全性、稳定性及合规性请自行鉴别,本项目不对任何第三方支付服务商做担保或背书。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
1. 进入管理后台 → **设置** → **支付设置** 标签页
|
||||||
|
2. 开启 **启用支付**
|
||||||
|
3. 配置基本参数(金额范围、超时时间等)
|
||||||
|
4. 在 **服务商管理** 中添加至少一个服务商实例
|
||||||
|
5. 用户即可在前端页面进行充值
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 系统设置
|
||||||
|
|
||||||
|
在管理后台 **设置 → 支付设置** 中配置以下参数:
|
||||||
|
|
||||||
|
### 基本设置
|
||||||
|
|
||||||
|
| 设置项 | 说明 | 默认值 |
|
||||||
|
|--------|------|--------|
|
||||||
|
| **启用支付** | 启用或禁用支付系统 | 关闭 |
|
||||||
|
| **商品名前缀** | 支付页面显示的商品名前缀 | - |
|
||||||
|
| **商品名后缀** | 商品名后缀(如"元") | - |
|
||||||
|
| **最低金额** | 单笔最低充值金额 | 1 |
|
||||||
|
| **最高金额** | 单笔最高充值金额(留空表示不限制) | - |
|
||||||
|
| **每日限额** | 每用户每日累计充值上限(留空表示不限制) | - |
|
||||||
|
| **订单超时时间** | 订单超时分钟数,至少 1 分钟 | 30 |
|
||||||
|
| **最大待支付订单数** | 同一用户最大并行待支付订单数 | 3 |
|
||||||
|
| **负载均衡策略** | 多服务商实例时的选择策略 | 轮询 |
|
||||||
|
|
||||||
|
### 前台可见支付方式路由
|
||||||
|
|
||||||
|
当前版本对用户统一展示支付方式,不区分官方渠道还是易支付:
|
||||||
|
|
||||||
|
- **支付宝**:后台启用后,需要额外指定该按钮路由到 `支付宝官方` 或 `易支付支付宝`
|
||||||
|
- **微信支付**:后台启用后,需要额外指定该按钮路由到 `微信官方` 或 `易支付微信`
|
||||||
|
- 同一个可见支付方式在同一时刻只能路由到一个来源
|
||||||
|
- 支付来源未选择时,即使对应按钮被开启,前台也不会暴露该支付方式
|
||||||
|
|
||||||
|
### 负载均衡策略
|
||||||
|
|
||||||
|
| 策略 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| **轮询(round-robin)** | 按顺序轮流分配到各服务商实例 |
|
||||||
|
| **最少金额(least-amount)** | 优先分配到当日累计金额最少的实例 |
|
||||||
|
|
||||||
|
### 取消频率限制
|
||||||
|
|
||||||
|
防止用户频繁创建并取消订单:
|
||||||
|
|
||||||
|
| 设置项 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| **启用限制** | 开关 |
|
||||||
|
| **窗口模式** | 滚动窗口 / 固定窗口 |
|
||||||
|
| **时间窗口** | 窗口长度 |
|
||||||
|
| **窗口单位** | 分钟 / 小时 |
|
||||||
|
| **最大次数** | 窗口内允许的最大取消次数 |
|
||||||
|
|
||||||
|
### 帮助信息
|
||||||
|
|
||||||
|
| 设置项 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| **帮助图片** | 充值页面显示的客服二维码等图片(支持上传) |
|
||||||
|
| **帮助文本** | 充值页面显示的说明文字 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 服务商配置
|
||||||
|
|
||||||
|
每种服务商需要不同的凭证和参数。在 **服务商管理 → 添加服务商** 中选择类型后填写。
|
||||||
|
|
||||||
|
> **回调地址自动生成**:添加服务商时,异步回调地址(Notify URL)和同步跳转地址(Return URL)由系统根据你的站点域名自动拼接,无需手动填写。管理员只需确认域名正确即可。
|
||||||
|
|
||||||
|
### EasyPay(易支付)
|
||||||
|
|
||||||
|
兼容任何 EasyPay 协议的支付服务商。
|
||||||
|
|
||||||
|
| 参数 | 说明 | 必填 |
|
||||||
|
|------|------|------|
|
||||||
|
| **商户 ID(PID)** | EasyPay 商户 ID | 是 |
|
||||||
|
| **商户密钥(PKey)** | EasyPay 商户密钥 | 是 |
|
||||||
|
| **API 地址** | EasyPay API 基础地址 | 是 |
|
||||||
|
| **支付宝通道 ID** | 指定支付宝通道(可选) | 否 |
|
||||||
|
| **微信通道 ID** | 指定微信通道(可选) | 否 |
|
||||||
|
|
||||||
|
### 支付宝官方
|
||||||
|
|
||||||
|
直接对接支付宝开放平台。桌面端返回二维码供页面内展示和扫码,移动端返回支付宝手机网站支付跳转链接。
|
||||||
|
|
||||||
|
| 参数 | 说明 | 必填 |
|
||||||
|
|------|------|------|
|
||||||
|
| **AppID** | 支付宝应用 AppID | 是 |
|
||||||
|
| **应用私钥** | RSA2 应用私钥 | 是 |
|
||||||
|
| **支付宝公钥** | 支付宝公钥 | 是 |
|
||||||
|
|
||||||
|
### 微信官方
|
||||||
|
|
||||||
|
直接对接微信支付 APIv3,支持 Native 扫码支付、H5 支付,以及在微信环境内的公众号/JSAPI 支付。
|
||||||
|
|
||||||
|
| 参数 | 说明 | 必填 |
|
||||||
|
|------|------|------|
|
||||||
|
| **AppID** | 微信支付 AppID | 是 |
|
||||||
|
| **商户号(MchID)** | 微信支付商户号 | 是 |
|
||||||
|
| **商户 API 私钥** | 商户 API 私钥(PEM 格式) | 是 |
|
||||||
|
| **APIv3 密钥** | 32 位 APIv3 密钥 | 是 |
|
||||||
|
| **微信支付公钥** | 微信支付公钥(PEM 格式) | 是 |
|
||||||
|
| **微信支付公钥 ID** | 微信支付公钥 ID | 是 |
|
||||||
|
| **商户证书序列号** | 商户证书序列号 | 是 |
|
||||||
|
|
||||||
|
### Stripe
|
||||||
|
|
||||||
|
国际支付平台,支持多种支付方式和币种。
|
||||||
|
|
||||||
|
| 参数 | 说明 | 必填 |
|
||||||
|
|------|------|------|
|
||||||
|
| **Secret Key** | Stripe 密钥(`sk_live_...` 或 `sk_test_...`) | 是 |
|
||||||
|
| **Publishable Key** | Stripe 可公开密钥(`pk_live_...` 或 `pk_test_...`) | 是 |
|
||||||
|
| **Webhook Secret** | Stripe Webhook 签名密钥(`whsec_...`) | 是 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 服务商实例管理
|
||||||
|
|
||||||
|
同一种服务商可以创建**多个实例**,实现负载均衡和风控:
|
||||||
|
|
||||||
|
- **多实例负载均衡** — 按轮询或最少金额策略分流订单
|
||||||
|
- **独立限额** — 每个实例可独立配置单笔最小/最大金额和每日限额
|
||||||
|
- **独立启停** — 可单独启用/禁用某个实例,不影响其他实例
|
||||||
|
- **退款控制** — 每个实例可单独开启或关闭退款功能
|
||||||
|
- **支付方式** — 每个实例可选择支持的支付方式子集
|
||||||
|
- **排序** — 拖拽调整实例顺序
|
||||||
|
|
||||||
|
### 实例限额配置
|
||||||
|
|
||||||
|
每个实例支持以下限额:
|
||||||
|
|
||||||
|
| 限额项 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| **单笔最小金额** | 该实例接受的最小订单金额 |
|
||||||
|
| **单笔最大金额** | 该实例接受的最大订单金额 |
|
||||||
|
| **每日限额** | 该实例每日累计交易上限 |
|
||||||
|
|
||||||
|
> 负载均衡时,系统会自动跳过超出限额的实例。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Webhook 配置
|
||||||
|
|
||||||
|
支付回调是支付系统的核心环节,必须正确配置:
|
||||||
|
|
||||||
|
### 回调地址格式
|
||||||
|
|
||||||
|
添加服务商时,系统会自动根据站点域名拼接回调地址,格式如下:
|
||||||
|
|
||||||
|
| 服务商 | 回调路径 |
|
||||||
|
|--------|---------|
|
||||||
|
| **EasyPay** | `https://your-domain.com/api/v1/payment/webhook/easypay` |
|
||||||
|
| **支付宝官方** | `https://your-domain.com/api/v1/payment/webhook/alipay` |
|
||||||
|
| **微信官方** | `https://your-domain.com/api/v1/payment/webhook/wxpay` |
|
||||||
|
| **Stripe** | `https://your-domain.com/api/v1/payment/webhook/stripe` |
|
||||||
|
|
||||||
|
> 将 `your-domain.com` 替换为你的实际域名。EasyPay / 支付宝 / 微信的回调地址在添加服务商时自动填入,无需手动配置。
|
||||||
|
|
||||||
|
### Stripe Webhook 设置
|
||||||
|
|
||||||
|
1. 登录 [Stripe Dashboard](https://dashboard.stripe.com/)
|
||||||
|
2. 进入 **Developers → Webhooks**
|
||||||
|
3. 添加端点,填写回调地址
|
||||||
|
4. 订阅事件:`payment_intent.succeeded`、`payment_intent.payment_failed`
|
||||||
|
5. 将生成的 Webhook Secret(`whsec_...`)填入服务商配置
|
||||||
|
|
||||||
|
### 注意事项
|
||||||
|
|
||||||
|
- 回调地址必须是 **HTTPS**(Stripe 强制要求,其他服务商强烈推荐)
|
||||||
|
- 确保服务器防火墙允许支付平台的回调请求
|
||||||
|
- 系统会自动进行签名验证,防止伪造回调
|
||||||
|
- 支付成功后自动完成余额充值,无需人工干预
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 支付流程
|
||||||
|
|
||||||
|
```
|
||||||
|
用户选择充值金额和支付方式
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
创建订单 (PENDING)
|
||||||
|
├─ 校验金额范围、待支付订单数、每日限额
|
||||||
|
├─ 负载均衡选择服务商实例
|
||||||
|
└─ 调用服务商获取支付信息
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
用户完成支付
|
||||||
|
├─ EasyPay → 扫码 / H5 跳转
|
||||||
|
├─ 支付宝官方 → 桌面二维码 / 移动端支付宝跳转
|
||||||
|
├─ 微信官方 → 桌面 Native 扫码 / 非微信 H5 / 微信内 JSAPI
|
||||||
|
└─ Stripe → Payment Element(银行卡/支付宝/微信等)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
支付回调验签 → 订单 PAID
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
自动充值到用户余额 → 订单 COMPLETED
|
||||||
|
```
|
||||||
|
|
||||||
|
### 订单状态说明
|
||||||
|
|
||||||
|
| 状态 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `PENDING` | 待支付,等待用户完成支付 |
|
||||||
|
| `PAID` | 已支付,等待充值到账 |
|
||||||
|
| `COMPLETED` | 已完成,余额已到账 |
|
||||||
|
| `EXPIRED` | 已过期,超时未支付 |
|
||||||
|
| `CANCELLED` | 已取消,用户主动取消 |
|
||||||
|
| `FAILED` | 充值失败,可管理员重试 |
|
||||||
|
| `REFUND_REQUESTED` | 已申请退款 |
|
||||||
|
| `REFUNDING` | 退款处理中 |
|
||||||
|
| `REFUNDED` | 已退款 |
|
||||||
|
|
||||||
|
### 超时与兜底
|
||||||
|
|
||||||
|
- 订单超时后,后台任务会先查询上游支付状态再标记过期
|
||||||
|
- 如果用户实际已支付但回调延迟,系统会通过查询补单
|
||||||
|
- 后台任务每 60 秒执行一次超时检查
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 从 Sub2ApiPay 迁移
|
||||||
|
|
||||||
|
如果你之前使用 [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) 作为外部支付系统,现在可以迁移到内置支付:
|
||||||
|
|
||||||
|
### 主要差异
|
||||||
|
|
||||||
|
| 对比项 | Sub2ApiPay | 内置支付 |
|
||||||
|
|--------|-----------|---------|
|
||||||
|
| 部署方式 | 独立服务(Next.js + PostgreSQL) | 内置于 Sub2API,无需额外部署 |
|
||||||
|
| 支付方式 | EasyPay、支付宝、微信、Stripe | 相同 |
|
||||||
|
| 配置方式 | 环境变量 + 独立管理后台 | Sub2API 管理后台内统一配置 |
|
||||||
|
| 充值对接 | 通过 Admin API 回调 | 内部直接处理,更可靠 |
|
||||||
|
| 订阅套餐 | 支持 | 暂不支持(计划中) |
|
||||||
|
| 订单管理 | 独立管理界面 | 集成在 Sub2API 管理后台 |
|
||||||
|
|
||||||
|
### 迁移步骤
|
||||||
|
|
||||||
|
1. 在 Sub2API 管理后台启用支付并配置服务商(使用相同的支付凭证)
|
||||||
|
2. 更新 Webhook 回调地址为 Sub2API 的回调地址
|
||||||
|
3. 确认新订单通过内置支付正常处理
|
||||||
|
4. 停用 Sub2ApiPay 服务
|
||||||
|
|
||||||
|
> **注意**:Sub2ApiPay 中的历史订单数据不会自动迁移。建议保留 Sub2ApiPay 一段时间以便查询历史记录。
|
||||||
@@ -4136,7 +4136,7 @@
|
|||||||
<p class="mt-2 text-xs text-gray-400 dark:text-gray-500">
|
<p class="mt-2 text-xs text-gray-400 dark:text-gray-500">
|
||||||
{{ t("admin.settings.payment.enabledPaymentTypesHint") }}
|
{{ t("admin.settings.payment.enabledPaymentTypesHint") }}
|
||||||
<a
|
<a
|
||||||
:href="paymentGuideHref"
|
:href="paymentMethodsHref"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="ml-1 text-primary-500 hover:text-primary-600 dark:text-primary-400 dark:hover:text-primary-300"
|
class="ml-1 text-primary-500 hover:text-primary-600 dark:text-primary-400 dark:hover:text-primary-300"
|
||||||
@@ -4723,8 +4723,14 @@ function localText(zh: string, en: string): string {
|
|||||||
|
|
||||||
const paymentGuideHref = computed(() =>
|
const paymentGuideHref = computed(() =>
|
||||||
locale.value.startsWith("zh")
|
locale.value.startsWith("zh")
|
||||||
? "https://github.com/Wei-Shaw/sub2api/blob/main/README_CN.md#%E6%94%AF%E4%BB%98"
|
? "https://github.com/Wei-Shaw/sub2api/blob/main/docs/PAYMENT_CN.md"
|
||||||
: "https://github.com/Wei-Shaw/sub2api/blob/main/README.md#payment",
|
: "https://github.com/Wei-Shaw/sub2api/blob/main/docs/PAYMENT.md",
|
||||||
|
);
|
||||||
|
|
||||||
|
const paymentMethodsHref = computed(() =>
|
||||||
|
locale.value.startsWith("zh")
|
||||||
|
? "https://github.com/Wei-Shaw/sub2api/blob/main/docs/PAYMENT_CN.md#支持的支付方式"
|
||||||
|
: "https://github.com/Wei-Shaw/sub2api/blob/main/docs/PAYMENT.md#supported-payment-methods",
|
||||||
);
|
);
|
||||||
|
|
||||||
type SettingsTab =
|
type SettingsTab =
|
||||||
|
|||||||
@@ -508,13 +508,13 @@ describe("admin SettingsView payment visible method controls", () => {
|
|||||||
|
|
||||||
expect(paymentLinks).toHaveLength(2);
|
expect(paymentLinks).toHaveLength(2);
|
||||||
expect(paymentLinks[0]?.attributes("href")).toBe(
|
expect(paymentLinks[0]?.attributes("href")).toBe(
|
||||||
"https://github.com/Wei-Shaw/sub2api/blob/main/README_CN.md#%E6%94%AF%E4%BB%98",
|
"https://github.com/Wei-Shaw/sub2api/blob/main/docs/PAYMENT_CN.md",
|
||||||
);
|
);
|
||||||
expect(paymentLinks[1]?.attributes("href")).toBe(
|
expect(paymentLinks[1]?.attributes("href")).toBe(
|
||||||
"https://github.com/Wei-Shaw/sub2api/blob/main/README_CN.md#%E6%94%AF%E4%BB%98",
|
"https://github.com/Wei-Shaw/sub2api/blob/main/docs/PAYMENT_CN.md#支持的支付方式",
|
||||||
);
|
);
|
||||||
for (const link of paymentLinks) {
|
for (const link of paymentLinks) {
|
||||||
expect(link.attributes("href")).not.toContain("docs/PAYMENT");
|
expect(link.attributes("href")).toContain("docs/PAYMENT");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user