subscription

This commit is contained in:
2026-07-02 19:54:55 +03:30
parent d79fa12d65
commit d20e5be9c8
29 changed files with 1402 additions and 0 deletions
@@ -0,0 +1,191 @@
import {
MigrationInterface,
QueryRunner,
Table,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class AddSubscriptions1720400000000 implements MigrationInterface {
name = 'AddSubscriptions1720400000000';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "public"."salon_subscriptions_status_enum" AS ENUM('active', 'expired', 'cancelled')`,
);
await queryRunner.createTable(
new Table({
name: 'subscription_plans',
columns: [
{
name: 'id',
type: 'uuid',
isPrimary: true,
generationStrategy: 'uuid',
default: 'gen_random_uuid()',
},
{ name: 'name', type: 'varchar', length: '100' },
{ name: 'code', type: 'varchar', length: '50', isUnique: true },
{ name: 'durationMonths', type: 'int' },
{ name: 'price', type: 'bigint' },
{ name: 'freeSmsCount', type: 'int' },
{ name: 'isActive', type: 'boolean', default: true },
{ name: 'createdAt', type: 'timestamp', default: 'now()' },
{ name: 'updatedAt', type: 'timestamp', default: 'now()' },
],
}),
true,
);
await queryRunner.createTable(
new Table({
name: 'sms_packages',
columns: [
{
name: 'id',
type: 'uuid',
isPrimary: true,
generationStrategy: 'uuid',
default: 'gen_random_uuid()',
},
{ name: 'name', type: 'varchar', length: '100' },
{ name: 'code', type: 'varchar', length: '50', isUnique: true },
{ name: 'smsCount', type: 'int' },
{ name: 'price', type: 'bigint' },
{ name: 'isActive', type: 'boolean', default: true },
{ name: 'createdAt', type: 'timestamp', default: 'now()' },
{ name: 'updatedAt', type: 'timestamp', default: 'now()' },
],
}),
true,
);
await queryRunner.createTable(
new Table({
name: 'salon_subscriptions',
columns: [
{
name: 'id',
type: 'uuid',
isPrimary: true,
generationStrategy: 'uuid',
default: 'gen_random_uuid()',
},
{ name: 'salonId', type: 'uuid' },
{ name: 'planId', type: 'uuid' },
{
name: 'status',
type: 'salon_subscriptions_status_enum',
default: `'active'`,
},
{ name: 'startDate', type: 'timestamp' },
{ name: 'endDate', type: 'timestamp' },
{ name: 'pricePaid', type: 'bigint' },
{ name: 'freeSmsGranted', type: 'int' },
{ name: 'freeSmsRemaining', type: 'int' },
{ name: 'createdAt', type: 'timestamp', default: 'now()' },
{ name: 'updatedAt', type: 'timestamp', default: 'now()' },
],
}),
true,
);
await queryRunner.createTable(
new Table({
name: 'salon_sms_purchases',
columns: [
{
name: 'id',
type: 'uuid',
isPrimary: true,
generationStrategy: 'uuid',
default: 'gen_random_uuid()',
},
{ name: 'salonId', type: 'uuid' },
{ name: 'packageId', type: 'uuid' },
{ name: 'smsCount', type: 'int' },
{ name: 'smsRemaining', type: 'int' },
{ name: 'pricePaid', type: 'bigint' },
{ name: 'createdAt', type: 'timestamp', default: 'now()' },
{ name: 'updatedAt', type: 'timestamp', default: 'now()' },
],
}),
true,
);
await queryRunner.createForeignKey(
'salon_subscriptions',
new TableForeignKey({
columnNames: ['salonId'],
referencedTableName: 'salons',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'salon_subscriptions',
new TableForeignKey({
columnNames: ['planId'],
referencedTableName: 'subscription_plans',
referencedColumnNames: ['id'],
onDelete: 'RESTRICT',
}),
);
await queryRunner.createForeignKey(
'salon_sms_purchases',
new TableForeignKey({
columnNames: ['salonId'],
referencedTableName: 'salons',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'salon_sms_purchases',
new TableForeignKey({
columnNames: ['packageId'],
referencedTableName: 'sms_packages',
referencedColumnNames: ['id'],
onDelete: 'RESTRICT',
}),
);
await queryRunner.createIndex(
'salon_subscriptions',
new TableIndex({
name: 'IDX_salon_subscriptions_salonId_status',
columnNames: ['salonId', 'status'],
}),
);
await queryRunner.query(`
INSERT INTO subscription_plans (name, code, "durationMonths", price, "freeSmsCount")
VALUES
('شروع رشد', 'start-growth', 3, 1990000, 500),
('رشد پایدار', 'stable-growth', 6, 3790000, 1200),
('حرفه‌ای', 'professional', 12, 6990000, 3000)
`);
await queryRunner.query(`
INSERT INTO sms_packages (name, code, "smsCount", price)
VALUES
('بسته پایه', 'basic', 1000, 390000),
('بسته حرفه‌ای', 'professional', 5000, 1850000),
('بسته ویژه', 'special', 10000, 3400000)
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('salon_sms_purchases', true);
await queryRunner.dropTable('salon_subscriptions', true);
await queryRunner.dropTable('sms_packages', true);
await queryRunner.dropTable('subscription_plans', true);
await queryRunner.query(
`DROP TYPE "public"."salon_subscriptions_status_enum"`,
);
}
}