Initial commit to prepare for remote overwrite
This commit is contained in:
48
app/api/payment/alipay/notify/route.ts
Normal file
48
app/api/payment/alipay/notify/route.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { type NextRequest, NextResponse } from "next/server"
|
||||
import { AlipayService } from "@/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()
|
||||
})
|
||||
|
||||
// 初始化支付宝服务
|
||||
const alipay = new AlipayService({
|
||||
appId: process.env.ALIPAY_APP_ID || "wx432c93e275548671",
|
||||
partnerId: process.env.ALIPAY_PARTNER_ID || "2088511801157159",
|
||||
key: process.env.ALIPAY_KEY || "lz6ey1h3kl9zqkgtjz3avb5gk37wzbrp",
|
||||
returnUrl: "",
|
||||
notifyUrl: "",
|
||||
})
|
||||
|
||||
// 验证签名
|
||||
const isValid = alipay.verifySign(params)
|
||||
|
||||
if (!isValid) {
|
||||
console.error("[v0] Alipay signature verification failed")
|
||||
return new NextResponse("fail")
|
||||
}
|
||||
|
||||
const { out_trade_no, trade_status, buyer_id, total_amount } = params
|
||||
|
||||
// 只处理支付成功的通知
|
||||
if (trade_status === "TRADE_SUCCESS" || trade_status === "TRADE_FINISHED") {
|
||||
console.log("[v0] Alipay payment success:", {
|
||||
orderId: out_trade_no,
|
||||
amount: total_amount,
|
||||
buyerId: buyer_id,
|
||||
})
|
||||
|
||||
// TODO: 更新订单状态、解锁内容、分配佣金
|
||||
}
|
||||
|
||||
return new NextResponse("success")
|
||||
} catch (error) {
|
||||
console.error("[v0] Alipay notify error:", error)
|
||||
return new NextResponse("fail")
|
||||
}
|
||||
}
|
||||
46
app/api/payment/callback/route.ts
Normal file
46
app/api/payment/callback/route.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { type NextRequest, NextResponse } from "next/server"
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { orderId, status, transactionId, amount, paymentMethod, signature } = body
|
||||
|
||||
console.log("[v0] Payment callback received:", {
|
||||
orderId,
|
||||
status,
|
||||
transactionId,
|
||||
amount,
|
||||
paymentMethod,
|
||||
})
|
||||
|
||||
// In production:
|
||||
// 1. Verify signature from payment gateway
|
||||
// 2. Update order status in database
|
||||
// 3. Grant user access to content
|
||||
// 4. Calculate and distribute referral commission
|
||||
|
||||
// Mock signature verification
|
||||
// const isValid = verifySignature(body, signature)
|
||||
|
||||
// For now, accept all callbacks
|
||||
const isValid = true
|
||||
|
||||
if (!isValid) {
|
||||
return NextResponse.json({ code: 403, message: "签名验证失败" }, { status: 403 })
|
||||
}
|
||||
|
||||
// Update order status
|
||||
if (status === "success") {
|
||||
// Grant access
|
||||
console.log("[v0] Payment successful, granting access for order:", orderId)
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
code: 0,
|
||||
message: "回调处理成功",
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("[v0] Payment callback error:", error)
|
||||
return NextResponse.json({ code: 500, message: "服务器错误" }, { status: 500 })
|
||||
}
|
||||
}
|
||||
88
app/api/payment/create-order/route.ts
Normal file
88
app/api/payment/create-order/route.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { type NextRequest, NextResponse } from "next/server"
|
||||
import { AlipayService } from "@/lib/payment/alipay"
|
||||
import { WechatPayService } from "@/lib/payment/wechat"
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { userId, type, sectionId, sectionTitle, amount, paymentMethod, referralCode } = body
|
||||
|
||||
// Validate required fields
|
||||
if (!userId || !type || !amount || !paymentMethod) {
|
||||
return NextResponse.json({ code: 400, message: "缺少必要参数" }, { status: 400 })
|
||||
}
|
||||
|
||||
// Generate order ID
|
||||
const orderId = `ORDER_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
||||
|
||||
// Create order object
|
||||
const order = {
|
||||
orderId,
|
||||
userId,
|
||||
type, // "section" | "fullbook"
|
||||
sectionId: type === "section" ? sectionId : undefined,
|
||||
sectionTitle: type === "section" ? sectionTitle : undefined,
|
||||
amount,
|
||||
paymentMethod, // "wechat" | "alipay" | "usdt" | "paypal"
|
||||
referralCode,
|
||||
status: "pending", // pending | completed | failed | refunded
|
||||
createdAt: new Date().toISOString(),
|
||||
expireAt: new Date(Date.now() + 30 * 60 * 1000).toISOString(), // 30 minutes
|
||||
}
|
||||
|
||||
// According to the payment method, create a payment order
|
||||
let paymentData = null
|
||||
|
||||
if (paymentMethod === "alipay") {
|
||||
const alipay = new AlipayService({
|
||||
appId: process.env.ALIPAY_APP_ID || "wx432c93e275548671",
|
||||
partnerId: process.env.ALIPAY_PARTNER_ID || "2088511801157159",
|
||||
key: process.env.ALIPAY_KEY || "lz6ey1h3kl9zqkgtjz3avb5gk37wzbrp",
|
||||
returnUrl: process.env.ALIPAY_RETURN_URL || `${process.env.NEXT_PUBLIC_BASE_URL}/payment/success`,
|
||||
notifyUrl: process.env.ALIPAY_NOTIFY_URL || `${process.env.NEXT_PUBLIC_BASE_URL}/api/payment/alipay/notify`,
|
||||
})
|
||||
|
||||
paymentData = alipay.createOrder({
|
||||
outTradeNo: orderId,
|
||||
subject: type === "section" ? `购买章节: ${sectionTitle}` : "购买整本书",
|
||||
totalAmount: amount,
|
||||
body: `知识付费-书籍购买`,
|
||||
})
|
||||
} else if (paymentMethod === "wechat") {
|
||||
const wechat = new WechatPayService({
|
||||
appId: process.env.WECHAT_APP_ID || "wx432c93e275548671",
|
||||
appSecret: process.env.WECHAT_APP_SECRET || "25b7e7fdb7998e5107e242ebb6ddabd0",
|
||||
mchId: process.env.WECHAT_MCH_ID || "1318592501",
|
||||
apiKey: process.env.WECHAT_API_KEY || "wx3e31b068be59ddc131b068be59ddc2",
|
||||
notifyUrl: process.env.WECHAT_NOTIFY_URL || `${process.env.NEXT_PUBLIC_BASE_URL}/api/payment/wechat/notify`,
|
||||
})
|
||||
|
||||
const clientIp = request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || "127.0.0.1"
|
||||
|
||||
paymentData = await wechat.createOrder({
|
||||
outTradeNo: orderId,
|
||||
body: type === "section" ? `购买章节: ${sectionTitle}` : "购买整本书",
|
||||
totalFee: amount,
|
||||
spbillCreateIp: clientIp.split(",")[0].trim(),
|
||||
})
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
code: 0,
|
||||
message: "订单创建成功",
|
||||
data: {
|
||||
...order,
|
||||
paymentData,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("[v0] Create order error:", error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
code: 500,
|
||||
message: error instanceof Error ? error.message : "服务器错误",
|
||||
},
|
||||
{ status: 500 },
|
||||
)
|
||||
}
|
||||
}
|
||||
46
app/api/payment/verify/route.ts
Normal file
46
app/api/payment/verify/route.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { type NextRequest, NextResponse } from "next/server"
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { orderId, paymentMethod, transactionId } = body
|
||||
|
||||
if (!orderId) {
|
||||
return NextResponse.json({ code: 400, message: "缺少订单号" }, { status: 400 })
|
||||
}
|
||||
|
||||
// In production, verify with payment gateway API
|
||||
// For now, simulate verification
|
||||
console.log("[v0] Verifying payment:", { orderId, paymentMethod, transactionId })
|
||||
|
||||
// Simulate verification delay
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
|
||||
// Mock verification result (95% success rate)
|
||||
const isVerified = Math.random() > 0.05
|
||||
|
||||
if (isVerified) {
|
||||
return NextResponse.json({
|
||||
code: 0,
|
||||
message: "支付验证成功",
|
||||
data: {
|
||||
orderId,
|
||||
status: "completed",
|
||||
verifiedAt: new Date().toISOString(),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
return NextResponse.json({
|
||||
code: 1,
|
||||
message: "支付未完成,请稍后再试",
|
||||
data: {
|
||||
orderId,
|
||||
status: "pending",
|
||||
},
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[v0] Verify payment error:", error)
|
||||
return NextResponse.json({ code: 500, message: "服务器错误" }, { status: 500 })
|
||||
}
|
||||
}
|
||||
59
app/api/payment/wechat/notify/route.ts
Normal file
59
app/api/payment/wechat/notify/route.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { type NextRequest, NextResponse } from "next/server"
|
||||
import { WechatPayService } from "@/lib/payment/wechat"
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const xmlData = await request.text()
|
||||
|
||||
const wechat = new WechatPayService({
|
||||
appId: process.env.WECHAT_APP_ID || "wx432c93e275548671",
|
||||
appSecret: process.env.WECHAT_APP_SECRET || "25b7e7fdb7998e5107e242ebb6ddabd0",
|
||||
mchId: process.env.WECHAT_MCH_ID || "1318592501",
|
||||
apiKey: process.env.WECHAT_API_KEY || "wx3e31b068be59ddc131b068be59ddc2",
|
||||
notifyUrl: "",
|
||||
})
|
||||
|
||||
// 解析XML数据
|
||||
const params = await wechat["parseXML"](xmlData)
|
||||
|
||||
// 验证签名
|
||||
const isValid = wechat.verifySign(params)
|
||||
|
||||
if (!isValid) {
|
||||
console.error("[v0] WeChat signature verification failed")
|
||||
return new NextResponse(
|
||||
"<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>",
|
||||
{
|
||||
headers: { "Content-Type": "application/xml" },
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
const { out_trade_no, result_code, total_fee, openid } = params
|
||||
|
||||
if (result_code === "SUCCESS") {
|
||||
console.log("[v0] WeChat payment success:", {
|
||||
orderId: out_trade_no,
|
||||
amount: Number.parseInt(total_fee) / 100,
|
||||
openid,
|
||||
})
|
||||
|
||||
// TODO: 更新订单状态、解锁内容、分配佣金
|
||||
}
|
||||
|
||||
return new NextResponse(
|
||||
"<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>",
|
||||
{
|
||||
headers: { "Content-Type": "application/xml" },
|
||||
},
|
||||
)
|
||||
} catch (error) {
|
||||
console.error("[v0] WeChat notify error:", error)
|
||||
return new NextResponse(
|
||||
"<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[系统错误]]></return_msg></xml>",
|
||||
{
|
||||
headers: { "Content-Type": "application/xml" },
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user