Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"@nestjs/mongoose": "^11.0.1",
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.0.11",
"@nestjs/schedule": "^6.0.1",
"@nestjs/swagger": "^11.0.6",
"@types/cookie-parser": "^1.4.9",
"@types/passport-google-oauth20": "^2.0.16",
Expand Down Expand Up @@ -51,7 +52,8 @@
"lint": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" && eslint --fix \"src/**/*.ts\" \"test/**/*.ts\"",
"lint:src": "prettier --write \"src/**/*.ts\" && eslint --fix \"src/**/*.ts\"",
"lint:test": "prettier --write \"test/**/*.ts\" && eslint --fix \"test/**/*.ts\"",
"seed": "ts-node -r tsconfig-paths/register scripts/seeds/index.ts"
"seed": "ts-node -r tsconfig-paths/register scripts/seeds/index.ts",
"seed:plan": "ts-node -r tsconfig-paths/register scripts/seeds/seed-plan.ts"
},
"devDependencies": {
"@darraghor/eslint-plugin-nestjs-typed": "^6.4.12",
Expand Down
35 changes: 35 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 29 additions & 5 deletions scripts/seeds/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@
- **用途**: 创建电话系统测试数据,包括用户、公司和服务
- **运行命令**: `npm run seed:telephony`

### 3. 全部Seed (`seed:all`)
### 3. Plan Seed (`seed:plan`)
- **文件**: `seed-plan-data.ts`
- **用途**: 创建计划数据(FREE, BASIC, PRO计划)
- **运行命令**: `npm run seed:plan`
- **说明**:
- 脚本会检查计划是否已存在,如果存在则更新,如果不存在则创建
- 需要在 `seed-plan-data.ts` 中更新 UAT 数据(价格、Stripe价格ID、功能等)

### 4. 全部Seed (`seed:all`)
- **用途**: 运行所有seed脚本
- **运行命令**: `npm run seed:all` 或 `npm run seed`

Expand All @@ -27,6 +35,9 @@ npm run seed:calllog

# 只运行telephony数据
npm run seed:telephony

# 只运行plan数据
npm run seed:plan
```

### 运行所有Seed
Expand All @@ -53,12 +64,23 @@ npm run seed
4. Carpet Cleaning - $100
5. Window Cleaning - $90

### Plan测试数据
- 创建三个计划: FREE, BASIC, PRO
- 每个计划包含:
- 名称和层级
- 定价选项(月度、季度、年度等)
- 功能(通话分钟数、支持级别)
- Stripe价格ID
- **注意**: 使用前需要在 `seed-plan-data.ts` 中更新UAT数据

## 注意事项

1. 运行seed脚本会清除现有的测试数据
2. 确保MongoDB连接正常
3. 确保环境变量配置正确
4. 每个seed脚本都可以独立运行
1. 运行seed脚本可能会清除现有的测试数据(calllog和telephony seed)
2. Plan seed会更新现有计划,如果计划不存在则创建新计划(不会删除现有计划)
3. 确保MongoDB连接正常
4. 确保环境变量配置正确
5. 每个seed脚本都可以独立运行
6. **Plan Seed使用前**: 请先在 `seed-plan-data.ts` 中更新UAT数据,包括价格、Stripe价格ID和功能描述

## 文件结构

Expand All @@ -67,9 +89,11 @@ scripts/seeds/
├── index.ts # 主入口文件,导入所有seed
├── seed-calllog.ts # Calllog seed入口
├── seed-telephony.ts # Telephony seed入口
├── seed-plan.ts # Plan seed入口
├── run-calllog-seed.ts # Calllog seed运行脚本
├── run-telephony-seed.ts # Telephony seed运行脚本
├── seed-inbox-data.ts # Calllog测试数据
├── seed-telephony-test-data.ts # Telephony测试数据
├── seed-plan-data.ts # Plan测试数据
└── README.md # 本文档
```
3 changes: 2 additions & 1 deletion scripts/seeds/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
import './seed-calllog';
import './seed-telephony';
import './seed-telephony';
import './seed-plan';
175 changes: 175 additions & 0 deletions scripts/seeds/seed-plan-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { connect, connection, model, Schema } from 'mongoose';

const MONGODB_URI =
process.env.MONGODB_URI || 'mongodb://localhost:27017/dispatchai';

// Plan Schema
const planSchema = new Schema(
{
name: { type: String, required: true, unique: true },
tier: {
type: String,
required: true,
enum: ['FREE', 'BASIC', 'PRO'],
},
pricing: [
{
rrule: { type: String, required: true },
price: { type: Number, required: true },
stripePriceId: { type: String, required: true },
},
],
features: {
callMinutes: { type: String, required: true },
support: { type: String, required: true },
},
isActive: { type: Boolean, default: true },
},
{ timestamps: true },
);

// Plan data configuration
// Updated with UAT data
const planData = {
FREE: {
name: 'Free Plan',
tier: 'FREE' as const,
pricing: [
{
rrule: 'FREQ=MONTHLY;INTERVAL=1',
price: 0,
stripePriceId: 'price_free_monthly', // Update with real Stripe price ID
},
],
features: {
callMinutes: '100 minutes',
support: 'Email support',
},
isActive: true,
},
BASIC: {
name: 'Basic Plan',
tier: 'BASIC' as const,
pricing: [
{
rrule: 'FREQ=MONTHLY;INTERVAL=1',
price: 19,
stripePriceId: 'price_1S4yeoR2XtOFzYzKH32PKqPk',
},
],
features: {
callMinutes: '100 Min/Month',
support: 'Automatic Summary',
},
isActive: true,
},
PRO: {
name: 'Pro Plan',
tier: 'PRO' as const,
pricing: [
{
rrule: 'FREQ=MONTHLY;INTERVAL=1',
price: 79,
stripePriceId: 'price_1S4yexR2XtOFzYzKm5w8RRrc',
},
],
features: {
callMinutes: '1000 Min/Month',
support: 'Automatic Summary + Service Booking',
},
isActive: true,
},
};

async function seedPlanData() {
try {
await connect(MONGODB_URI);
console.log('✅ Connected to MongoDB');

const PlanModel = model('Plan', planSchema);

// Seed each plan
const plans = ['FREE', 'BASIC', 'PRO'] as const;

for (const tier of plans) {
const planConfig = planData[tier];

// Check if plan already exists
const existingPlan = await PlanModel.findOne({ tier }).exec();

if (existingPlan) {
console.log(`🔄 Updating existing ${tier} plan...`);
await PlanModel.findOneAndUpdate(
{ tier },
planConfig,
{
new: true,
upsert: false,
runValidators: true,
},
).exec();
console.log(`✅ Updated ${tier} plan: ${planConfig.name}`);
} else {
console.log(`➕ Creating new ${tier} plan...`);
await PlanModel.create(planConfig);
console.log(`✅ Created ${tier} plan: ${planConfig.name}`);
}
}

// Display all plans
console.log('\n📋 All Plans:');
const allPlans = await PlanModel.find({ isActive: true })
.sort({ tier: 1 })
.exec();

allPlans.forEach(plan => {
console.log(`\n${plan.tier} - ${plan.name}`);
console.log(` Features:`);
if (plan.features) {
console.log(` - Call Minutes: ${plan.features.callMinutes}`);
console.log(` - Support: ${plan.features.support}`);
} else {
console.log(` - Features not available`);
}
console.log(` Pricing:`);
plan.pricing?.forEach(pricing => {
const period = pricing.rrule.includes('INTERVAL=3')
? 'quarter'
: pricing.rrule.includes('FREQ=YEARLY')
? 'year'
: 'month';
console.log(
` - $${pricing.price}/${period} (Stripe: ${pricing.stripePriceId})`,
);
});
});

console.log('\n🚀 Plan Data Seeding Complete!');
} catch (error) {
console.error('❌ Error seeding plan data:', error);
throw error;
} finally {
await connection.close();
console.log('🔌 Disconnected from MongoDB');
}
}

// Export for use in other files
export { seedPlanData };

// If running directly
if (require.main === module) {
console.log('🚀 Starting Plan Data Seeding...');
console.log('=====================================');

seedPlanData()
.then(() => {
console.log('\n✅ Plan data seeding completed successfully!');
process.exit(0);
})
.catch((error: any) => {
console.error('❌ Failed to seed plan data:', error);
process.exit(1);
});
}

19 changes: 19 additions & 0 deletions scripts/seeds/seed-plan.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { seedPlanData } from './seed-plan-data';

console.log('🚀 Starting Plan Data Seeding...');
console.log('=====================================');

seedPlanData()
.then(() => {
console.log('\n✅ Plan data seeding completed successfully!');
console.log('\n📝 Next Steps:');
console.log('1. Verify plans in your database');
console.log('2. Update Stripe price IDs if needed');
console.log('3. Test plan subscription flows');
process.exit(0);
})
.catch((error: any) => {
console.error('❌ Failed to seed plan data:', error);
process.exit(1);
});

Loading