import { NextRequest, NextResponse } from 'next/server' import { stripe, STRIPE_CONFIG } from '@/lib/stripe' import { prisma } from '@/lib/prisma' import { headers } from 'next/headers' import { SubscriptionService } from '@/lib/subscription-service' export async function POST(request: NextRequest) { try { console.log('🔔 Webhook received') const body = await request.text() const headersList = await headers() const signature = headersList.get('stripe-signature') if (!signature) { console.log('❌ No signature found') return NextResponse.json({ error: 'No signature' }, { status: 400 }) } // 验证 webhook 签名 const event = stripe.webhooks.constructEvent( body, signature, STRIPE_CONFIG.webhookSecret ) console.log(`📨 Processing event: ${event.type}`) // 处理不同类型的事件 switch (event.type) { case 'checkout.session.completed': await handleCheckoutSessionCompleted(event.data.object as unknown as Record) break case 'customer.subscription.created': case 'customer.subscription.updated': await handleSubscriptionUpdate(event.data.object as unknown as Record) break case 'customer.subscription.deleted': await handleSubscriptionDeleted(event.data.object as unknown as Record) break case 'invoice.payment_succeeded': await handlePaymentSucceeded(event.data.object as unknown as Record) break case 'invoice.payment_failed': await handlePaymentFailed(event.data.object as unknown as Record) break default: console.log(`Unhandled event type: ${event.type}`) } return NextResponse.json({ received: true }) } catch (error) { console.error('Webhook error:', error) return NextResponse.json( { error: 'Webhook handler failed' }, { status: 400 } ) } } async function handleCheckoutSessionCompleted(session: Record) { try { console.log('🛒 Processing checkout session completed') console.log('Session data:', JSON.stringify(session, null, 2)) const subscriptionId = session.subscription as string console.log('Subscription ID from session:', subscriptionId) if (!subscriptionId) { console.log('❌ No subscription ID found in checkout session') return } // 获取订阅详情 console.log('📞 Retrieving subscription from Stripe...') const subscription = await stripe.subscriptions.retrieve(subscriptionId) console.log('✅ Retrieved subscription:', subscription.id, 'status:', subscription.status) // 处理订阅更新 await handleSubscriptionUpdate(subscription as unknown as Record) } catch (error) { console.error('❌ Error handling checkout session completed:', error) } } async function handleSubscriptionUpdate(subscription: Record) { try { console.log('🔄 Processing subscription update') const customerId = subscription.customer as string const status = subscription.status as string const stripeSubscriptionId = subscription.id as string const items = subscription.items as { data: Array<{ price: { id: string } }> } const priceId = items?.data[0]?.price?.id const currentPeriodStart = subscription.current_period_start as number const currentPeriodEnd = subscription.current_period_end as number console.log(`📊 Subscription details:`, { customerId, status, stripeSubscriptionId, priceId }) // 查找用户 const user = await prisma.user.findFirst({ where: { stripeCustomerId: customerId } }) if (!user) { console.error('❌ User not found for customer:', customerId) return } console.log(`👤 Found user: ${user.id}`) if (status === 'active' || status === 'trialing') { // 根据 Stripe 价格 ID 获取套餐 ID const planId = await SubscriptionService.getPlanIdByStripePriceId(priceId) // 检查是否已有待激活的订阅记录(通过用户 ID 查找) const existingSubscription = await prisma.subscription.findFirst({ where: { userId: user.id, status: 'pending', subscriptionPlanId: planId }, orderBy: { createdAt: 'desc' } }) if (existingSubscription) { // 激活现有的订阅记录,并设置 Stripe 订阅 ID await prisma.subscription.update({ where: { id: existingSubscription.id }, data: { stripeSubscriptionId, isActive: true, status: 'active', startDate: new Date(currentPeriodStart * 1000), endDate: new Date(currentPeriodEnd * 1000), metadata: subscription ? JSON.parse(JSON.stringify(subscription)) : undefined, updatedAt: new Date() } }) console.log(`✅ Activated existing subscription ${existingSubscription.id} for user ${user.id}`) } else { // 检查是否是续订(已有活跃订阅) const activeSubscription = await SubscriptionService.getUserActiveSubscription(user.id) if (activeSubscription) { // 这是续订,创建新的订阅记录 await SubscriptionService.createRenewalSubscription( user.id, planId, stripeSubscriptionId, new Date(currentPeriodStart * 1000), new Date(currentPeriodEnd * 1000), customerId, subscription ) console.log(`Created renewal subscription for user ${user.id}`) } else { // 直接创建并激活订阅(可能是通过其他方式创建的订阅) await SubscriptionService.createRenewalSubscription( user.id, planId, stripeSubscriptionId, new Date(currentPeriodStart * 1000), new Date(currentPeriodEnd * 1000), customerId, subscription ) console.log(`Created new subscription for user ${user.id}`) } } } // 更新用户的默认订阅套餐(保持向后兼容) const planId = status === 'active' || status === 'trialing' ? await SubscriptionService.getPlanIdByStripePriceId(priceId) : 'free' await SubscriptionService.updateUserSubscriptionPlan(user.id, planId) } catch (error) { console.error('Error handling subscription update:', error) } } async function handleSubscriptionDeleted(subscription: Record) { try { const customerId = subscription.customer as string // 查找用户 const user = await prisma.user.findFirst({ where: { stripeCustomerId: customerId } }) if (!user) { console.error('User not found for customer:', customerId) return } // 将用户降级为免费计划 await SubscriptionService.updateUserSubscriptionPlan(user.id, 'free') console.log(`Reset user ${user.id} to free plan`) } catch (error) { console.error('Error handling subscription deletion:', error) } } async function handlePaymentSucceeded(_invoice: Record) { try { // 这里可以添加额外的逻辑,比如发送确认邮件等 } catch (error) { console.error('Error handling payment success:', error) } } async function handlePaymentFailed(_invoice: Record) { try { // 这里可以添加额外的逻辑,比如发送提醒邮件等 } catch (error) { console.error('Error handling payment failure:', error) } }