finished sub
This commit is contained in:
parent
5b36748048
commit
64e2ad63b8
103
scripts/create-test-subscription.ts
Normal file
103
scripts/create-test-subscription.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#!/usr/bin/env tsx
|
||||||
|
|
||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
async function createTestSubscription() {
|
||||||
|
try {
|
||||||
|
console.log('🧪 Creating test subscription...')
|
||||||
|
|
||||||
|
// 使用真实的数据
|
||||||
|
const subscriptionData = {
|
||||||
|
userId: '9975b2c5-7955-48cf-9594-74b8d9beab25',
|
||||||
|
subscriptionPlanId: 'pro',
|
||||||
|
stripeSubscriptionId: 'sub_1Rt8nRLW0cChKPJ0Osn5UBcV',
|
||||||
|
stripeCustomerId: 'cus_SojwymqWZ4EXlZ',
|
||||||
|
isActive: true,
|
||||||
|
status: 'active',
|
||||||
|
startDate: new Date(1754492307 * 1000), // 2025-08-06T14:58:27.000Z
|
||||||
|
endDate: new Date(1757170707 * 1000), // 2025-09-06T14:58:27.000Z
|
||||||
|
metadata: {
|
||||||
|
test: true,
|
||||||
|
created_by: 'manual_script'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('📊 Creating subscription with data:', subscriptionData)
|
||||||
|
|
||||||
|
// 检查是否已存在
|
||||||
|
const existing = await prisma.subscription.findFirst({
|
||||||
|
where: {
|
||||||
|
stripeSubscriptionId: subscriptionData.stripeSubscriptionId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
console.log('⚠️ Subscription already exists:', existing.id)
|
||||||
|
console.log('🗑️ Deleting existing subscription...')
|
||||||
|
await prisma.subscription.delete({
|
||||||
|
where: { id: existing.id }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新订阅
|
||||||
|
const newSubscription = await prisma.subscription.create({
|
||||||
|
data: subscriptionData
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('✅ Created subscription:', newSubscription.id)
|
||||||
|
|
||||||
|
// 更新用户的订阅计划
|
||||||
|
await prisma.user.update({
|
||||||
|
where: { id: subscriptionData.userId },
|
||||||
|
data: {
|
||||||
|
subscriptionPlanId: 'pro',
|
||||||
|
subscribePlan: 'pro'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('✅ Updated user subscription plan')
|
||||||
|
|
||||||
|
// 验证创建结果
|
||||||
|
const createdSubscription = await prisma.subscription.findUnique({
|
||||||
|
where: { id: newSubscription.id },
|
||||||
|
include: {
|
||||||
|
user: {
|
||||||
|
select: {
|
||||||
|
email: true,
|
||||||
|
subscriptionPlanId: true,
|
||||||
|
subscribePlan: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
subscriptionPlan: {
|
||||||
|
select: {
|
||||||
|
name: true,
|
||||||
|
price: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('📋 Subscription details:')
|
||||||
|
console.log(' ID:', createdSubscription?.id)
|
||||||
|
console.log(' User:', createdSubscription?.user.email)
|
||||||
|
console.log(' Plan:', createdSubscription?.subscriptionPlan.name)
|
||||||
|
console.log(' Price:', `$${createdSubscription?.subscriptionPlan.price}`)
|
||||||
|
console.log(' Status:', createdSubscription?.status)
|
||||||
|
console.log(' Active:', createdSubscription?.isActive)
|
||||||
|
console.log(' Start:', createdSubscription?.startDate)
|
||||||
|
console.log(' End:', createdSubscription?.endDate)
|
||||||
|
console.log(' User Plan ID:', createdSubscription?.user.subscriptionPlanId)
|
||||||
|
console.log(' User Plan:', createdSubscription?.user.subscribePlan)
|
||||||
|
|
||||||
|
console.log('🎉 Test subscription created successfully!')
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error creating test subscription:', error)
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createTestSubscription()
|
88
scripts/test-subscription-table.ts
Normal file
88
scripts/test-subscription-table.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env tsx
|
||||||
|
|
||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
async function testSubscriptionTable() {
|
||||||
|
try {
|
||||||
|
console.log('🔍 Testing subscription table...')
|
||||||
|
|
||||||
|
// 测试查询所有订阅
|
||||||
|
const subscriptions = await prisma.subscription.findMany({
|
||||||
|
include: {
|
||||||
|
user: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
stripeCustomerId: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
subscriptionPlan: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
price: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(`📊 Found ${subscriptions.length} subscriptions:`)
|
||||||
|
subscriptions.forEach((sub, index) => {
|
||||||
|
console.log(`${index + 1}. Subscription ${sub.id}:`)
|
||||||
|
console.log(` - User: ${sub.user.email} (${sub.user.id})`)
|
||||||
|
console.log(` - Plan: ${sub.subscriptionPlan.name} ($${sub.subscriptionPlan.price})`)
|
||||||
|
console.log(` - Status: ${sub.status}`)
|
||||||
|
console.log(` - Active: ${sub.isActive}`)
|
||||||
|
console.log(` - Stripe ID: ${sub.stripeSubscriptionId}`)
|
||||||
|
console.log(` - Start: ${sub.startDate}`)
|
||||||
|
console.log(` - End: ${sub.endDate}`)
|
||||||
|
console.log('')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试查询用户
|
||||||
|
const users = await prisma.user.findMany({
|
||||||
|
where: {
|
||||||
|
stripeCustomerId: {
|
||||||
|
not: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
stripeCustomerId: true,
|
||||||
|
subscriptionPlanId: true,
|
||||||
|
subscribePlan: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(`👥 Found ${users.length} users with Stripe customer IDs:`)
|
||||||
|
users.forEach((user, index) => {
|
||||||
|
console.log(`${index + 1}. ${user.email}:`)
|
||||||
|
console.log(` - User ID: ${user.id}`)
|
||||||
|
console.log(` - Stripe Customer ID: ${user.stripeCustomerId}`)
|
||||||
|
console.log(` - Subscription Plan ID: ${user.subscriptionPlanId}`)
|
||||||
|
console.log(` - Subscribe Plan: ${user.subscribePlan}`)
|
||||||
|
console.log('')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试查询订阅套餐
|
||||||
|
const plans = await prisma.subscriptionPlan.findMany()
|
||||||
|
console.log(`📦 Found ${plans.length} subscription plans:`)
|
||||||
|
plans.forEach((plan, index) => {
|
||||||
|
console.log(`${index + 1}. ${plan.name} (${plan.id}):`)
|
||||||
|
console.log(` - Price: $${plan.price}`)
|
||||||
|
console.log(` - Stripe Price ID: ${plan.stripePriceId}`)
|
||||||
|
console.log(` - Active: ${plan.isActive}`)
|
||||||
|
console.log('')
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error testing subscription table:', error)
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testSubscriptionTable()
|
232
scripts/test-webhook-data.ts
Normal file
232
scripts/test-webhook-data.ts
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
#!/usr/bin/env tsx
|
||||||
|
|
||||||
|
// 模拟从你的日志中提取的 Stripe 订阅数据
|
||||||
|
const mockSubscriptionData = {
|
||||||
|
"id": "sub_1Rt8nRLW0cChKPJ0Osn5UBcV",
|
||||||
|
"object": "subscription",
|
||||||
|
"application": null,
|
||||||
|
"application_fee_percent": null,
|
||||||
|
"automatic_tax": {
|
||||||
|
"disabled_reason": null,
|
||||||
|
"enabled": false,
|
||||||
|
"liability": null
|
||||||
|
},
|
||||||
|
"billing_cycle_anchor": 1754492307,
|
||||||
|
"billing_cycle_anchor_config": null,
|
||||||
|
"billing_mode": {
|
||||||
|
"type": "classic"
|
||||||
|
},
|
||||||
|
"billing_thresholds": null,
|
||||||
|
"cancel_at": null,
|
||||||
|
"cancel_at_period_end": false,
|
||||||
|
"canceled_at": null,
|
||||||
|
"cancellation_details": {
|
||||||
|
"comment": null,
|
||||||
|
"feedback": null,
|
||||||
|
"reason": null
|
||||||
|
},
|
||||||
|
"collection_method": "charge_automatically",
|
||||||
|
"created": 1754492307,
|
||||||
|
"currency": "usd",
|
||||||
|
"customer": "cus_SojwymqWZ4EXlZ",
|
||||||
|
"days_until_due": null,
|
||||||
|
"default_payment_method": "pm_1Rt8nPLW0cChKPJ0EF0QrEyS",
|
||||||
|
"default_source": null,
|
||||||
|
"default_tax_rates": [],
|
||||||
|
"description": null,
|
||||||
|
"discounts": [],
|
||||||
|
"ended_at": null,
|
||||||
|
"invoice_settings": {
|
||||||
|
"account_tax_ids": null,
|
||||||
|
"issuer": {
|
||||||
|
"type": "self"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"object": "list",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": "si_SomMVRu4Bpje2r",
|
||||||
|
"object": "subscription_item",
|
||||||
|
"billing_thresholds": null,
|
||||||
|
"created": 1754492308,
|
||||||
|
"current_period_end": 1757170707,
|
||||||
|
"current_period_start": 1754492307,
|
||||||
|
"discounts": [],
|
||||||
|
"metadata": {},
|
||||||
|
"plan": {
|
||||||
|
"id": "price_1RslfmLW0cChKPJ0VurJSg9I",
|
||||||
|
"object": "plan",
|
||||||
|
"active": true,
|
||||||
|
"amount": 1999,
|
||||||
|
"amount_decimal": "1999",
|
||||||
|
"billing_scheme": "per_unit",
|
||||||
|
"created": 1754403422,
|
||||||
|
"currency": "usd",
|
||||||
|
"interval": "month",
|
||||||
|
"interval_count": 1,
|
||||||
|
"livemode": false,
|
||||||
|
"metadata": {},
|
||||||
|
"meter": null,
|
||||||
|
"nickname": null,
|
||||||
|
"product": "prod_SoOSFPRNsYcTF8",
|
||||||
|
"tiers_mode": null,
|
||||||
|
"transform_usage": null,
|
||||||
|
"trial_period_days": null,
|
||||||
|
"usage_type": "licensed"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"id": "price_1RslfmLW0cChKPJ0VurJSg9I",
|
||||||
|
"object": "price",
|
||||||
|
"active": true,
|
||||||
|
"billing_scheme": "per_unit",
|
||||||
|
"created": 1754403422,
|
||||||
|
"currency": "usd",
|
||||||
|
"custom_unit_amount": null,
|
||||||
|
"livemode": false,
|
||||||
|
"lookup_key": null,
|
||||||
|
"metadata": {},
|
||||||
|
"nickname": null,
|
||||||
|
"product": "prod_SoOSFPRNsYcTF8",
|
||||||
|
"recurring": {
|
||||||
|
"interval": "month",
|
||||||
|
"interval_count": 1,
|
||||||
|
"meter": null,
|
||||||
|
"trial_period_days": null,
|
||||||
|
"usage_type": "licensed"
|
||||||
|
},
|
||||||
|
"tax_behavior": "inclusive",
|
||||||
|
"tiers_mode": null,
|
||||||
|
"transform_quantity": null,
|
||||||
|
"type": "recurring",
|
||||||
|
"unit_amount": 1999,
|
||||||
|
"unit_amount_decimal": "1999"
|
||||||
|
},
|
||||||
|
"quantity": 1,
|
||||||
|
"subscription": "sub_1Rt8nRLW0cChKPJ0Osn5UBcV",
|
||||||
|
"tax_rates": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"has_more": false,
|
||||||
|
"total_count": 1,
|
||||||
|
"url": "/v1/subscription_items?subscription=sub_1Rt8nRLW0cChKPJ0Osn5UBcV"
|
||||||
|
},
|
||||||
|
"latest_invoice": "in_1Rt8nPLW0cChKPJ0YOG0OCof",
|
||||||
|
"livemode": false,
|
||||||
|
"metadata": {},
|
||||||
|
"next_pending_invoice_item_invoice": null,
|
||||||
|
"on_behalf_of": null,
|
||||||
|
"pause_collection": null,
|
||||||
|
"payment_settings": {
|
||||||
|
"payment_method_options": {
|
||||||
|
"acss_debit": null,
|
||||||
|
"bancontact": null,
|
||||||
|
"card": {
|
||||||
|
"network": null,
|
||||||
|
"request_three_d_secure": "automatic"
|
||||||
|
},
|
||||||
|
"customer_balance": null,
|
||||||
|
"konbini": null,
|
||||||
|
"sepa_debit": null,
|
||||||
|
"us_bank_account": null
|
||||||
|
},
|
||||||
|
"payment_method_types": [
|
||||||
|
"card"
|
||||||
|
],
|
||||||
|
"save_default_payment_method": "off"
|
||||||
|
},
|
||||||
|
"pending_invoice_item_interval": null,
|
||||||
|
"pending_setup_intent": null,
|
||||||
|
"pending_update": null,
|
||||||
|
"plan": {
|
||||||
|
"id": "price_1RslfmLW0cChKPJ0VurJSg9I",
|
||||||
|
"object": "plan",
|
||||||
|
"active": true,
|
||||||
|
"amount": 1999,
|
||||||
|
"amount_decimal": "1999",
|
||||||
|
"billing_scheme": "per_unit",
|
||||||
|
"created": 1754403422,
|
||||||
|
"currency": "usd",
|
||||||
|
"interval": "month",
|
||||||
|
"interval_count": 1,
|
||||||
|
"livemode": false,
|
||||||
|
"metadata": {},
|
||||||
|
"meter": null,
|
||||||
|
"nickname": null,
|
||||||
|
"product": "prod_SoOSFPRNsYcTF8",
|
||||||
|
"tiers_mode": null,
|
||||||
|
"transform_usage": null,
|
||||||
|
"trial_period_days": null,
|
||||||
|
"usage_type": "licensed"
|
||||||
|
},
|
||||||
|
"quantity": 1,
|
||||||
|
"schedule": null,
|
||||||
|
"start_date": 1754492307,
|
||||||
|
"status": "active",
|
||||||
|
"test_clock": null,
|
||||||
|
"transfer_data": null,
|
||||||
|
"trial_end": null,
|
||||||
|
"trial_settings": {
|
||||||
|
"end_behavior": {
|
||||||
|
"missing_payment_method": "create_invoice"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"trial_start": null
|
||||||
|
}
|
||||||
|
|
||||||
|
function testWebhookData() {
|
||||||
|
console.log('🔍 Testing webhook data extraction...')
|
||||||
|
|
||||||
|
const subscription = mockSubscriptionData as any
|
||||||
|
|
||||||
|
console.log('📊 Subscription object keys:', Object.keys(subscription))
|
||||||
|
|
||||||
|
// 测试当前的提取逻辑
|
||||||
|
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('🎯 Extracted data (current logic):')
|
||||||
|
console.log(' customerId:', customerId)
|
||||||
|
console.log(' status:', status)
|
||||||
|
console.log(' stripeSubscriptionId:', stripeSubscriptionId)
|
||||||
|
console.log(' priceId:', priceId)
|
||||||
|
console.log(' currentPeriodStart:', currentPeriodStart)
|
||||||
|
console.log(' currentPeriodEnd:', currentPeriodEnd)
|
||||||
|
|
||||||
|
// 检查日期是否有效
|
||||||
|
if (currentPeriodStart) {
|
||||||
|
const startDate = new Date(currentPeriodStart * 1000)
|
||||||
|
console.log(' startDate:', startDate.toISOString())
|
||||||
|
} else {
|
||||||
|
console.log(' ❌ currentPeriodStart is undefined/null')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPeriodEnd) {
|
||||||
|
const endDate = new Date(currentPeriodEnd * 1000)
|
||||||
|
console.log(' endDate:', endDate.toISOString())
|
||||||
|
} else {
|
||||||
|
console.log(' ❌ currentPeriodEnd is undefined/null')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查替代的日期字段
|
||||||
|
console.log('\n🔍 Looking for alternative date fields:')
|
||||||
|
console.log(' start_date:', subscription.start_date)
|
||||||
|
console.log(' created:', subscription.created)
|
||||||
|
console.log(' billing_cycle_anchor:', subscription.billing_cycle_anchor)
|
||||||
|
|
||||||
|
// 检查 items 中的日期
|
||||||
|
if (subscription.items?.data?.[0]) {
|
||||||
|
const item = subscription.items.data[0]
|
||||||
|
console.log(' item.current_period_start:', item.current_period_start)
|
||||||
|
console.log(' item.current_period_end:', item.current_period_end)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n✅ Analysis complete!')
|
||||||
|
}
|
||||||
|
|
||||||
|
testWebhookData()
|
111
scripts/test-webhook-fix.ts
Normal file
111
scripts/test-webhook-fix.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#!/usr/bin/env tsx
|
||||||
|
|
||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
// 模拟修复后的 webhook 处理逻辑
|
||||||
|
async function testWebhookFix() {
|
||||||
|
try {
|
||||||
|
console.log('🧪 Testing webhook fix...')
|
||||||
|
|
||||||
|
// 模拟 Stripe 订阅数据
|
||||||
|
const mockSubscription = {
|
||||||
|
id: "sub_1Rt8nRLW0cChKPJ0Osn5UBcV",
|
||||||
|
customer: "cus_SojwymqWZ4EXlZ",
|
||||||
|
status: "active",
|
||||||
|
start_date: 1754492307,
|
||||||
|
items: {
|
||||||
|
data: [{
|
||||||
|
price: { id: "price_1RslfmLW0cChKPJ0VurJSg9I" },
|
||||||
|
current_period_start: 1754492307,
|
||||||
|
current_period_end: 1757170707
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取数据(使用修复后的逻辑)
|
||||||
|
const customerId = mockSubscription.customer
|
||||||
|
const status = mockSubscription.status
|
||||||
|
const stripeSubscriptionId = mockSubscription.id
|
||||||
|
const items = mockSubscription.items
|
||||||
|
const priceId = items?.data[0]?.price?.id
|
||||||
|
const currentPeriodStart = items?.data[0]?.current_period_start || mockSubscription.start_date
|
||||||
|
const currentPeriodEnd = items?.data[0]?.current_period_end || (mockSubscription.start_date + 30 * 24 * 60 * 60)
|
||||||
|
|
||||||
|
console.log('📊 Extracted data:')
|
||||||
|
console.log(' customerId:', customerId)
|
||||||
|
console.log(' status:', status)
|
||||||
|
console.log(' stripeSubscriptionId:', stripeSubscriptionId)
|
||||||
|
console.log(' priceId:', priceId)
|
||||||
|
console.log(' currentPeriodStart:', currentPeriodStart)
|
||||||
|
console.log(' currentPeriodEnd:', currentPeriodEnd)
|
||||||
|
|
||||||
|
// 验证日期
|
||||||
|
if (!currentPeriodStart || !currentPeriodEnd) {
|
||||||
|
console.error('❌ Missing period dates')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const startDate = new Date(currentPeriodStart * 1000)
|
||||||
|
const endDate = new Date(currentPeriodEnd * 1000)
|
||||||
|
|
||||||
|
console.log('📅 Converted dates:')
|
||||||
|
console.log(' startDate:', startDate.toISOString())
|
||||||
|
console.log(' endDate:', endDate.toISOString())
|
||||||
|
|
||||||
|
// 检查日期是否有效
|
||||||
|
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
|
||||||
|
console.error('❌ Invalid dates')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ Dates are valid!')
|
||||||
|
|
||||||
|
// 查找用户
|
||||||
|
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.email)
|
||||||
|
|
||||||
|
// 查找套餐
|
||||||
|
const plan = await prisma.subscriptionPlan.findFirst({
|
||||||
|
where: { stripePriceId: priceId }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!plan) {
|
||||||
|
console.error('❌ Plan not found for price:', priceId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('📦 Found plan:', plan.name)
|
||||||
|
|
||||||
|
// 模拟创建订阅记录
|
||||||
|
console.log('🔄 Would create subscription with data:')
|
||||||
|
console.log({
|
||||||
|
userId: user.id,
|
||||||
|
subscriptionPlanId: plan.id,
|
||||||
|
stripeSubscriptionId,
|
||||||
|
stripeCustomerId: customerId,
|
||||||
|
isActive: true,
|
||||||
|
status: 'active',
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('✅ Webhook fix test completed successfully!')
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error testing webhook fix:', error)
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testWebhookFix()
|
@ -98,20 +98,47 @@ async function handleSubscriptionCreated(subscription: Record<string, unknown>)
|
|||||||
const customerId = subscription.customer as string
|
const customerId = subscription.customer as string
|
||||||
const status = subscription.status as string
|
const status = subscription.status as string
|
||||||
const stripeSubscriptionId = subscription.id as string
|
const stripeSubscriptionId = subscription.id as string
|
||||||
const items = subscription.items as { data: Array<{ price: { id: string } }> }
|
const items = subscription.items as { data: Array<{
|
||||||
|
price: { id: string }
|
||||||
|
current_period_start: number
|
||||||
|
current_period_end: number
|
||||||
|
}> }
|
||||||
const priceId = items?.data[0]?.price?.id
|
const priceId = items?.data[0]?.price?.id
|
||||||
const currentPeriodStart = subscription.current_period_start as number
|
|
||||||
const currentPeriodEnd = subscription.current_period_end as number
|
// 从 subscription items 中获取周期日期,如果不存在则使用 subscription 的 start_date
|
||||||
|
const currentPeriodStart = items?.data[0]?.current_period_start || subscription.start_date as number
|
||||||
|
const currentPeriodEnd = items?.data[0]?.current_period_end || (subscription.start_date as number + 30 * 24 * 60 * 60) // 默认30天后
|
||||||
|
|
||||||
console.log(`📊 New subscription details:`, {
|
console.log(`📊 New subscription details:`, {
|
||||||
customerId,
|
customerId,
|
||||||
status,
|
status,
|
||||||
stripeSubscriptionId,
|
stripeSubscriptionId,
|
||||||
priceId
|
priceId,
|
||||||
|
currentPeriodStart,
|
||||||
|
currentPeriodEnd
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 验证必要的字段
|
||||||
|
if (!customerId || !stripeSubscriptionId || !priceId) {
|
||||||
|
console.error('❌ Missing required subscription data:', {
|
||||||
|
customerId: !!customerId,
|
||||||
|
stripeSubscriptionId: !!stripeSubscriptionId,
|
||||||
|
priceId: !!priceId
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证日期字段
|
||||||
|
if (!currentPeriodStart || !currentPeriodEnd) {
|
||||||
|
console.error('❌ Missing or invalid period dates:', {
|
||||||
|
currentPeriodStart,
|
||||||
|
currentPeriodEnd
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 查找用户
|
// 查找用户
|
||||||
const user = await prisma.user.findFirst({
|
const user = await (prisma as any).user.findFirst({
|
||||||
where: { stripeCustomerId: customerId }
|
where: { stripeCustomerId: customerId }
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -126,13 +153,24 @@ async function handleSubscriptionCreated(subscription: Record<string, unknown>)
|
|||||||
// 根据 Stripe 价格 ID 获取套餐 ID
|
// 根据 Stripe 价格 ID 获取套餐 ID
|
||||||
const planId = await SubscriptionService.getPlanIdByStripePriceId(priceId)
|
const planId = await SubscriptionService.getPlanIdByStripePriceId(priceId)
|
||||||
|
|
||||||
|
// 创建日期对象,确保有效性
|
||||||
|
const startDate = new Date(currentPeriodStart * 1000)
|
||||||
|
const endDate = new Date(currentPeriodEnd * 1000)
|
||||||
|
|
||||||
|
console.log(`📅 Subscription dates:`, {
|
||||||
|
currentPeriodStart,
|
||||||
|
currentPeriodEnd,
|
||||||
|
startDate: startDate.toISOString(),
|
||||||
|
endDate: endDate.toISOString()
|
||||||
|
})
|
||||||
|
|
||||||
// 创建新的订阅记录
|
// 创建新的订阅记录
|
||||||
const newSubscription = await SubscriptionService.createRenewalSubscription(
|
const newSubscription = await SubscriptionService.createRenewalSubscription(
|
||||||
user.id,
|
user.id,
|
||||||
planId,
|
planId,
|
||||||
stripeSubscriptionId,
|
stripeSubscriptionId,
|
||||||
new Date(currentPeriodStart * 1000),
|
startDate,
|
||||||
new Date(currentPeriodEnd * 1000),
|
endDate,
|
||||||
customerId,
|
customerId,
|
||||||
subscription
|
subscription
|
||||||
)
|
)
|
||||||
@ -154,10 +192,16 @@ async function handleSubscriptionUpdate(subscription: Record<string, unknown>) {
|
|||||||
const customerId = subscription.customer as string
|
const customerId = subscription.customer as string
|
||||||
const status = subscription.status as string
|
const status = subscription.status as string
|
||||||
const stripeSubscriptionId = subscription.id as string
|
const stripeSubscriptionId = subscription.id as string
|
||||||
const items = subscription.items as { data: Array<{ price: { id: string } }> }
|
const items = subscription.items as { data: Array<{
|
||||||
|
price: { id: string }
|
||||||
|
current_period_start: number
|
||||||
|
current_period_end: number
|
||||||
|
}> }
|
||||||
const priceId = items?.data[0]?.price?.id
|
const priceId = items?.data[0]?.price?.id
|
||||||
const currentPeriodStart = subscription.current_period_start as number
|
|
||||||
const currentPeriodEnd = subscription.current_period_end as number
|
// 从 subscription items 中获取周期日期
|
||||||
|
const currentPeriodStart = items?.data[0]?.current_period_start || subscription.start_date as number
|
||||||
|
const currentPeriodEnd = items?.data[0]?.current_period_end || (subscription.start_date as number + 30 * 24 * 60 * 60)
|
||||||
|
|
||||||
console.log(`📊 Subscription details:`, {
|
console.log(`📊 Subscription details:`, {
|
||||||
customerId,
|
customerId,
|
||||||
@ -167,7 +211,7 @@ async function handleSubscriptionUpdate(subscription: Record<string, unknown>) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 查找用户
|
// 查找用户
|
||||||
const user = await prisma.user.findFirst({
|
const user = await (prisma as any).user.findFirst({
|
||||||
where: { stripeCustomerId: customerId }
|
where: { stripeCustomerId: customerId }
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -183,7 +227,7 @@ async function handleSubscriptionUpdate(subscription: Record<string, unknown>) {
|
|||||||
const planId = await SubscriptionService.getPlanIdByStripePriceId(priceId)
|
const planId = await SubscriptionService.getPlanIdByStripePriceId(priceId)
|
||||||
|
|
||||||
// 查找现有的订阅记录(通过 Stripe 订阅 ID)
|
// 查找现有的订阅记录(通过 Stripe 订阅 ID)
|
||||||
const existingSubscription = await prisma.subscription.findFirst({
|
const existingSubscription = await (prisma as any).subscription.findFirst({
|
||||||
where: {
|
where: {
|
||||||
stripeSubscriptionId,
|
stripeSubscriptionId,
|
||||||
}
|
}
|
||||||
@ -191,7 +235,7 @@ async function handleSubscriptionUpdate(subscription: Record<string, unknown>) {
|
|||||||
|
|
||||||
if (existingSubscription) {
|
if (existingSubscription) {
|
||||||
// 更新现有的订阅记录
|
// 更新现有的订阅记录
|
||||||
await prisma.subscription.update({
|
await (prisma as any).subscription.update({
|
||||||
where: { id: existingSubscription.id },
|
where: { id: existingSubscription.id },
|
||||||
data: {
|
data: {
|
||||||
isActive: true,
|
isActive: true,
|
||||||
@ -227,7 +271,7 @@ async function handleSubscriptionDeleted(subscription: Record<string, unknown>)
|
|||||||
const customerId = subscription.customer as string
|
const customerId = subscription.customer as string
|
||||||
|
|
||||||
// 查找用户
|
// 查找用户
|
||||||
const user = await prisma.user.findFirst({
|
const user = await (prisma as any).user.findFirst({
|
||||||
where: { stripeCustomerId: customerId }
|
where: { stripeCustomerId: customerId }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user