订单处理指南
本文档介绍如何管理 Vibany 平台的支付订单,包括订单查询、状态更新和退款处理。
订单系统概述
Vibany 的订单系统用于管理用户积分充值。支持支付宝、微信支付(易支付)和 Stripe 支付方式。
订单状态
| 状态 | 说明 | 触发条件 |
|---|---|---|
| PENDING | 待支付 | 订单创建后 |
| SUCCESS | 支付成功 | 收到支付回调且验证通过 |
| FAILED | 支付失败 | 支付超时或用户取消 |
| REFUND | 已退款 | 管理员手动退款 |
订单数据结构
// lib/db/schema.ts
orders {
id: string; // 订单 ID
userId: string; // 用户 ID
buyerId: string; // 购买者 ID
type: string; // "credit" 或 "debit"
amount: number; // 积分数量
status: OrderStatus; // 订单状态
paymentMethod: string; // 支付方式
outTradeNo: string; // 商户订单号
tradeNo: string; // 支付平台订单号
qrCodeUrl: string; // 支付二维码 URL
paidAt: Date; // 支付时间
refundedAt: Date; // 退款时间
extra: object; // 扩展信息
createdAt: Date; // 创建时间
}
查看订单
通过 Admin 后台
- 访问
/admin/orders - 查看所有订单列表
- 支持筛选(按状态、支付方式、时间)
- 支持搜索(按订单号、用户邮箱)
通过数据库查询
-- 查看最近订单
SELECT * FROM orders
ORDER BY created_at DESC
LIMIT 20;
-- 查看特定用户订单
SELECT * FROM orders
WHERE user_id = 'user_xxx'
ORDER BY created_at DESC;
-- 查看待支付订单
SELECT * FROM orders
WHERE status = 'PENDING'
AND created_at > NOW() - INTERVAL '24 hours';
-- 查看支付成功订单统计
SELECT
DATE(created_at) as date,
COUNT(*) as order_count,
SUM(amount) as total_points
FROM orders
WHERE status = 'SUCCESS'
GROUP BY DATE(created_at)
ORDER BY date DESC;
支付回调处理
易支付回调
回调地址:
POST https://yourdomain.com/api/public/epay/notify
处理流程:
- 接收回调数据
- 验证 RSA 签名
- 检查订单状态
- 更新订单为 SUCCESS
- 充值用户积分
- 处理邀请奖励(如果有)
Stripe Webhook
回调地址:
POST https://yourdomain.com/api/public/stripe/notify
监听事件:
checkout.session.completedcheckout.session.async_payment_succeeded
本地测试:
stripe listen --forward-to localhost:3000/api/public/stripe/notify
手动处理订单
标记订单为已支付
当支付回调未能正常处理时,可能需要手动标记订单:
-- 更新订单状态
UPDATE orders
SET
status = 'SUCCESS',
paid_at = NOW(),
trade_no = 'manual_fix_xxx'
WHERE id = 'order_xxx';
-- 充值积分(需要同时执行)
UPDATE wallets
SET permanent_points = permanent_points + (SELECT amount FROM orders WHERE id = 'order_xxx')
WHERE user_id = (SELECT user_id FROM orders WHERE id = 'order_xxx');
退款处理
通过 Admin 后台:
- 找到订单
- 点击 "退款"
- 确认退款金额
- 系统会自动扣除用户积分并标记订单为 REFUND
通过 API:
// 处理退款
await processRefund({
orderId: 'order_xxx',
reason: '用户要求退款',
adminId: 'admin_xxx'
});
数据库操作:
-- 标记订单为已退款
UPDATE orders
SET
status = 'REFUND',
refunded_at = NOW()
WHERE id = 'order_xxx';
-- 扣除用户积分
UPDATE wallets
SET permanent_points = permanent_points - (SELECT amount FROM orders WHERE id = 'order_xxx')
WHERE user_id = (SELECT user_id FROM orders WHERE id = 'order_xxx');
订单统计
收入统计
-- 每日收入统计
SELECT
DATE(created_at) as date,
COUNT(*) as order_count,
SUM(amount) as total_points,
payment_method,
COUNT(CASE WHEN status = 'SUCCESS' THEN 1 END) as success_count
FROM orders
WHERE status = 'SUCCESS'
GROUP BY DATE(created_at), payment_method
ORDER BY date DESC;
-- 月度汇总
SELECT
DATE_TRUNC('month', created_at) as month,
COUNT(*) as total_orders,
SUM(CASE WHEN status = 'SUCCESS' THEN amount ELSE 0 END) as revenue_points
FROM orders
GROUP BY DATE_TRUNC('month', created_at)
ORDER BY month DESC;
支付方式分析
SELECT
payment_method,
COUNT(*) as order_count,
SUM(amount) as total_amount,
AVG(amount) as avg_amount
FROM orders
WHERE status = 'SUCCESS'
GROUP BY payment_method;
常见问题
订单状态不同步
症状:用户已支付但订单仍显示 PENDING
排查步骤:
- 检查支付平台是否发送了回调
- 查看服务器日志中的回调处理记录
- 验证回调签名是否正确
- 检查数据库连接是否正常
解决方案:
- 手动查询支付平台确认支付状态
- 手动更新订单状态
- 检查并修复回调配置
重复支付
原因:用户多次点击支付按钮
处理:
// 检查订单是否已处理
if (order.status === 'SUCCESS') {
return { message: 'Order already processed' };
}
支付回调失败
检查清单:
- 回调 URL 可访问
- HTTPS 证书有效
- 服务器防火墙允许外部访问
- 请求体未被修改(Nginx 配置)
Stripe Webhook 验证失败
解决方案:
- 确认
STRIPE_WEBHOOK_SECRET正确 - 检查请求体是否原样传递
- 使用
stripe listen本地测试
对账流程
每日对账
-
导出平台数据:
- 从易支付后台导出当日交易
- 从 Stripe Dashboard 导出交易
-
对比系统数据:
SELECT out_trade_no, amount, status, created_at FROM orders WHERE DATE(created_at) = CURRENT_DATE - 1 ORDER BY created_at; -
处理差异:
- 平台有但系统无:手动补单
- 系统有但平台无:检查是否为测试数据
最佳实践
- 幂等性:确保同一笔支付不会被重复处理
- 日志记录:所有支付操作都要有详细日志
- 监控告警:设置订单异常监控
- 定期对账:每日/每周进行对账
- 备份数据:定期备份订单数据