diff --git a/scripts/debug-pricing-plans.ts b/scripts/debug-pricing-plans.ts new file mode 100644 index 0000000..19a3d8f --- /dev/null +++ b/scripts/debug-pricing-plans.ts @@ -0,0 +1,128 @@ +import { PrismaClient } from '@prisma/client' +import { SubscriptionService } from '../src/lib/subscription-service' +import { isPlanFree } from '../src/lib/subscription-utils' + +const prisma = new PrismaClient() + +async function debugPricingPlans() { + console.log('🔍 Debugging pricing plans visibility...') + + try { + // 1. 获取所有套餐的详细信息 + console.log('\n1. All plans in database:') + const allPlans = await SubscriptionService.getAvailablePlans() + + allPlans.forEach((plan, index) => { + console.log(`\n${index + 1}. Plan Details:`) + console.log(` - ID: "${plan.id}"`) + console.log(` - Name: "${plan.name}"`) + console.log(` - Display Name: "${plan.displayName}"`) + console.log(` - Price: $${plan.price}`) + console.log(` - Stripe Price ID: "${plan.stripePriceId || 'NULL'}"`) + console.log(` - Is Active: ${plan.isActive}`) + console.log(` - Is Free: ${isPlanFree(plan)}`) + console.log(` - Has Valid Price ID: ${!!(plan.stripePriceId && plan.stripePriceId.trim() !== '')}`) + }) + + // 2. 模拟未登录用户的过滤逻辑 + console.log('\n2. Filtering logic for anonymous user:') + + const filteredPlans = allPlans.filter(plan => { + console.log(`\nChecking plan: ${plan.displayName} (${plan.id})`) + + // 只显示官方的免费套餐(ID为'free'或名称为'free') + if (isPlanFree(plan) && (plan.id === 'free' || plan.name.toLowerCase() === 'free')) { + console.log(` ✅ Showing: Official free plan`) + return true + } else if (isPlanFree(plan)) { + console.log(` ❌ Hidden: Free plan but not official (${plan.id}, ${plan.name})`) + } + + // 用户当前套餐总是显示 (对于未登录用户,userData = null) + const userData = null as { subscriptionPlanId: string } | null // 模拟未登录用户 + if (userData && userData.subscriptionPlanId === plan.id) { + console.log(` ✅ Showing: Current plan`) + return true + } else { + console.log(` ❌ Not current plan (user not logged in)`) + } + + // 付费套餐必须有 stripePriceId 才能显示(可订阅) + if (!isPlanFree(plan) && plan.stripePriceId && plan.stripePriceId.trim() !== '') { + console.log(` ✅ Showing: Paid plan with valid Stripe Price ID`) + return true + } else if (!isPlanFree(plan)) { + console.log(` ❌ Hidden: Paid plan without valid Stripe Price ID`) + } + + return false + }) + + console.log('\n3. Plans visible to anonymous user:') + filteredPlans.forEach((plan, index) => { + console.log(` ${index + 1}. ${plan.displayName} (${plan.id}) - $${plan.price}`) + }) + + // 3. 检查可能的问题 + console.log('\n4. Potential issues:') + + const problematicPlans = allPlans.filter(plan => + !isPlanFree(plan) && (!plan.stripePriceId || plan.stripePriceId.trim() === '') + ) + + if (problematicPlans.length > 0) { + console.log(` ⚠️ Found ${problematicPlans.length} paid plans without valid Stripe Price ID:`) + problematicPlans.forEach(plan => { + console.log(` - ${plan.displayName} (${plan.id}): $${plan.price}`) + console.log(` Should be hidden for anonymous users unless it's their current plan`) + }) + } else { + console.log(' ✅ All paid plans have valid Stripe Price IDs') + } + + // 4. 检查是否有奇怪的套餐 + console.log('\n5. Checking for unusual plans:') + + const plansWithoutId = allPlans.filter(plan => !plan.id || plan.id.trim() === '') + if (plansWithoutId.length > 0) { + console.log(` ⚠️ Found ${plansWithoutId.length} plans without proper ID:`) + plansWithoutId.forEach(plan => { + console.log(` - Display Name: "${plan.displayName}"`) + console.log(` - ID: "${plan.id}"`) + }) + } + + const plansWithEmptyName = allPlans.filter(plan => !plan.name || plan.name.trim() === '') + if (plansWithEmptyName.length > 0) { + console.log(` ⚠️ Found ${plansWithEmptyName.length} plans without proper name:`) + plansWithEmptyName.forEach(plan => { + console.log(` - Display Name: "${plan.displayName}"`) + console.log(` - Name: "${plan.name}"`) + console.log(` - ID: "${plan.id}"`) + }) + } + + console.log('\n🎉 Debug completed!') + + } catch (error) { + console.error('❌ Debug failed:', error) + throw error + } finally { + await prisma.$disconnect() + } +} + +// 运行调试 +if (require.main === module) { + debugPricingPlans() + .then(() => { + console.log('✅ Debug completed!') + process.exit(0) + }) + .catch((error) => { + console.error('❌ Debug failed:', error) + process.exit(1) + }) +} + +export { debugPricingPlans } diff --git a/scripts/test-pricing-page-filtering.ts b/scripts/test-pricing-page-filtering.ts index c7419db..bb5b94b 100644 --- a/scripts/test-pricing-page-filtering.ts +++ b/scripts/test-pricing-page-filtering.ts @@ -47,7 +47,7 @@ async function testPricingPageFiltering() { console.log(` Visible plans: ${filteredPlans.length}`) filteredPlans.forEach(plan => { const isCurrent = scenario.userData?.subscriptionPlanId === plan.id - const canSubscribe = !isPlanFree(plan) && plan.stripePriceId && !isCurrent + const canSubscribe = !isPlanFree(plan) && !!plan.stripePriceId && !isCurrent console.log(` - ${plan.displayName}:`) console.log(` * Current plan: ${isCurrent}`) diff --git a/src/app/pricing/page.tsx b/src/app/pricing/page.tsx index e7916c2..8207d19 100644 --- a/src/app/pricing/page.tsx +++ b/src/app/pricing/page.tsx @@ -30,16 +30,22 @@ export default function PricingPage() { const response = await fetch('/api/subscription-plans') if (response.ok) { const data = await response.json() - // 过滤套餐:只显示免费套餐、用户当前套餐,以及有 stripePriceId 的套餐 + // 过滤套餐:只显示真正的免费套餐、用户当前套餐,以及有 stripePriceId 的付费套餐 const filteredPlans = (data.plans || []).filter((plan: SubscriptionPlan) => { - // 免费套餐总是显示 - if (isPlanFree(plan)) return true + // 只显示官方的免费套餐(ID为'free'或名称为'free') + if (isPlanFree(plan) && (plan.id === 'free' || plan.name.toLowerCase() === 'free')) { + return true + } - // 用户当前套餐总是显示 + // 用户当前套餐总是显示(即使是异常套餐) if (userData && isCurrentPlan(plan.id)) return true - // 其他套餐必须有 stripePriceId 才能显示(可订阅) - return plan.stripePriceId && plan.stripePriceId.trim() !== '' + // 付费套餐必须有 stripePriceId 才能显示(可订阅) + if (!isPlanFree(plan) && plan.stripePriceId && plan.stripePriceId.trim() !== '') { + return true + } + + return false }) setPlans(filteredPlans) }