const { Client } = require('pg'); require('dotenv').config(); // 使用DATABASE_URL如果可用,否则回退到个别配置 const client = new Client( process.env.DATABASE_URL || { host: process.env.DATABASE_HOST || 'localhost', port: process.env.DATABASE_PORT || 5432, database: process.env.DATABASE_NAME || 'meteor_db', user: process.env.DATABASE_USER || 'postgres', password: process.env.DATABASE_PASSWORD || 'password', } ); // 订阅计划数据 const subscriptionPlans = [ { plan_id: 'basic-monthly', name: '基础版(月付)', description: '适合个人用户的基础功能', price: 9.99, currency: 'CNY', interval: 'month', interval_count: 1, stripe_price_id: 'price_basic_monthly', features: JSON.stringify([ '基础数据访问', '10个设备连接', '基础天气数据', '标准技术支持', '7天数据保留' ]), is_popular: false, is_active: true }, { plan_id: 'pro-monthly', name: '专业版(月付)', description: '适合专业用户和小团队', price: 29.99, currency: 'CNY', interval: 'month', interval_count: 1, stripe_price_id: 'price_pro_monthly', features: JSON.stringify([ '高级数据分析', '无限设备连接', '实时数据流', '高级天气集成', '优先技术支持', '30天数据保留', '自定义报告', 'API访问权限' ]), is_popular: true, is_active: true }, { plan_id: 'pro-yearly', name: '专业版(年付)', description: '专业版年付,享受20%折扣', price: 287.99, currency: 'CNY', interval: 'year', interval_count: 1, stripe_price_id: 'price_pro_yearly', features: JSON.stringify([ '高级数据分析', '无限设备连接', '实时数据流', '高级天气集成', '优先技术支持', '30天数据保留', '自定义报告', 'API访问权限', '年付8折优惠' ]), is_popular: false, is_active: true }, { plan_id: 'enterprise-monthly', name: '企业版(月付)', description: '适合大型企业和研究机构', price: 99.99, currency: 'CNY', interval: 'month', interval_count: 1, stripe_price_id: 'price_enterprise_monthly', features: JSON.stringify([ '企业级数据分析', '无限设备和用户', '实时数据流', '完整天气数据', '24/7专属支持', '365天数据保留', '高级自定义报告', '完整API访问', '数据导出功能', '白标定制', 'SSO单点登录', '专属客户经理' ]), is_popular: false, is_active: true }, { plan_id: 'free-trial', name: '免费试用', description: '14天免费试用专业版功能', price: 0.00, currency: 'CNY', interval: 'month', interval_count: 1, stripe_price_id: null, features: JSON.stringify([ '14天试用期', '所有专业版功能', '最多5个设备', '基础技术支持', '试用期数据保留' ]), is_popular: false, is_active: true } ]; // 生成用户订阅数据 async function generateUserSubscriptions() { // 获取所有用户 const usersResult = await client.query('SELECT id FROM user_profiles ORDER BY id'); const users = usersResult.rows; if (users.length === 0) { console.log('No users found. Skipping user subscription generation.'); return []; } // 获取所有订阅计划 const plansResult = await client.query('SELECT id, plan_id FROM subscription_plans WHERE is_active = true'); const plans = plansResult.rows; const subscriptions = []; const subscriptionStatuses = ['active', 'canceled', 'past_due', 'trialing']; // 为部分用户创建订阅 (约70%的用户有订阅) const usersWithSubscriptions = users.filter(() => Math.random() < 0.7); for (const user of usersWithSubscriptions) { const randomPlan = plans[Math.floor(Math.random() * plans.length)]; const status = subscriptionStatuses[Math.floor(Math.random() * subscriptionStatuses.length)]; const now = new Date(); const currentPeriodStart = new Date(now.getTime() - Math.random() * 30 * 24 * 60 * 60 * 1000); // 过去30天内开始 const currentPeriodEnd = new Date(currentPeriodStart.getTime() + 30 * 24 * 60 * 60 * 1000); // 30天周期 let trialStart = null; let trialEnd = null; let canceledAt = null; if (status === 'trialing') { trialStart = currentPeriodStart; trialEnd = new Date(trialStart.getTime() + 14 * 24 * 60 * 60 * 1000); // 14天试用 } if (status === 'canceled') { canceledAt = new Date(currentPeriodStart.getTime() + Math.random() * 20 * 24 * 60 * 60 * 1000); } subscriptions.push({ user_profile_id: user.id, subscription_plan_id: randomPlan.id, stripe_subscription_id: `sub_${Math.random().toString(36).substr(2, 9)}`, // 模拟Stripe ID status: status, current_period_start: currentPeriodStart, current_period_end: currentPeriodEnd, cancel_at_period_end: status === 'canceled' ? true : Math.random() < 0.1, canceled_at: canceledAt, trial_start: trialStart, trial_end: trialEnd }); } return subscriptions; } // 生成订阅历史记录 function generateSubscriptionHistory(subscriptionId, subscriptionData) { const history = []; const actions = ['created', 'updated', 'renewed', 'payment_failed']; // 创建记录 history.push({ user_subscription_id: subscriptionId, action: 'created', old_status: null, new_status: 'active', metadata: JSON.stringify({ created_by: 'system', payment_method: 'card' }) }); // 添加一些随机历史记录 const numHistory = Math.floor(Math.random() * 3) + 1; // 1-3条记录 for (let i = 0; i < numHistory; i++) { const action = actions[Math.floor(Math.random() * actions.length)]; let oldStatus = 'active'; let newStatus = 'active'; if (action === 'payment_failed') { oldStatus = 'active'; newStatus = 'past_due'; } else if (action === 'renewed') { oldStatus = 'past_due'; newStatus = 'active'; } history.push({ user_subscription_id: subscriptionId, action: action, old_status: oldStatus, new_status: newStatus, metadata: JSON.stringify({ timestamp: new Date().toISOString(), source: 'stripe_webhook' }) }); } return history; } // 生成支付记录 function generatePaymentRecords(subscriptionId, subscriptionData) { const payments = []; const paymentStatuses = ['succeeded', 'failed', 'pending']; const paymentMethods = ['card', 'alipay', 'wechat_pay']; // 生成1-5条支付记录 const numPayments = Math.floor(Math.random() * 5) + 1; for (let i = 0; i < numPayments; i++) { const status = paymentStatuses[Math.floor(Math.random() * paymentStatuses.length)]; const amount = 29.99 + Math.random() * 70; // 随机金额 let paidAt = null; let failureReason = null; if (status === 'succeeded') { paidAt = new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000); } else if (status === 'failed') { failureReason = ['card_declined', 'insufficient_funds', 'expired_card'][Math.floor(Math.random() * 3)]; } payments.push({ user_subscription_id: subscriptionId, stripe_payment_intent_id: `pi_${Math.random().toString(36).substr(2, 9)}`, amount: amount, currency: 'CNY', status: status, payment_method: paymentMethods[Math.floor(Math.random() * paymentMethods.length)], failure_reason: failureReason, paid_at: paidAt }); } return payments; } async function seedSubscriptionData() { try { await client.connect(); console.log('Connected to database'); // 清空现有数据 console.log('Clearing existing subscription data...'); await client.query('DELETE FROM payment_records'); await client.query('DELETE FROM subscription_history'); await client.query('DELETE FROM user_subscriptions'); await client.query('DELETE FROM subscription_plans'); // 插入订阅计划数据 console.log('Inserting subscription plans...'); const planIds = []; for (const plan of subscriptionPlans) { const query = ` INSERT INTO subscription_plans ( plan_id, name, description, price, currency, interval, interval_count, stripe_price_id, features, is_popular, is_active ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id `; const values = [ plan.plan_id, plan.name, plan.description, plan.price, plan.currency, plan.interval, plan.interval_count, plan.stripe_price_id, plan.features, plan.is_popular, plan.is_active ]; const result = await client.query(query, values); const planId = result.rows[0].id; planIds.push(planId); console.log(`Inserted subscription plan: ${plan.name} (ID: ${planId})`); } // 生成用户订阅数据 console.log('Generating user subscriptions...'); const subscriptions = await generateUserSubscriptions(); for (const subscription of subscriptions) { const query = ` INSERT INTO user_subscriptions ( user_profile_id, subscription_plan_id, stripe_subscription_id, status, current_period_start, current_period_end, cancel_at_period_end, canceled_at, trial_start, trial_end ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING id `; const values = [ subscription.user_profile_id, subscription.subscription_plan_id, subscription.stripe_subscription_id, subscription.status, subscription.current_period_start, subscription.current_period_end, subscription.cancel_at_period_end, subscription.canceled_at, subscription.trial_start, subscription.trial_end ]; const result = await client.query(query, values); const subscriptionId = result.rows[0].id; // 生成订阅历史记录 const history = generateSubscriptionHistory(subscriptionId, subscription); for (const record of history) { const historyQuery = ` INSERT INTO subscription_history ( user_subscription_id, action, old_status, new_status, metadata ) VALUES ($1, $2, $3, $4, $5) `; const historyValues = [ record.user_subscription_id, record.action, record.old_status, record.new_status, record.metadata ]; await client.query(historyQuery, historyValues); } // 生成支付记录 const payments = generatePaymentRecords(subscriptionId, subscription); for (const payment of payments) { const paymentQuery = ` INSERT INTO payment_records ( user_subscription_id, stripe_payment_intent_id, amount, currency, status, payment_method, failure_reason, paid_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) `; const paymentValues = [ payment.user_subscription_id, payment.stripe_payment_intent_id, payment.amount, payment.currency, payment.status, payment.payment_method, payment.failure_reason, payment.paid_at ]; await client.query(paymentQuery, paymentValues); } console.log(`Generated subscription for user ${subscription.user_profile_id} with ${history.length} history records and ${payments.length} payment records`); } console.log('Subscription data seeding completed successfully!'); // 显示统计信息 const planCount = await client.query('SELECT COUNT(*) FROM subscription_plans'); const subscriptionCount = await client.query('SELECT COUNT(*) FROM user_subscriptions'); const historyCount = await client.query('SELECT COUNT(*) FROM subscription_history'); const paymentCount = await client.query('SELECT COUNT(*) FROM payment_records'); console.log(`Total subscription plans: ${planCount.rows[0].count}`); console.log(`Total user subscriptions: ${subscriptionCount.rows[0].count}`); console.log(`Total history records: ${historyCount.rows[0].count}`); console.log(`Total payment records: ${paymentCount.rows[0].count}`); } catch (error) { console.error('Error seeding subscription data:', error); process.exit(1); } finally { await client.end(); console.log('Database connection closed'); } } // 如果直接运行此脚本 if (require.main === module) { seedSubscriptionData(); } module.exports = { seedSubscriptionData };