From b0751bf42bebd1c8c184f71dcb478f20bec9bc4b Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Fri, 20 Feb 2026 18:08:43 +0330 Subject: [PATCH] order --- src/common/enums/permission.enum.ts | 7 +- src/modules/admin/providers/admin.service.ts | 24 +++--- .../order/controllers/order.controller.ts | 15 ++++ .../dto/update-status-as-designer.dto.ts | 12 +++ src/modules/order/dto/update-status.dto.ts | 12 +++ src/modules/order/providers/order.service.ts | 85 ++++++++++++++++--- .../order/repositories/order.repository.ts | 4 +- 7 files changed, 133 insertions(+), 26 deletions(-) create mode 100644 src/modules/order/dto/update-status-as-designer.dto.ts create mode 100644 src/modules/order/dto/update-status.dto.ts diff --git a/src/common/enums/permission.enum.ts b/src/common/enums/permission.enum.ts index 584f5cf..1ce2c5a 100644 --- a/src/common/enums/permission.enum.ts +++ b/src/common/enums/permission.enum.ts @@ -18,12 +18,13 @@ export enum PermissionEnum { VIEW_MY_ASSIGNED_INVOICED_REQUESTS = 'view_my_assigned_invoiced_requests', VIEW_ORDERS = 'view_orders', - VIEW_MY_ORDERS = 'view_my_orders', + VIEW_ASSIGNED_ORDERS = 'view_assigned_orders', CREATE_ORDER = 'create_order', UPDATE_ORDER = 'update_order', ASSIGN_DESIGNER = 'assign_designer', DELETE_ORDER = 'delete_order', + // User & Admin Management MANAGE_ADMINS = 'manage_admins', // Role Management @@ -52,7 +53,7 @@ export const PermissionTitles: Record = { [PermissionEnum.CREATE_ORDER]: 'ایجاد سفارش جدید', [PermissionEnum.UPDATE_ORDER]: 'ویرایش سفارش ', [PermissionEnum.VIEW_ORDERS]: "مشاهده همه سفارش ها", - [PermissionEnum.VIEW_MY_ORDERS]: "مشاهده سفارش های من", + [PermissionEnum.VIEW_ASSIGNED_ORDERS]: "مشاهده سفارش های من", [PermissionEnum.ASSIGN_DESIGNER]: "اضافه کردن طراح به سفارش", [PermissionEnum.MANAGE_ADMINS]: 'مدیریت مدیران', @@ -71,5 +72,5 @@ export const PermissionTitles: Record = { [PermissionEnum.CREATE_INVOICE]: "", [PermissionEnum.UPDATE_INVOICE]: "", [PermissionEnum.DELETE_INVOICE]: "", - [PermissionEnum.DELETE_ORDER]: "" + [PermissionEnum.DELETE_ORDER]: "", }; diff --git a/src/modules/admin/providers/admin.service.ts b/src/modules/admin/providers/admin.service.ts index 38edf04..5701fa9 100644 --- a/src/modules/admin/providers/admin.service.ts +++ b/src/modules/admin/providers/admin.service.ts @@ -163,19 +163,19 @@ export class AdminService { return admins } - async hasPermission(adminId: string, permissionName: PermissionEnum): Promise { - const has = await this.adminRepository.count({ - id: adminId, - role: { - permissions: { - $some: { - name: permissionName - } - } - } - }) + async hasPermissions(adminId: string, permissionNames: PermissionEnum[]): Promise { + if (permissionNames.length === 0) return [] - return !!has + const admin = await this.adminRepository.findOne( + { id: adminId }, + { populate: ['role', 'role.permissions'] }, + ) + if (!admin?.role?.permissions) return [] + + const adminPermissionNames = new Set( + admin.role.permissions.getItems().map((p) => p.name), + ) + return permissionNames.filter((name) => adminPermissionNames.has(name)) } } diff --git a/src/modules/order/controllers/order.controller.ts b/src/modules/order/controllers/order.controller.ts index ec23782..d13205c 100644 --- a/src/modules/order/controllers/order.controller.ts +++ b/src/modules/order/controllers/order.controller.ts @@ -11,6 +11,7 @@ import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard'; import { Permissions } from 'src/common/decorators/permissions.decorator'; import { PermissionEnum } from 'src/common/enums/permission.enum'; import { AssignDesignerDto } from '../dto/assign-designer.dto'; +import { UpdateStatusDto } from '../dto/update-status.dto'; @ApiTags('orders') @ApiBearerAuth() @@ -45,6 +46,13 @@ export class OrderController { return this.orderService.createOrderAsAdmin(adminId, body); } + // Permission handled inside service + @Get('admin/orders') + @UseGuards(AdminAuthGuard) + @ApiOperation({ summary: 'Get all orders with pagination and filters' }) + findAllAsAdmin(@Query() dto: FindOrdersDto, @AdminId() adminId: string) { + return this.orderService.findOrdersAsUser(adminId, dto); + } @Get('admin/orders/:id') @UseGuards(AdminAuthGuard) @@ -79,6 +87,13 @@ export class OrderController { return this.orderService.assignDesigner(orderId, body.designerId); } + // Permission handled inside service + @Post('admin/orders/:orderId/status') + @UseGuards(AdminAuthGuard) + @ApiOperation({ summary: 'Assign Order Designer ' }) + updateStatus(@Param('orderId') orderId: string,@AdminId()adminId:string, @Body() dto: UpdateStatusDto) { + return this.orderService.updateStatus(orderId,adminId, dto); + } } diff --git a/src/modules/order/dto/update-status-as-designer.dto.ts b/src/modules/order/dto/update-status-as-designer.dto.ts new file mode 100644 index 0000000..4c4e25a --- /dev/null +++ b/src/modules/order/dto/update-status-as-designer.dto.ts @@ -0,0 +1,12 @@ +import { + IsString +} from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { OrderStatusEnum } from '../interface/order.interface'; + +export class UpdateStatusAsDesignerDto { + @IsString() + @ApiProperty() + status: OrderStatusEnum.DESIGN_INITIATED | OrderStatusEnum.DESIGN_FINISHED | OrderStatusEnum.DESIGN_REVISION; +} + diff --git a/src/modules/order/dto/update-status.dto.ts b/src/modules/order/dto/update-status.dto.ts new file mode 100644 index 0000000..4ecc496 --- /dev/null +++ b/src/modules/order/dto/update-status.dto.ts @@ -0,0 +1,12 @@ +import { + IsString +} from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { OrderStatusEnum } from '../interface/order.interface'; + +export class UpdateStatusDto { + @IsString() + @ApiProperty({enum:OrderStatusEnum}) + status: OrderStatusEnum +} + diff --git a/src/modules/order/providers/order.service.ts b/src/modules/order/providers/order.service.ts index dd4f28b..713b1f9 100644 --- a/src/modules/order/providers/order.service.ts +++ b/src/modules/order/providers/order.service.ts @@ -1,4 +1,4 @@ -import { Injectable, BadRequestException, Logger, NotFoundException } from '@nestjs/common'; +import { Injectable, BadRequestException, Logger, NotFoundException, ForbiddenException } from '@nestjs/common'; import { EntityManager } from '@mikro-orm/postgresql'; import { OrderRepository } from '../repositories/order.repository'; import { FindOrdersDto } from '../dto/find-orders.dto'; @@ -26,6 +26,8 @@ import { OrderType } from '../entities/order-type.entity'; import { Product } from 'src/modules/product/entities/product.entity'; import { InvoiceItem } from 'src/modules/invoice/entities/invoice-item.entity'; import { PaginatedResult } from 'src/common/interfaces/pagination.interface'; +import { UpdateStatusAsDesignerDto } from '../dto/update-status-as-designer.dto'; +import { UpdateStatusDto } from '../dto/update-status.dto'; @Injectable() export class OrderService { @@ -112,8 +114,26 @@ export class OrderService { }) } - async findOrdersAsAdmin(dto: FindOrdersDto): Promise> { - return this.orderRepository.findAllPaginated(dto) + async findOrdersAsAdmin(adminId: string, dto: FindOrdersDto): Promise> { + const permissions = await this.adminService.hasPermissions(adminId, + [PermissionEnum.VIEW_ORDERS, PermissionEnum.VIEW_ASSIGNED_ORDERS]) + + if (permissions.includes(PermissionEnum.VIEW_ORDERS)) { + + return this.orderRepository.findAllPaginated(dto) + + } else if (permissions.includes(PermissionEnum.VIEW_ASSIGNED_ORDERS)) { + + return this.orderRepository.findAllPaginated({ + designerId: adminId, + ...dto + }) + + } else { + + throw new ForbiddenException("You don't have permission to view orders") + + } } async getOrderAsUser(userId: string, orderId: string): Promise { @@ -124,13 +144,6 @@ export class OrderService { return order } - async findOrderOrFail(id: string): Promise { - const order = await this.em.findOne(Order, { id }, { populate: ['user', 'type', 'product', 'creator'] }); - if (!order) { - throw new NotFoundException(`Order with ID ${id} not found.`); - } - return order; - } async updateOrderAsAdmin(id: string, dto: UpdateOrderAsAdminDto): Promise { const order = await this.findOrderOrFail(id); @@ -177,6 +190,38 @@ export class OrderService { await this.em.flush(); } + async updateStatusAsDesigner(orderId: string, dto: UpdateStatusAsDesignerDto): Promise { + const order = await this.findOrderOrFail(orderId); + order.status = dto.status; + await this.em.flush(); + return order + } + + async updateStatus(orderId: string, adminId: string, dto: UpdateStatusDto): Promise { + const permissions = await this.adminService.hasPermissions(adminId, + [PermissionEnum.VIEW_ORDERS, PermissionEnum.VIEW_ASSIGNED_ORDERS]) + + if (permissions.includes(PermissionEnum.VIEW_ORDERS)) { + const order = await this.findOrderOrFail(orderId); + order.status = dto.status; + await this.em.flush(); + return order + } + + if (permissions.includes(PermissionEnum.VIEW_ASSIGNED_ORDERS)) { + const order = await this.findOrderOrFailAssignedOrder(orderId, adminId); + order.status = dto.status; + await this.em.flush(); + return order + } + + const order = await this.findOrderOrFail(orderId); + + order.status = dto.status; + await this.em.flush(); + return order + } + async assignDesigner(orderId: string, designerId: string) { const order = await this.findOrderOrFail(orderId) const designer = await this.adminService.findOrFail(designerId) @@ -185,4 +230,24 @@ export class OrderService { await this.em.flush() return order } + + // -----------Hrlper Methods ----------- + async findOrderOrFail(id: string): Promise { + const order = await this.em.findOne(Order, { id }, { populate: ['user', 'type', 'product', 'creator'] }); + if (!order) { + throw new NotFoundException(`Order with ID ${id} not found.`); + } + return order; + } + + async findOrderOrFailAssignedOrder(id: string, adminId: string): Promise { + const order = await this.em.findOne(Order, { id }, { populate: ['user', 'type', 'product', 'creator'] }); + if (!order) { + throw new NotFoundException(`Order with ID ${id} not found.`); + } + if (order?.designer?.id !== adminId) { + throw new ForbiddenException("You don't have permission to view this order") + } + return order; + } } diff --git a/src/modules/order/repositories/order.repository.ts b/src/modules/order/repositories/order.repository.ts index c044040..d15a85b 100644 --- a/src/modules/order/repositories/order.repository.ts +++ b/src/modules/order/repositories/order.repository.ts @@ -9,6 +9,7 @@ import { FindOrdersDto } from '../dto/find-orders.dto'; class FindOrdersOpts extends FindOrdersDto { userId?: string; + adminId?: string; designerId?: string }; @@ -29,7 +30,8 @@ export class OrderRepository extends EntityRepository { userId, from, to, - designerId + designerId, + adminId } = opts; const offset = (page - 1) * limit;