diff --git a/database/migrations/.snapshot-dmenu.json b/database/migrations/.snapshot-dmenu.json index 71c052f..7bcefce 100644 --- a/database/migrations/.snapshot-dmenu.json +++ b/database/migrations/.snapshot-dmenu.json @@ -864,15 +864,14 @@ "nullable": true, "mappedType": "integer" }, - "phone": { - "name": "phone", - "type": "varchar(255)", + "phones": { + "name": "phones", + "type": "jsonb", "unsigned": false, "autoincrement": false, "primary": false, "nullable": true, - "length": 255, - "mappedType": "string" + "mappedType": "json" }, "instagram": { "name": "instagram", @@ -1246,66 +1245,6 @@ "length": 255, "mappedType": "string" }, - "card_number": { - "name": "card_number", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "length": 255, - "mappedType": "string" - }, - "card_number2": { - "name": "card_number2", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "length": 255, - "mappedType": "string" - }, - "card_number3": { - "name": "card_number3", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "length": 255, - "mappedType": "string" - }, - "card_owner": { - "name": "card_owner", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "length": 255, - "mappedType": "string" - }, - "card_owner2": { - "name": "card_owner2", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "length": 255, - "mappedType": "string" - }, - "card_owner3": { - "name": "card_owner3", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "length": 255, - "mappedType": "string" - }, "enabled": { "name": "enabled", "type": "boolean", @@ -1420,6 +1359,142 @@ }, "nativeEnums": {} }, + { + "columns": { + "id": { + "name": "id", + "type": "char(26)", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 26, + "mappedType": "character" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" + }, + "payment_method_id": { + "name": "payment_method_id", + "type": "char(26)", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 26, + "mappedType": "character" + }, + "card_number": { + "name": "card_number", + "type": "varchar(255)", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 255, + "mappedType": "string" + }, + "owner": { + "name": "owner", + "type": "varchar(255)", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 255, + "mappedType": "string" + } + }, + "name": "payment_method_cards", + "schema": "public", + "indexes": [ + { + "keyName": "payment_method_cards_created_at_index", + "columnNames": [ + "created_at" + ], + "composite": false, + "constraint": false, + "primary": false, + "unique": false + }, + { + "keyName": "payment_method_cards_deleted_at_index", + "columnNames": [ + "deleted_at" + ], + "composite": false, + "constraint": false, + "primary": false, + "unique": false + }, + { + "keyName": "payment_method_cards_payment_method_id_index", + "columnNames": [ + "payment_method_id" + ], + "composite": false, + "constraint": false, + "primary": false, + "unique": false + }, + { + "keyName": "payment_method_cards_pkey", + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": { + "payment_method_cards_payment_method_id_foreign": { + "constraintName": "payment_method_cards_payment_method_id_foreign", + "columnNames": [ + "payment_method_id" + ], + "localTableName": "public.payment_method_cards", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.payment_methods", + "updateRule": "cascade" + } + }, + "nativeEnums": {} + }, { "columns": { "id": { @@ -5491,26 +5566,6 @@ "length": 255, "mappedType": "string" }, - "city": { - "name": "city", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "length": 255, - "mappedType": "string" - }, - "province": { - "name": "province", - "type": "varchar(255)", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "length": 255, - "mappedType": "string" - }, "postal_code": { "name": "postal_code", "type": "varchar(255)", diff --git a/database/migrations/Migration20260629083652_phonesRestuarant.ts b/database/migrations/Migration20260629083652_phonesRestuarant.ts new file mode 100644 index 0000000..c43b53e --- /dev/null +++ b/database/migrations/Migration20260629083652_phonesRestuarant.ts @@ -0,0 +1,14 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20260629083652_phonesRestuarant extends Migration { + + override async up(): Promise { + this.addSql(`alter table "restaurants" add column "phones" jsonb null;`); + } + + override async down(): Promise { + this.addSql(`alter table "restaurants" add column "phone" varchar(255) null;`); + + } + +} diff --git a/src/modules/restaurants/controllers/restaurants.controller.ts b/src/modules/restaurants/controllers/restaurants.controller.ts index 65245af..07ecfbb 100644 --- a/src/modules/restaurants/controllers/restaurants.controller.ts +++ b/src/modules/restaurants/controllers/restaurants.controller.ts @@ -1,6 +1,6 @@ import { Controller, Get, Post, Body, Patch, Param, UseGuards, Delete, Query } from '@nestjs/common'; import { RestaurantsService } from '../providers/restaurants.service'; -import { CreateRestaurantDto } from '../dto/create-restaurant.dto'; +import { SetupRestaurantDto } from '../dto/setup-restaurant.dto'; import { UpdateRestaurantDto } from '../dto/update-restaurant.dto'; import { UpgradeSubscriptionDto } from '../dto/upgrade-subscription.dto'; import { FindRestaurantsDto } from '../dto/find-restaurants.dto'; @@ -108,10 +108,11 @@ export class RestaurantsController { @UseGuards(SuperAdminAuthGuard) @ApiBearerAuth() - @ApiOperation({ summary: 'Create a new restaurant' }) + @ApiOperation({ summary: 'Setup a new restaurant' }) + @ApiBody({ type: SetupRestaurantDto }) @Post('super-admin/restaurants') - createRestaurant(@Body() createRestaurantDto: CreateRestaurantDto) { - return this.restaurantsService.setupRestuarant(createRestaurantDto); + setupRestaurant(@Body() setupRestaurantDto: SetupRestaurantDto) { + return this.restaurantsService.setupRestuarant(setupRestaurantDto); } @UseGuards(SuperAdminAuthGuard) diff --git a/src/modules/restaurants/dto/create-restaurant.dto.ts b/src/modules/restaurants/dto/create-restaurant.dto.ts index fbfb106..632d6da 100644 --- a/src/modules/restaurants/dto/create-restaurant.dto.ts +++ b/src/modules/restaurants/dto/create-restaurant.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { IsString, IsOptional, IsNumber, IsDate, IsEnum, IsBoolean } from 'class-validator'; +import { IsString, IsOptional, IsNumber, IsDate, IsEnum, IsBoolean, IsArray } from 'class-validator'; import { Type } from 'class-transformer'; import { PlanEnum } from '../interface/plan.interface'; @@ -23,10 +23,11 @@ export class CreateRestaurantDto { @IsNumber() establishedYear: number; - @ApiPropertyOptional({ example: '09123456789', description: 'شماره تلفن' }) + @ApiPropertyOptional({ example: ['09123456789', '09123456789'], description: 'شماره تلفن' }) @IsOptional() - @IsString() - phone: string; + @IsArray() + @IsString({ each: true }) + phones?: string[]; @ApiProperty({ example: 'base', enum: PlanEnum, description: 'پلن رستوران' }) @IsEnum(PlanEnum) diff --git a/src/modules/restaurants/dto/setup-restaurant.dto.ts b/src/modules/restaurants/dto/setup-restaurant.dto.ts new file mode 100644 index 0000000..eadfbe5 --- /dev/null +++ b/src/modules/restaurants/dto/setup-restaurant.dto.ts @@ -0,0 +1,54 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { IsString, IsOptional, IsNumber, IsDate, IsEnum, IsBoolean } from 'class-validator'; +import { Type } from 'class-transformer'; +import { PlanEnum } from '../interface/plan.interface'; + +export class SetupRestaurantDto { + @ApiProperty({ example: 'کافه ژیوان', description: 'نام رستوران' }) + @IsString() + name!: string; + + @ApiPropertyOptional({ example: 'zhivan', description: 'شناسه (slug) رستوران، لاتین و بدون فاصله (اختیاری - در صورت عدم ارسال، از نام رستوران تولید می‌شود)' }) + @IsOptional() + @IsString() + slug?: string; + + @ApiPropertyOptional({ example: 'zhivan.dmenu.ir', description: 'دامنه اختصاصی رستوران' }) + @IsOptional() + @IsString() + domain?: string; + + @ApiPropertyOptional({ example: 2020, description: 'سال تأسیس' }) + @IsOptional() + @IsNumber() + establishedYear: number; + + @ApiPropertyOptional({ example: '09123456789', description: 'شماره تلفن' }) + @IsOptional() + @IsString() + phone?: string; + + @ApiProperty({ example: 'base', enum: PlanEnum, description: 'پلن رستوران' }) + @IsEnum(PlanEnum) + plan!: PlanEnum; + + @ApiProperty({ example: 'sub_1234567890', description: 'شناسه اشتراک' }) + @IsString() + subscriptionId!: string; + + @ApiProperty({ example: '2025-12-26', description: 'تاریخ انقضای اشتراک' }) + @Type(() => Date) + @IsDate() + subscriptionEndDate!: Date; + + @ApiProperty({ example: '2025-12-26', description: 'تاریخ شروع اشتراک' }) + @Type(() => Date) + @IsDate() + subscriptionStartDate!: Date; + + + @ApiProperty() + @IsBoolean() + isActive?: boolean; + +} diff --git a/src/modules/restaurants/entities/restaurant.entity.ts b/src/modules/restaurants/entities/restaurant.entity.ts index fd4ad2f..1ca8e7d 100644 --- a/src/modules/restaurants/entities/restaurant.entity.ts +++ b/src/modules/restaurants/entities/restaurant.entity.ts @@ -43,8 +43,8 @@ export class Restaurant extends BaseEntity { @Property({ nullable: true }) establishedYear?: number; - @Property({ nullable: true }) - phone?: string; + @Property({ nullable: true, type: 'json' }) + phones?: string[]; @Property({ nullable: true }) instagram?: string; diff --git a/src/modules/restaurants/providers/restaurants.service.ts b/src/modules/restaurants/providers/restaurants.service.ts index f4a7860..9e2acc8 100644 --- a/src/modules/restaurants/providers/restaurants.service.ts +++ b/src/modules/restaurants/providers/restaurants.service.ts @@ -1,5 +1,5 @@ import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; -import { CreateRestaurantDto } from '../dto/create-restaurant.dto'; +import { SetupRestaurantDto } from '../dto/setup-restaurant.dto'; import { UpdateRestaurantDto } from '../dto/update-restaurant.dto'; import { UpdateRestaurantBgDto } from '../dto/update-restaurant-bg.dto'; import { UpgradeSubscriptionDto } from '../dto/upgrade-subscription.dto'; @@ -43,7 +43,7 @@ export class RestaurantsService { private readonly cacheService: CacheService, ) { } - async setupRestuarant(dto: CreateRestaurantDto): Promise { + async setupRestuarant(dto: SetupRestaurantDto): Promise { return await this.em.transactional(async (em) => { // Generate or validate slug const slug = slugify(dto.slug ?? dto.name, { @@ -63,7 +63,7 @@ export class RestaurantsService { name: dto.name, slug, establishedYear: dto.establishedYear, - phone: dto.phone, + phones: dto.phone ? [dto.phone] : undefined, isActive: true, plan: dto.plan, domain: `https://dmenu.danakcorp.com/${slug}`, @@ -79,7 +79,7 @@ export class RestaurantsService { throw new BadRequestException(`Role not found for plan: ${dto.plan}`); } - const normalizedPhone = normalizePhone(dto.phone); + const normalizedPhone = normalizePhone(dto.phone ?? ''); let admin = await em.findOne(Admin, { phone: normalizedPhone }); if (!admin) { admin = em.create(Admin, {