diff --git a/src/app.module.ts b/src/app.module.ts index ffe1a03..6c27ef6 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -11,8 +11,8 @@ import { ThrottlerModule } from '@nestjs/throttler'; import { ScheduleModule } from '@nestjs/schedule'; import { productModule } from './modules/product/product.module'; import { RolesModule } from './modules/roles/roles.module'; -import { PaymentsModule } from './modules/payment/payments.module'; -import { OrdersModule } from './modules/order/orders.module'; +import { PaymentModule } from './modules/payment/payments.module'; +import { OrderModule } from './modules/order/orders.module'; import { NotificationsModule } from './modules/notification/notifications.module'; import { EventEmitterModule } from '@nestjs/event-emitter'; import { CacheModule } from '@nestjs/cache-manager'; @@ -37,8 +37,8 @@ import { cacheConfig } from './config/cache.config'; ScheduleModule.forRoot(), productModule, RolesModule, - PaymentsModule, - OrdersModule, + PaymentModule, + OrderModule, NotificationsModule, EventEmitterModule.forRoot(), ], diff --git a/src/modules/order/controllers/orders.controller.ts b/src/modules/order/controllers/orders.controller.ts index c062a68..8bc0272 100644 --- a/src/modules/order/controllers/orders.controller.ts +++ b/src/modules/order/controllers/orders.controller.ts @@ -18,7 +18,7 @@ export class OrdersController { constructor(private readonly ordersService: OrdersService) { } @Post('public/checkout') - // @UseGuards(AuthGuard) + @UseGuards(AuthGuard) @ApiOperation({ summary: 'Checkout : create order ' }) @ApiBody({ type: CreateOrderDto }) checkout(@UserId() userId: string, @Body() body: CreateOrderDto) { diff --git a/src/modules/order/dto/create-order.dto.ts b/src/modules/order/dto/create-order.dto.ts index f19b74b..1756adc 100644 --- a/src/modules/order/dto/create-order.dto.ts +++ b/src/modules/order/dto/create-order.dto.ts @@ -1,20 +1,12 @@ -import { IsString, IsOptional, IsBoolean, IsInt, Min, IsArray, IsNumber } from 'class-validator'; +import { + IsString, IsOptional, IsBoolean, + IsInt, Min, IsArray, IsNumber, + IsNotEmpty, + ArrayMinSize +} from 'class-validator'; import { ApiPropertyOptional, ApiProperty } from '@nestjs/swagger'; import { Type } from 'class-transformer'; -export class CreateOrderDto { - @IsArray() - @ApiProperty({ isArray: true }) - items: CreateOrderItemDto[]; - - @IsString() - content: string - - @IsArray() - @IsString({ each: true }) - attachments: string[] -} - export class CreateOrderItemDto { @IsInt() @@ -22,8 +14,37 @@ export class CreateOrderItemDto { productId: bigint; @ApiProperty() + @IsNumber() quantity: number + @ApiProperty() @IsArray() attributesValues: string[] -} \ No newline at end of file +} + +export class CreateOrderDto { + @IsArray() + @ApiProperty({ + isArray: true, type: [CreateOrderItemDto], example: [ + { + productId: 1, + quantity: 100, + attributesValues: [] + } + ] + }) + @IsNotEmpty() + @ArrayMinSize(1, { message: 'At least one product is required' }) + @Type(() => CreateOrderItemDto) + items: CreateOrderItemDto[]; + + @ApiPropertyOptional({ example: 'توضیحات' }) + @IsString() + content: string + + @ApiPropertyOptional({ example: [] }) + @IsArray() + @IsString({ each: true }) + attachments: string[] +} + diff --git a/src/modules/order/orders.module.ts b/src/modules/order/orders.module.ts index 9005dd4..3b8a52b 100644 --- a/src/modules/order/orders.module.ts +++ b/src/modules/order/orders.module.ts @@ -4,11 +4,8 @@ import { OrdersService } from './providers/orders.service'; import { OrdersController } from './controllers/orders.controller'; import { Order } from './entities/order.entity'; import { OrderItem } from './entities/order-item.entity'; -import { User } from '../user/entities/user.entity'; -import { Product } from '../product/entities/product.entity'; -import { UserAddress } from '../user/entities/user-address.entity'; import { AuthModule } from '../auth/auth.module'; -import { PaymentsModule } from '../payment/payments.module'; +import { PaymentModule } from '../payment/payments.module'; import { JwtModule } from '@nestjs/jwt'; import { OrderRepository } from './repositories/order.repository'; import { OrderListeners } from './listeners/order.listeners'; @@ -25,19 +22,18 @@ import { OrderItemRepository } from './repositories/order-item.repository'; imports: [ MikroOrmModule.forFeature([Order, OrderItem]), AuthModule, - forwardRef(() => PaymentsModule), + forwardRef(() => PaymentModule), JwtModule, AdminModule, NotificationsModule, UtilsModule, forwardRef(() => UserModule), - // PaymentsModule, productModule, TicketModule ], controllers: [OrdersController], - providers: [OrdersService, OrderRepository, OrderListeners, - OrdersCrone,OrderItemRepository], + providers: [OrdersService, OrderRepository, OrderListeners, + OrdersCrone, OrderItemRepository], exports: [OrderRepository, OrdersService], }) -export class OrdersModule { } +export class OrderModule { } diff --git a/src/modules/order/providers/orders.service.ts b/src/modules/order/providers/orders.service.ts index 4b7d0a5..cc510d4 100644 --- a/src/modules/order/providers/orders.service.ts +++ b/src/modules/order/providers/orders.service.ts @@ -48,7 +48,8 @@ export class OrdersService { async createOrder(userId: string, dto: CreateOrderDto) { const { attachments, content, items } = dto - this.em.transactional(async (em) => { + + const order = await this.em.transactional(async (em) => { const user = await this.userService.findById(userId) if (!user) { throw new BadRequestException("user not found") @@ -95,14 +96,17 @@ export class OrdersService { content, user, attachments, - status: TicketStatus.PENDING + status: TicketStatus.PENDING, + admin: null }) em.persist(ticket) - em.flush() + await em.flush() + return order }) + return order } } diff --git a/src/modules/payment/payments.module.ts b/src/modules/payment/payments.module.ts index ddecb63..b787413 100644 --- a/src/modules/payment/payments.module.ts +++ b/src/modules/payment/payments.module.ts @@ -11,12 +11,12 @@ import { PaymentRepository } from './repositories/payment.repository'; import { PaymentListeners } from './listeners/payment.listeners'; import { AdminModule } from '../admin/admin.module'; import { NotificationsModule } from '../notification/notifications.module'; -import { OrdersModule } from '../order/orders.module'; +import { OrderModule } from '../order/orders.module'; @Module({ imports: [MikroOrmModule.forFeature([Payment]), AuthModule, JwtModule, AdminModule, NotificationsModule, - forwardRef(() => OrdersModule)], + forwardRef(() => OrderModule)], controllers: [PaymentsController], providers: [PaymentsService, PaymentRepository, ZarinpalGateway, GatewayManager, PaymentListeners], @@ -26,4 +26,4 @@ import { OrdersModule } from '../order/orders.module'; // PaymentGatewayService, ], }) -export class PaymentsModule { } +export class PaymentModule { } diff --git a/src/modules/product/controllers/product.controller.ts b/src/modules/product/controllers/product.controller.ts index 812ce2d..dc5b471 100644 --- a/src/modules/product/controllers/product.controller.ts +++ b/src/modules/product/controllers/product.controller.ts @@ -39,18 +39,66 @@ export class productController { ) { } - // @Get('public/products/:productId') - // @UseGuards() - // @ApiBearerAuth() - // @ApiOperation({ summary: 'Get a product by id' }) - // @ApiParam({ name: 'productId', required: true }) - // findPublicproductById(@Param('productId') productId: string, @UserId() userId?: string): Promise { - // const a = this.productsService.findPublicById(productId, userId); - // return a; - // } + /*====================CATEGORY =========================*/ + @Post('admin/category') + // @UseGuards(AdminAuthGuard) + @ApiBearerAuth() + @Permissions(Permission.MANAGE_productS) + @ApiOperation({ summary: 'Create a new category' }) + @ApiBody({ type: CreateCategoryDto }) + createCategory(@Body() createproductDto: CreateCategoryDto) { + return this.categoryService.create(createproductDto); + } + + @Get('admin/category') + // @UseGuards(AdminAuthGuard) + @ApiBearerAuth() + @Permissions(Permission.MANAGE_productS) + @ApiOperation({ summary: 'Get a paginated list of Categories' }) + @ApiQuery({ name: 'page', required: false, type: Number }) + @ApiQuery({ name: 'limit', required: false, type: Number }) + @ApiQuery({ name: 'search', required: false, type: String }) + @ApiQuery({ name: 'orderBy', required: false, type: String }) + @ApiQuery({ name: 'order', required: false, enum: ['asc', 'desc'] }) + @ApiQuery({ name: 'isActive', required: false, type: Boolean }) + async findAllCategories(@Query() dto: FindCategoriesDto) { + const result = await this.categoryService.findAll(dto); + return result; + } - /* ---------------------------------- Admin ---------------------------------- */ + @Get('admin/category/:id') + // @UseGuards(AdminAuthGuard) + @ApiBearerAuth() + @Permissions(Permission.MANAGE_productS) + @ApiOperation({ summary: 'Get a category by id' }) + @ApiParam({ name: 'id', required: true }) + findCategoryById(@Param('id') id: string) { + return this.categoryService.findById(+id); + } + + @Patch('admin/category/:id') + // @UseGuards(AdminAuthGuard) + @ApiBearerAuth() + @Permissions(Permission.MANAGE_productS) + @ApiOperation({ summary: 'Update a category' }) + @ApiParam({ name: 'id', required: true }) + @ApiBody({ type: UpdateCategoryDto }) + updateCategory(@Param('id') id: string, @Body() dto: UpdateCategoryDto) { + return this.categoryService.update(+id, dto); + } + + @Delete('admin/category/:id') + // @UseGuards(AdminAuthGuard) + @ApiBearerAuth() + @Permissions(Permission.MANAGE_productS) + @ApiOperation({ summary: 'Delete (soft) a category' }) + @ApiParam({ name: 'id', required: true }) + removeCategory(@Param('id') id: string,) { + return this.categoryService.remove(+id); + } + + /* =============================== PRODUCT ================================= */ @Post('admin/product') // @UseGuards(AdminAuthGuard) @ApiBearerAuth() @@ -109,66 +157,9 @@ export class productController { return this.productService.remove(id); } - /**CATEGORY */ - @Post('admin/product/category') - // @UseGuards(AdminAuthGuard) - @ApiBearerAuth() - @Permissions(Permission.MANAGE_productS) - @ApiOperation({ summary: 'Create a new category' }) - @ApiBody({ type: CreateCategoryDto }) - createCategory(@Body() createproductDto: CreateCategoryDto) { - return this.categoryService.create(createproductDto); - } + - @Get('admin/products/category') - // @UseGuards(AdminAuthGuard) - @ApiBearerAuth() - @Permissions(Permission.MANAGE_productS) - @ApiOperation({ summary: 'Get a paginated list of Categories' }) - @ApiQuery({ name: 'page', required: false, type: Number }) - @ApiQuery({ name: 'limit', required: false, type: Number }) - @ApiQuery({ name: 'search', required: false, type: String }) - @ApiQuery({ name: 'orderBy', required: false, type: String }) - @ApiQuery({ name: 'order', required: false, enum: ['asc', 'desc'] }) - @ApiQuery({ name: 'isActive', required: false, type: Boolean }) - async findAllCategories(@Query() dto: FindCategoriesDto) { - const result = await this.categoryService.findAll(dto); - return result; - } - - - @Get('admin/products/category/:id') - // @UseGuards(AdminAuthGuard) - @ApiBearerAuth() - @Permissions(Permission.MANAGE_productS) - @ApiOperation({ summary: 'Get a category by id' }) - @ApiParam({ name: 'id', required: true }) - findCategoryById(@Param('id') id: string) { - return this.categoryService.findById(+id); - } - - @Patch('admin/products/category/:id') - // @UseGuards(AdminAuthGuard) - @ApiBearerAuth() - @Permissions(Permission.MANAGE_productS) - @ApiOperation({ summary: 'Update a category' }) - @ApiParam({ name: 'id', required: true }) - @ApiBody({ type: UpdateCategoryDto }) - updateCategory(@Param('id') id: string, @Body() dto: UpdateCategoryDto) { - return this.categoryService.update(+id, dto); - } - - @Delete('admin/products/category/:id') - // @UseGuards(AdminAuthGuard) - @ApiBearerAuth() - @Permissions(Permission.MANAGE_productS) - @ApiOperation({ summary: 'Delete (soft) a category' }) - @ApiParam({ name: 'id', required: true }) - removeCategory(@Param('id') id: string,) { - return this.categoryService.remove(+id); - } - - /*------------------------------ Attibute ------------------------*/ + /*=============================== Attibute ==========================*/ @Post('admin/product/:id/attribute') // @UseGuards(AdminAuthGuard) @ApiBearerAuth() diff --git a/src/modules/product/entities/attribute.entity.ts b/src/modules/product/entities/attribute.entity.ts index 5113a72..47a1e85 100644 --- a/src/modules/product/entities/attribute.entity.ts +++ b/src/modules/product/entities/attribute.entity.ts @@ -7,7 +7,7 @@ import { AttributeValue } from './attribute-value.entity'; @Entity({ tableName: 'attributes' }) export class Attribute extends BaseEntity { @ManyToOne(() => Product) - product: Product + product!: Product @ManyToOne(() => Attribute, { nullable: true }) parent?: Attribute | null diff --git a/src/modules/ticket/entities/ticket.entity.ts b/src/modules/ticket/entities/ticket.entity.ts index 62b6f74..a16669b 100755 --- a/src/modules/ticket/entities/ticket.entity.ts +++ b/src/modules/ticket/entities/ticket.entity.ts @@ -9,11 +9,9 @@ import { Enum, PrimaryKey, } from '@mikro-orm/core'; - import { BaseEntity } from "../../../common/entities/base.entity"; import { User } from "../../user/entities/user.entity"; import { TicketStatus } from "../enums/ticket-status.enum"; -// import { Product } from 'src/modules/product/entities/product.entity'; import { Admin } from 'src/modules/admin/entities/admin.entity'; @Entity() @@ -23,21 +21,21 @@ export class Ticket extends BaseEntity { @Enum(() => TicketStatus) status: TicketStatus; - + @Property({ type: 'text' }) content: string; - @ManyToOne(() => Admin) - admin: Admin | null; + @ManyToOne(() => User, { nullable: true }) + user?: User | null; - @ManyToOne(() => User,) - user: User; + @ManyToOne(() => Admin, { nullable: true }) + admin?: Admin | null; - @ManyToOne(() => Ticket) - parent: Ticket | null; + @ManyToOne(() => Ticket, { nullable: true }) + parent?: Ticket | null; - @OneToMany(()=>Ticket,(ticket)=>ticket.id) - children=new Collection(this) + @OneToMany(() => Ticket, (ticket) => ticket.parent) + children = new Collection(this) @Property({ type: 'json' }) attachments: string[] diff --git a/src/seeders/data/product.data.ts b/src/seeders/data/product.data.ts index 5d2e56f..d845a81 100644 --- a/src/seeders/data/product.data.ts +++ b/src/seeders/data/product.data.ts @@ -9,9 +9,9 @@ export interface productData { export const productsData: productData[] = [ { - title: 'قهوه ترک.. Turkish coffee', - desc: [''], - categoryTitle: 'قهوه ', + title: 'کارت ویزیت', + desc: ['توضیح کار ویزیت'], + categoryTitle: '', isActive: true, images: ["https://dmenu.danakcorp.com/uploads/images/product/product_1715711043900.png"], }