This commit is contained in:
2025-11-10 23:23:44 +03:30
parent 6a25bf9116
commit 4c274c3118
7 changed files with 257 additions and 0 deletions
+2
View File
@@ -14,6 +14,7 @@ import { UploaderModule } from './modules/uploader/uploader.module';
import { AdminModule } from './modules/admin/admin.module';
// import { CacheService } from './modules/utils/cache.service';
import { ThrottlerModule } from '@nestjs/throttler';
import { RestaurantsModule } from './modules/restaurants/restaurants.module';
@Module({
imports: [
@@ -41,6 +42,7 @@ import { ThrottlerModule } from '@nestjs/throttler';
limit: 5, // max requests per window
},
]),
RestaurantsModule,
],
controllers: [],
// providers: [CacheService],
@@ -0,0 +1,97 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsString, IsOptional, IsNumber, IsBoolean, IsArray, IsUrl } from 'class-validator';
export class CreateRestaurantDto {
@ApiProperty({ example: 'Cafe Morteza' })
@IsString()
name!: string;
@ApiProperty({ example: 'cafe-morteza' })
@IsString()
slug!: string;
@ApiPropertyOptional({ example: 'https://example.com/logo.png' })
@IsOptional()
@IsUrl()
logo?: string;
@ApiPropertyOptional({ example: 'Tehran, Valiasr St. No. 123' })
@IsOptional()
@IsString()
address?: string;
@ApiPropertyOptional({ example: '#ff6600' })
@IsOptional()
@IsString()
menuColor?: string;
@ApiPropertyOptional({ example: 35.6892 })
@IsOptional()
@IsNumber()
latitude?: number;
@ApiPropertyOptional({ example: 51.389 })
@IsOptional()
@IsNumber()
longitude?: number;
@ApiPropertyOptional({ example: 5000, description: 'Service area in meters' })
@IsOptional()
@IsNumber()
serviceArea?: number;
@ApiPropertyOptional({ example: 2020 })
@IsOptional()
@IsNumber()
establishedYear?: number;
@ApiPropertyOptional({ example: '+989123456789' })
@IsOptional()
@IsString()
phoneNumber?: string;
@ApiPropertyOptional({ example: 'https://instagram.com/cafemorteza' })
@IsOptional()
@IsUrl()
instagram?: string;
@ApiPropertyOptional({ example: 'https://t.me/cafemorteza' })
@IsOptional()
@IsUrl()
telegram?: string;
@ApiPropertyOptional({ example: 'https://wa.me/989123456789' })
@IsOptional()
@IsUrl()
whatsapp?: string;
@ApiPropertyOptional({ example: 'Cozy place with best coffee in town.' })
@IsOptional()
@IsString()
description?: string;
@ApiPropertyOptional({ example: 'Best Cafe in Tehran' })
@IsOptional()
@IsString()
seoTitle?: string;
@ApiPropertyOptional({ example: 'Cafe Morteza serves high-quality coffee.' })
@IsOptional()
@IsString()
seoDescription?: string;
@ApiPropertyOptional({ example: ['coffee', 'breakfast', 'cafe'] })
@IsOptional()
@IsArray()
tagNames?: string[];
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isOpenNow?: boolean;
@ApiPropertyOptional({ example: 0.09 })
@IsOptional()
@IsNumber()
vat?: number;
}
@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/swagger';
import { CreateRestaurantDto } from './create-restaurant.dto';
export class UpdateRestaurantDto extends PartialType(CreateRestaurantDto) {}
@@ -0,0 +1,69 @@
import { Entity, Property } from '@mikro-orm/core';
import { BaseEntity } from '../../../common/entities/base.entity';
@Entity({ tableName: 'restaurants' })
export class Restaurant extends BaseEntity {
// --- اطلاعات پایه ---
@Property()
name!: string;
@Property({ unique: true })
slug!: string;
@Property({ nullable: true })
logo?: string;
@Property({ nullable: true })
address?: string;
@Property({ nullable: true })
menuColor?: string;
// --- مختصات جغرافیایی ---
@Property({ nullable: true })
latitude?: number;
@Property({ nullable: true })
longitude?: number;
// --- شعاع خدمات (مثلاً بر حسب متر یا کیلومتر) ---
@Property({ nullable: true })
serviceArea?: number;
// --- وضعیت‌ها ---
@Property({ default: true })
isActive: boolean = true;
@Property({ nullable: true })
establishedYear?: number;
@Property({ nullable: true })
phoneNumber?: string;
@Property({ nullable: true })
instagram?: string;
@Property({ nullable: true })
telegram?: string;
@Property({ nullable: true })
whatsapp?: string;
// --- توضیحات ---
@Property({ type: 'text', nullable: true })
description?: string;
// --- سئو ---
@Property({ nullable: true })
seoTitle?: string;
@Property({ nullable: true, type: 'text' })
seoDescription?: string;
@Property({ nullable: true, type: 'json' })
tagNames?: string[];
// --- مالیات یا VAT ---
@Property({ type: 'decimal', default: 0 })
vat?: number = 0;
}
@@ -0,0 +1,34 @@
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { RestaurantsService } from './restaurants.service';
import { CreateRestaurantDto } from './dto/create-restaurant.dto';
import { UpdateRestaurantDto } from './dto/update-restaurant.dto';
@Controller('restaurants')
export class RestaurantsController {
constructor(private readonly restaurantsService: RestaurantsService) {}
@Post()
create(@Body() createRestaurantDto: CreateRestaurantDto) {
return this.restaurantsService.create(createRestaurantDto);
}
@Get()
findAll() {
return this.restaurantsService.findAll();
}
@Get(':slug')
findOne(@Param('slug') slug: string) {
return this.restaurantsService.findBySlug(slug);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateRestaurantDto: UpdateRestaurantDto) {
return this.restaurantsService.update(+id, updateRestaurantDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.restaurantsService.remove(+id);
}
}
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { RestaurantsService } from './restaurants.service';
import { RestaurantsController } from './restaurants.controller';
@Module({
controllers: [RestaurantsController],
providers: [RestaurantsService],
})
export class RestaurantsModule {}
@@ -0,0 +1,42 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateRestaurantDto } from './dto/create-restaurant.dto';
import { UpdateRestaurantDto } from './dto/update-restaurant.dto';
import { Restaurant } from './entities/restaurant.entity';
import { EntityManager } from '@mikro-orm/postgresql';
@Injectable()
export class RestaurantsService {
constructor(private readonly em: EntityManager) {}
async create(dto: CreateRestaurantDto): Promise<Restaurant> {
const restaurant = this.em.create(Restaurant, {
...dto,
isActive: true,
});
await this.em.persistAndFlush(restaurant);
return restaurant;
}
findAll() {
return `This action returns all restaurants`;
}
async findBySlug(slug: string): Promise<Restaurant> {
const restaurant = await this.em.findOne(Restaurant, { slug });
if (!restaurant) {
throw new NotFoundException(`Restaurant with slug "${slug}" not found`);
}
return restaurant;
}
update(id: number, updateRestaurantDto: UpdateRestaurantDto) {
return `This action updates a #${id} restaurant`;
}
remove(id: number) {
return `This action removes a #${id} restaurant`;
}
}