156 lines
5.5 KiB
TypeScript
156 lines
5.5 KiB
TypeScript
/**
|
||
* 支付宝回调通知 API
|
||
* 基于 Universal_Payment_Module v4.0 设计
|
||
*
|
||
* POST /api/payment/alipay/notify
|
||
*/
|
||
|
||
import { type NextRequest, NextResponse } from "next/server"
|
||
import { PaymentFactory, SignatureError } from "@/lib/payment"
|
||
import { query } from "@/lib/db"
|
||
|
||
// 确保网关已注册
|
||
import "@/lib/payment/alipay"
|
||
|
||
export async function POST(request: NextRequest) {
|
||
try {
|
||
// 获取表单数据
|
||
const formData = await request.formData()
|
||
const params: Record<string, string> = {}
|
||
|
||
formData.forEach((value, key) => {
|
||
params[key] = value.toString()
|
||
})
|
||
|
||
console.log("[Alipay Notify] 收到回调:", {
|
||
out_trade_no: params.out_trade_no,
|
||
trade_status: params.trade_status,
|
||
total_amount: params.total_amount,
|
||
})
|
||
|
||
// 创建支付宝网关
|
||
const gateway = PaymentFactory.create("alipay_wap")
|
||
|
||
try {
|
||
// 解析并验证回调数据
|
||
const notifyResult = gateway.parseNotify(params)
|
||
|
||
if (notifyResult.status === "paid") {
|
||
console.log("[Alipay Notify] 支付成功:", {
|
||
tradeSn: notifyResult.tradeSn,
|
||
platformSn: notifyResult.platformSn,
|
||
amount: notifyResult.payAmount / 100, // 转换为元
|
||
payTime: notifyResult.payTime,
|
||
})
|
||
|
||
// === ✅ 1. 更新订单状态 ===
|
||
try {
|
||
// 通过 transaction_id 查找订单
|
||
const orderRows = await query(`
|
||
SELECT id, user_id, amount, product_type, product_id
|
||
FROM orders
|
||
WHERE transaction_id = ? AND status = 'created'
|
||
LIMIT 1
|
||
`, [notifyResult.tradeSn]) as any[]
|
||
|
||
if (orderRows.length === 0) {
|
||
console.error('[Alipay Notify] ❌ 订单不存在或已处理:', notifyResult.tradeSn)
|
||
} else {
|
||
const order = orderRows[0]
|
||
const orderId = order.id
|
||
const userId = order.user_id
|
||
const amount = parseFloat(order.amount)
|
||
const productType = order.product_type
|
||
const productId = order.product_id
|
||
|
||
// 更新订单状态为已支付
|
||
await query(`
|
||
UPDATE orders
|
||
SET status = 'paid',
|
||
pay_time = ?,
|
||
updated_at = NOW()
|
||
WHERE id = ?
|
||
`, [notifyResult.payTime, orderId])
|
||
|
||
console.log('[Alipay Notify] ✅ 订单状态已更新:', { orderId, status: 'paid' })
|
||
|
||
// === ✅ 2. 解锁内容/开通权限 ===
|
||
if (productType === 'fullbook') {
|
||
// 购买全书
|
||
await query('UPDATE users SET has_full_book = 1 WHERE id = ?', [userId])
|
||
console.log('[Alipay Notify] ✅ 全书权限已开通:', userId)
|
||
} else if (productType === 'section' && productId) {
|
||
// 购买单个章节
|
||
console.log('[Alipay Notify] ✅ 章节权限已开通:', { userId, sectionId: productId })
|
||
}
|
||
|
||
// === ✅ 3. 分配佣金(如果有推荐人) ===
|
||
try {
|
||
// 查询用户的推荐人
|
||
const userRows = await query(`
|
||
SELECT u.id, u.referred_by, rb.referrer_id, rb.status
|
||
FROM users u
|
||
LEFT JOIN referral_bindings rb ON rb.referee_id = u.id AND rb.status = 'active' AND rb.expiry_date > NOW()
|
||
WHERE u.id = ?
|
||
LIMIT 1
|
||
`, [userId]) as any[]
|
||
|
||
if (userRows.length > 0 && userRows[0].referrer_id) {
|
||
const referrerId = userRows[0].referrer_id
|
||
const commissionRate = 0.9 // 90% 佣金比例
|
||
const commissionAmount = parseFloat((amount * commissionRate).toFixed(2))
|
||
|
||
// 更新推荐人的 pending_earnings
|
||
await query(`
|
||
UPDATE users
|
||
SET pending_earnings = pending_earnings + ?
|
||
WHERE id = ?
|
||
`, [commissionAmount, referrerId])
|
||
|
||
// 更新绑定状态为已转化
|
||
await query(`
|
||
UPDATE referral_bindings
|
||
SET status = 'converted',
|
||
conversion_date = NOW(),
|
||
commission_amount = ?
|
||
WHERE referee_id = ? AND status = 'active'
|
||
`, [commissionAmount, userId])
|
||
|
||
console.log('[Alipay Notify] ✅ 佣金已分配:', {
|
||
referrerId,
|
||
commissionAmount,
|
||
orderId
|
||
})
|
||
} else {
|
||
console.log('[Alipay Notify] ℹ️ 该用户无推荐人,无需分配佣金')
|
||
}
|
||
} catch (commErr) {
|
||
console.error('[Alipay Notify] ❌ 分配佣金失败:', commErr)
|
||
// 不中断主流程
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('[Alipay Notify] ❌ 订单处理失败:', error)
|
||
// 不中断,继续返回成功响应给支付宝(避免重复回调)
|
||
}
|
||
} else {
|
||
console.log("[Alipay Notify] 非支付成功状态:", notifyResult.status)
|
||
}
|
||
|
||
// 返回成功响应
|
||
return new NextResponse(gateway.successResponse())
|
||
|
||
} catch (error) {
|
||
if (error instanceof SignatureError) {
|
||
console.error("[Alipay Notify] 签名验证失败")
|
||
return new NextResponse(gateway.failResponse())
|
||
}
|
||
throw error
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error("[Alipay Notify] 处理失败:", error)
|
||
return new NextResponse("fail")
|
||
}
|
||
}
|