175 lines
5.1 KiB
TypeScript
175 lines
5.1 KiB
TypeScript
/**
|
||
* 创建支付订单 API
|
||
* 基于 Universal_Payment_Module v4.0 设计
|
||
*
|
||
* POST /api/payment/create-order
|
||
*/
|
||
|
||
import { type NextRequest, NextResponse } from "next/server"
|
||
import {
|
||
PaymentFactory,
|
||
generateOrderSn,
|
||
generateTradeSn,
|
||
yuanToFen,
|
||
getNotifyUrl,
|
||
getReturnUrl,
|
||
} from "@/lib/payment"
|
||
import { query } from "@/lib/db"
|
||
|
||
// 确保网关已注册
|
||
import "@/lib/payment/alipay"
|
||
import "@/lib/payment/wechat"
|
||
|
||
export async function POST(request: NextRequest) {
|
||
try {
|
||
const body = await request.json()
|
||
const { userId, type, sectionId, sectionTitle, amount, paymentMethod, referralCode } = body
|
||
|
||
// 验证必要参数
|
||
if (!userId || !type || !amount || !paymentMethod) {
|
||
return NextResponse.json(
|
||
{ code: 400, message: "缺少必要参数", data: null },
|
||
{ status: 400 }
|
||
)
|
||
}
|
||
|
||
// 生成订单号
|
||
const orderSn = generateOrderSn()
|
||
const tradeSn = generateTradeSn()
|
||
|
||
// 创建订单对象
|
||
const order = {
|
||
orderSn,
|
||
tradeSn,
|
||
userId,
|
||
type, // "section" | "fullbook"
|
||
sectionId: type === "section" ? sectionId : undefined,
|
||
sectionTitle: type === "section" ? sectionTitle : undefined,
|
||
amount,
|
||
paymentMethod, // "wechat" | "alipay" | "usdt" | "paypal"
|
||
referralCode,
|
||
status: "created",
|
||
createdAt: new Date().toISOString(),
|
||
expireAt: new Date(Date.now() + 30 * 60 * 1000).toISOString(), // 30分钟
|
||
}
|
||
|
||
// === 💾 插入订单到数据库 ===
|
||
try {
|
||
// 获取用户 openId(如果有)
|
||
let openId = null
|
||
try {
|
||
const userRows = await query('SELECT open_id FROM users WHERE id = ?', [userId]) as any[]
|
||
if (userRows.length > 0) {
|
||
openId = userRows[0].open_id
|
||
}
|
||
} catch (e) {
|
||
console.warn('[Payment] 获取 openId 失败:', e)
|
||
}
|
||
|
||
const productType = type === 'section' ? 'section' : 'fullbook'
|
||
const productId = type === 'section' ? sectionId : 'fullbook'
|
||
const description = type === 'section'
|
||
? `购买章节: ${sectionTitle}`
|
||
: '购买整本书'
|
||
|
||
await query(`
|
||
INSERT INTO orders (
|
||
id, order_sn, user_id, open_id,
|
||
product_type, product_id, amount, description,
|
||
status, transaction_id, created_at, updated_at
|
||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||
`, [
|
||
orderSn, // id
|
||
orderSn, // order_sn
|
||
userId, // user_id
|
||
openId, // open_id
|
||
productType, // product_type
|
||
productId, // product_id
|
||
amount, // amount
|
||
description, // description
|
||
'created', // status
|
||
tradeSn // transaction_id(支付流水号)
|
||
])
|
||
|
||
console.log('[Payment] ✅ 订单已插入数据库:', { orderSn, userId, amount })
|
||
} catch (dbError) {
|
||
console.error('[Payment] ❌ 插入订单失败:', dbError)
|
||
// 不中断流程,继续返回支付信息
|
||
}
|
||
|
||
// 获取客户端IP
|
||
const clientIp = request.headers.get("x-forwarded-for")
|
||
|| request.headers.get("x-real-ip")
|
||
|| "127.0.0.1"
|
||
|
||
// 根据支付方式创建支付网关
|
||
let paymentData = null
|
||
const goodsTitle = type === "section" ? `购买章节: ${sectionTitle}` : "购买整本书"
|
||
|
||
// 确定网关类型
|
||
let gateway: string
|
||
if (paymentMethod === "alipay") {
|
||
gateway = "alipay_wap"
|
||
} else if (paymentMethod === "wechat") {
|
||
gateway = "wechat_native"
|
||
} else {
|
||
gateway = paymentMethod
|
||
}
|
||
|
||
try {
|
||
// 创建支付网关
|
||
const paymentGateway = PaymentFactory.create(gateway)
|
||
|
||
// 创建交易
|
||
const tradeResult = await paymentGateway.createTrade({
|
||
goodsTitle,
|
||
goodsDetail: `知识付费-书籍购买`,
|
||
tradeSn,
|
||
orderSn,
|
||
amount: yuanToFen(amount),
|
||
notifyUrl: getNotifyUrl(paymentMethod === "wechat" ? "wechat" : "alipay"),
|
||
returnUrl: getReturnUrl(orderSn),
|
||
createIp: clientIp.split(",")[0].trim(),
|
||
platformType: paymentMethod === "wechat" ? "native" : "wap",
|
||
})
|
||
|
||
paymentData = {
|
||
type: tradeResult.type,
|
||
payload: tradeResult.payload,
|
||
tradeSn: tradeResult.tradeSn,
|
||
expiration: tradeResult.expiration,
|
||
}
|
||
|
||
} catch (gatewayError) {
|
||
console.error("[Payment] Gateway error:", gatewayError)
|
||
// 如果网关创建失败,返回模拟数据(开发测试用)
|
||
paymentData = {
|
||
type: "qrcode",
|
||
payload: `mock://pay/${paymentMethod}/${orderSn}`,
|
||
tradeSn,
|
||
expiration: 1800,
|
||
}
|
||
}
|
||
|
||
return NextResponse.json({
|
||
code: 200,
|
||
message: "订单创建成功",
|
||
data: {
|
||
...order,
|
||
paymentData,
|
||
gateway, // 返回网关信息,用于前端轮询时指定
|
||
},
|
||
})
|
||
} catch (error) {
|
||
console.error("[Payment] Create order error:", error)
|
||
return NextResponse.json(
|
||
{
|
||
code: 500,
|
||
message: error instanceof Error ? error.message : "服务器错误",
|
||
data: null,
|
||
},
|
||
{ status: 500 }
|
||
)
|
||
}
|
||
}
|