diff --git a/src/discount/controllers/coupon.controller.ts b/src/discount/controllers/coupon.controller.ts index b09b0bd..f26d040 100644 --- a/src/discount/controllers/coupon.controller.ts +++ b/src/discount/controllers/coupon.controller.ts @@ -43,7 +43,7 @@ export class CouponController { @Post() @UseGuards(AuthGuard, RolesGuard) - @Roles(UserRole.ADMIN) + @Roles(UserRole.ADMIN, UserRole.BRANCH_ADMIN) @ApiOperation({ summary: 'Create a coupon' }) @ApiResponse({ status: HttpStatus.CREATED, @@ -56,7 +56,7 @@ export class CouponController { @Get() @UseGuards(AuthGuard, RolesGuard) - @Roles(UserRole.ADMIN) + @Roles(UserRole.ADMIN, UserRole.BRANCH_ADMIN) @UseInterceptors(PaginationInterceptor) @ApiOperation({ summary: 'List all coupons' }) @ApiQuery({ @@ -118,7 +118,10 @@ export class CouponController { } @HttpCode(HttpStatus.NO_CONTENT) + @UseGuards(AuthGuard, RolesGuard) + @Roles(UserRole.ADMIN, UserRole.BRANCH_ADMIN) @Delete('bulk') + @ApiBearerAuth() @ApiOperation({ summary: 'Bulk delete coupons' }) @ApiResponse({ description: 'Successful bulk deletion of coupons', @@ -131,7 +134,10 @@ export class CouponController { } @HttpCode(HttpStatus.NO_CONTENT) + @UseGuards(AuthGuard, RolesGuard) + @Roles(UserRole.ADMIN, UserRole.BRANCH_ADMIN) @Patch('bulk') + @ApiBearerAuth() @ApiOperation({ summary: 'Bulk update coupons' }) @ApiResponse({ description: 'Successful bulk update of coupons', @@ -160,7 +166,8 @@ export class CouponController { @Patch(':code') @UseGuards(AuthGuard, RolesGuard) - @Roles(UserRole.ADMIN) + @Roles(UserRole.ADMIN, UserRole.BRANCH_ADMIN) + @ApiBearerAuth() @ApiOperation({ summary: 'Update coupon by code' }) @ApiResponse({ status: HttpStatus.OK, @@ -177,7 +184,8 @@ export class CouponController { @HttpCode(HttpStatus.NO_CONTENT) @Delete(':code') @UseGuards(AuthGuard, RolesGuard) - @Roles(UserRole.ADMIN) + @Roles(UserRole.ADMIN, UserRole.BRANCH_ADMIN) + @ApiBearerAuth() @ApiOperation({ summary: 'Delete coupon by code' }) @ApiResponse({ status: HttpStatus.NO_CONTENT, diff --git a/src/discount/controllers/promo.controller.ts b/src/discount/controllers/promo.controller.ts index 9cde9a1..9e7ad28 100644 --- a/src/discount/controllers/promo.controller.ts +++ b/src/discount/controllers/promo.controller.ts @@ -41,7 +41,7 @@ import { PaginationInterceptor } from 'src/utils/pagination.interceptor'; @ApiExtraModels(PaginationDTO, ResponsePromoDTO) @ApiBearerAuth() @UseGuards(AuthGuard, RolesGuard) -@Roles(UserRole.ADMIN) +@Roles(UserRole.ADMIN, UserRole.BRANCH_ADMIN) export class PromoController { constructor(private readonly promoService: PromoService) {} diff --git a/src/email/email.controller.spec.ts b/src/email/email.controller.spec.ts deleted file mode 100644 index 9470aa8..0000000 --- a/src/email/email.controller.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { EmailController } from './email.controller'; - -describe('EmailController', () => { - let controller: EmailController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [EmailController], - }).compile(); - - controller = module.get(EmailController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/src/inventory/inventory.controller.ts b/src/inventory/inventory.controller.ts index dc863bc..0bcdd35 100644 --- a/src/inventory/inventory.controller.ts +++ b/src/inventory/inventory.controller.ts @@ -11,6 +11,8 @@ import { HttpCode, Query, UseInterceptors, + Req, + BadRequestException, } from '@nestjs/common'; import { InventoryService } from './inventory.service'; import { @@ -21,7 +23,7 @@ import { BulkUpdateInventoryDTO, } from './dto/inventory.dto'; import { RolesGuard } from 'src/auth/roles.guard'; -import { AuthGuard } from 'src/auth/auth.guard'; +import { AuthGuard, CustomRequest } from 'src/auth/auth.guard'; import { UserRole } from 'src/user/entities/user.entity'; import { Roles } from 'src/auth/roles.decorador'; import { BranchId } from 'src/auth/branch-id.decorator'; @@ -53,8 +55,15 @@ export class InventoryController { type: ResponseInventoryDTO, }) async create( + @Req() req: CustomRequest, @Body() createInventoryDTO: CreateInventoryDTO, ): Promise { + if (req.user.role === UserRole.BRANCH_ADMIN) { + if (!req.user.branch) { + throw new BadRequestException('Branch not found'); + } + createInventoryDTO.branchId = req.user.branch.id; + } return await this.inventoryService.create(createInventoryDTO); } @@ -144,10 +153,15 @@ export class InventoryController { type: Inventory, }) async update( + @Req() req: CustomRequest, @Param('id') id: string, @Body() updateInventoryDTO: UpdateInventoryDTO, ) { - return await this.inventoryService.update(id, updateInventoryDTO); + let branchId: string | undefined; + if (req.user.role === UserRole.BRANCH_ADMIN) { + branchId = req.user.branch.id; + } + return await this.inventoryService.update(id, updateInventoryDTO, branchId); } @HttpCode(HttpStatus.NO_CONTENT) @@ -161,8 +175,15 @@ export class InventoryController { status: HttpStatus.NO_CONTENT, type: Inventory, }) - async remove(@Param('id') id: string): Promise { - await this.inventoryService.remove(id); + async remove( + @Req() req: CustomRequest, + @Param('id') id: string, + ): Promise { + let branchId: string | undefined; + if (req.user.role === UserRole.BRANCH_ADMIN) { + branchId = req.user.branch.id; + } + await this.inventoryService.remove(id, branchId); } @UseGuards(AuthGuard, RolesGuard) diff --git a/src/inventory/inventory.service.ts b/src/inventory/inventory.service.ts index dae18e3..fe4d61a 100644 --- a/src/inventory/inventory.service.ts +++ b/src/inventory/inventory.service.ts @@ -9,7 +9,7 @@ import { BulkUpdateInventoryDTO, } from './dto/inventory.dto'; import { Inventory } from './entities/inventory.entity'; -import { Repository } from 'typeorm'; +import { FindOneOptions, Repository } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm'; import { ProductPresentation } from 'src/products/entities/product-presentation.entity'; import { BranchService } from 'src/branch/branch.service'; @@ -111,14 +111,30 @@ export class InventoryService { async update( id: string, updateInventoryDTO: UpdateInventoryDTO, + branchId?: string, ): Promise { - const inventory = await this.findOne(id); + let where: FindOneOptions = { where: { id } }; + if (branchId) { + where = { + where: { id, branch: { id: branchId } }, + }; + } + const inventory = await this.inventoryRepository.findOne(where); const updatedInventory = { ...inventory, ...updateInventoryDTO }; return await this.inventoryRepository.save(updatedInventory); } - async remove(id: string): Promise { - const inventory = await this.findOne(id); + async remove(id: string, branchId?: string): Promise { + let where: FindOneOptions = { where: { id } }; + if (branchId) { + where = { + where: { id, branch: { id: branchId } }, + }; + } + const inventory = await this.inventoryRepository.findOne(where); + if (!inventory) { + throw new NotFoundException(`Inventory #${id} not found`); + } const deleted = await this.inventoryRepository.softDelete(inventory.id); if (!deleted.affected) { throw new NotFoundException(`Inventory #${id} not found`); diff --git a/src/order/controllers/order-delivery.controller.ts b/src/order/controllers/order-delivery.controller.ts index 286a66a..ebe97db 100644 --- a/src/order/controllers/order-delivery.controller.ts +++ b/src/order/controllers/order-delivery.controller.ts @@ -11,7 +11,7 @@ import { Param, Patch, } from '@nestjs/common'; -import { OrderService } from '../order.service'; +import { OrderService } from '../services/order.service'; import { AuthGuard, CustomRequest } from 'src/auth/auth.guard'; import { ApiBearerAuth, @@ -29,10 +29,14 @@ import { } from '../dto/order-delivery.dto'; import { User } from 'src/user/entities/user.entity'; import { plainToInstance } from 'class-transformer'; +import { OrderDeliveryService } from '../services/order-delivery.controller'; @Controller('delivery') export class OrderDeliveryController { - constructor(private readonly orderService: OrderService) {} + constructor( + private readonly orderService: OrderService, + private readonly orderDeliveryService: OrderDeliveryService, + ) {} @Get() @UseGuards(AuthGuard) @@ -92,12 +96,17 @@ export class OrderDeliveryController { @Query() pagination: OrderDeliveryQueryDTO, ): Promise<{ data: OrderDeliveryDTO[]; total: number }> { const { page, limit, status, branchId, employeeId } = pagination; - const data = await this.orderService.findAllOD(req.user, page, limit, { - status, - branchId, - employeeId, - }); - const total = await this.orderService.countDeliveries(req.user, { + const data = await this.orderDeliveryService.findAll( + req.user, + page, + limit, + { + status, + branchId, + employeeId, + }, + ); + const total = await this.orderDeliveryService.countDeliveries(req.user, { status, branchId, employeeId, @@ -121,7 +130,7 @@ export class OrderDeliveryController { async getDelivery( @Param('deliveryId') deliveryId: string, ): Promise { - const delivery = await this.orderService.getDelivery(deliveryId); + const delivery = await this.orderDeliveryService.findOne(deliveryId); return plainToInstance(OrderDeliveryDTO, delivery, { excludeExtraneousValues: true, @@ -140,7 +149,7 @@ export class OrderDeliveryController { @Body() updateDeliveryDto: UpdateDeliveryDTO, ): Promise { const user = req.user as User; - const updatedDelivery = await this.orderService.updateDelivery( + const updatedDelivery = await this.orderDeliveryService.update( user, deliveryId, updateDeliveryDto, diff --git a/src/order/controllers/order.controller.ts b/src/order/controllers/order.controller.ts index 3aefbd3..51ff5d0 100644 --- a/src/order/controllers/order.controller.ts +++ b/src/order/controllers/order.controller.ts @@ -14,7 +14,7 @@ import { Patch, NotFoundException, } from '@nestjs/common'; -import { OrderService } from '../order.service'; +import { OrderService } from '../services/order.service'; import { CreateOrderDTO, OrderListUpdateDTO, @@ -139,10 +139,14 @@ export class OrderController { @Req() req: CustomRequest, @Query() query: OrderQueryDTO, ): Promise<{ data: ResponseOrderDTO[]; total: number }> { - const { page, limit, userId, branchId, status, type } = query; + const { page, limit, userId, status, type } = query; + let { branchId } = query; let user; if ([UserRole.ADMIN, UserRole.BRANCH_ADMIN].includes(req.user.role)) { if (userId) user = userId; + if (req.user.role === UserRole.BRANCH_ADMIN) { + branchId = req.user.branch.id; + } } else { user = req.user.id; } @@ -164,7 +168,7 @@ export class OrderController { } @UseGuards(AuthGuard, RolesGuard) - @Roles(UserRole.ADMIN) + @Roles(UserRole.ADMIN, UserRole.BRANCH_ADMIN) @Patch('bulk') @ApiBearerAuth() @ApiOperation({ summary: 'Bulk update orders' }) @@ -172,10 +176,18 @@ export class OrderController { status: HttpStatus.NO_CONTENT, description: 'Orders updated successfully', }) - async bulkUpdate(@Body() updateOrderDto: OrderListUpdateDTO): Promise { + async bulkUpdate( + @Req() req: CustomRequest, + @Body() updateOrderDto: OrderListUpdateDTO, + ): Promise { + let branchId: string | undefined; + if (req.user.role === UserRole.BRANCH_ADMIN) { + branchId = req.user.branch.id; + } await this.orderService.bulkUpdate( updateOrderDto.orders, updateOrderDto.status, + branchId, ); } @@ -195,6 +207,11 @@ export class OrderController { let order: Order; if ([UserRole.ADMIN, UserRole.BRANCH_ADMIN].includes(req.user.role)) { order = await this.orderService.findOne(id); + if (req.user.role === UserRole.BRANCH_ADMIN) { + if (order.branch.id !== req.user.branch.id) { + throw new NotFoundException('Order not found'); + } + } } else if ([UserRole.DELIVERY].includes(req.user.role)) { order = await this.orderService.findOne(id); if (order.type !== OrderType.DELIVERY) { @@ -226,9 +243,18 @@ export class OrderController { type: ResponseOrderDetailedDTO, }) async update( + @Req() req: CustomRequest, @Param('id', new ParseUUIDPipe()) id: string, @Body() updateOrderStatusDTO: UpdateOrderStatusDTO, ) { - return await this.orderService.update(id, updateOrderStatusDTO.status); + let branchId: string | undefined; + if (req.user.role === UserRole.BRANCH_ADMIN) { + branchId = req.user.branch.id; + } + return await this.orderService.update( + id, + updateOrderStatusDTO.status, + branchId, + ); } } diff --git a/src/order/order.gateway.ts b/src/order/order.gateway.ts index 72e0c38..f9f19ae 100644 --- a/src/order/order.gateway.ts +++ b/src/order/order.gateway.ts @@ -16,7 +16,7 @@ import { } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; import { UpdateOrderStatusWsDTO } from './dto/order'; -import { OrderService } from './order.service'; +import { OrderService } from './services/order.service'; import { AuthGuardWs } from 'src/auth/auth.guard'; import { AuthService } from 'src/auth/auth.service'; import { RolesGuardWs } from 'src/auth/roles.guard'; @@ -24,6 +24,7 @@ import { Roles } from 'src/auth/roles.decorador'; import { UserRole } from 'src/user/entities/user.entity'; import { WebsocketExceptionsFilter } from './ws.filters'; import { UpdateDeliveryWsDTO } from './dto/order-delivery.dto'; +import { OrderDeliveryService } from './services/order-delivery.controller'; @WebSocketGateway({ cors: { @@ -38,6 +39,7 @@ export class OrderGateway implements OnGatewayConnection, OnGatewayDisconnect { constructor( private readonly authService: AuthService, private readonly orderService: OrderService, + private readonly orderDeliveryService: OrderDeliveryService, ) {} handleConnection(client: Socket) { @@ -98,8 +100,8 @@ export class OrderGateway implements OnGatewayConnection, OnGatewayDisconnect { @ConnectedSocket() client: Socket, @MessageBody() data: UpdateDeliveryWsDTO, ) { - this.orderService - .getDelivery(data.id) + this.orderDeliveryService + .findOne(data.id) .then((delivery) => { this.orderService .getUserByOrderId(delivery.order.id) diff --git a/src/order/order.module.ts b/src/order/order.module.ts index f00cfbe..7a5e7a4 100644 --- a/src/order/order.module.ts +++ b/src/order/order.module.ts @@ -1,5 +1,5 @@ import { Module, forwardRef } from '@nestjs/common'; -import { OrderService } from './order.service'; +import { OrderService } from './services/order.service'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Order, OrderDetail } from './entities/order.entity'; import { BranchService } from 'src/branch/branch.service'; diff --git a/src/order/services/order-delivery.controller.ts b/src/order/services/order-delivery.controller.ts new file mode 100644 index 0000000..e78a28f --- /dev/null +++ b/src/order/services/order-delivery.controller.ts @@ -0,0 +1,166 @@ +import { + BadRequestException, + Injectable, + NotFoundException, +} from '@nestjs/common'; +import { User, UserRole } from 'src/user/entities/user.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { OrderDelivery } from '../entities/order_delivery.entity'; +import { UpdateDeliveryDTO } from '../dto/order-delivery.dto'; +import { UserService } from 'src/user/user.service'; + +@Injectable() +export class OrderDeliveryService { + constructor( + @InjectRepository(OrderDelivery) + private orderDeliveryRepository: Repository, + private userService: UserService, + ) {} + + async findAll( + user: User, + page: number, + pageSize: number, + filters?: { + status?: string; + branchId?: string; + employeeId?: string; + }, + ): Promise { + const query = this.orderDeliveryRepository + .createQueryBuilder('delivery') + .leftJoinAndSelect('delivery.order', 'order') + .leftJoinAndSelect('order.user', 'orderUser') + .leftJoinAndSelect('orderUser.profile', 'profile') + .leftJoinAndSelect('delivery.address', 'address') + .leftJoinAndSelect('address.city', 'city') + .leftJoinAndSelect('city.state', 'state') + .leftJoinAndSelect('state.country', 'country') + .leftJoinAndSelect('delivery.branch', 'branch') + .leftJoinAndSelect('delivery.employee', 'employee') + .where('delivery.deletedAt IS NULL'); + + if (user.role !== UserRole.ADMIN) { + query.andWhere('employee.id = :userId', { userId: user.id }); + } else if (filters?.employeeId) { + query.andWhere('employee.id = :employeeId', { + employeeId: filters.employeeId, + }); + } + + if (filters?.status) { + query.andWhere('delivery.deliveryStatus = :status', { + status: filters.status, + }); + } + + if (filters?.branchId) { + query.andWhere('branch.id = :branchId', { branchId: filters.branchId }); + } + + const delivery = query + .orderBy('delivery.createdAt', 'DESC') + .skip((page - 1) * pageSize) + .take(pageSize); + + return await delivery.getMany(); + } + + async countDeliveries( + user: User, + filters?: { + status?: string; + branchId?: string; + employeeId?: string; + }, + ): Promise { + const query = this.orderDeliveryRepository + .createQueryBuilder('delivery') + .leftJoin('delivery.branch', 'branch') + .leftJoin('delivery.employee', 'employee') + .where('delivery.deletedAt IS NULL'); + + if (user.role !== UserRole.ADMIN) { + query.andWhere('employee.id = :userId', { userId: user.id }); + } else if (filters?.employeeId) { + query.andWhere('employee.id = :employeeId', { + employeeId: filters.employeeId, + }); + } + + if (filters?.status) { + query.andWhere('delivery.deliveryStatus = :status', { + status: filters.status, + }); + } + + if (filters?.branchId) { + query.andWhere('branch.id = :branchId', { branchId: filters.branchId }); + } + + return await query.getCount(); + } + + async findOne(deliveryId: string): Promise { + const delivery = await this.orderDeliveryRepository.findOne({ + where: { id: deliveryId }, + relations: [ + 'order', + 'order.user', + 'order.user.profile', + 'address', + 'address.city', + 'address.city.state', + 'address.city.state.country', + 'employee', + 'branch', + ], + }); + if (!delivery) { + throw new NotFoundException('Delivery not found.'); + } + return delivery; + } + + async update( + user: User, + deliveryId: string, + updateData: UpdateDeliveryDTO, + ): Promise { + const delivery = await this.orderDeliveryRepository.findOne({ + where: { id: deliveryId }, + relations: [ + 'order', + 'order.user', + 'address', + 'address.city', + 'address.city.state', + 'address.city.state.country', + 'employee', + 'branch', + ], + }); + if (!delivery) { + throw new NotFoundException('Delivery not found.'); + } + + const updateDelivery = this.orderDeliveryRepository.merge( + delivery, + updateData, + ); + if (updateData.employeeId) { + const employee = await this.userService.findUserById( + updateData.employeeId, + ); + if (!employee) { + throw new NotFoundException('Employee not found.'); + } + if (employee.role !== UserRole.DELIVERY) { + throw new BadRequestException('User is not an employee.'); + } + updateDelivery.employee = employee; + } + return await this.orderDeliveryRepository.save(updateDelivery); + } +} diff --git a/src/order/order.service.ts b/src/order/services/order.service.ts similarity index 78% rename from src/order/order.service.ts rename to src/order/services/order.service.ts index bc41728..14c4b92 100644 --- a/src/order/order.service.ts +++ b/src/order/services/order.service.ts @@ -3,8 +3,8 @@ import { Injectable, NotFoundException, } from '@nestjs/common'; -import { CreateOrderDTO, SalesReportDTO } from './dto/order'; -import { User, UserRole } from 'src/user/entities/user.entity'; +import { CreateOrderDTO, SalesReportDTO } from '../dto/order'; +import { User } from 'src/user/entities/user.entity'; import { ProductPresentationService } from 'src/products/services/product-presentation.service'; import { InjectRepository } from '@nestjs/typeorm'; import { In, Repository } from 'typeorm'; @@ -13,14 +13,13 @@ import { OrderDetail, OrderStatus, OrderType, -} from './entities/order.entity'; +} from '../entities/order.entity'; import { BranchService } from 'src/branch/branch.service'; import { Branch } from 'src/branch/entities/branch.entity'; import { OrderDelivery, OrderDeliveryStatus, -} from './entities/order_delivery.entity'; -import { UpdateDeliveryDTO } from './dto/order-delivery.dto'; +} from '../entities/order_delivery.entity'; import { UserAddress } from 'src/user/entities/user-address.entity'; import { UserService } from 'src/user/user.service'; import { CouponService } from 'src/discount/services/coupon.service'; @@ -198,9 +197,10 @@ export class OrderService { return { orders, total }; } - async findOne(id: string, userId?: string) { + async findOne(id: string, userId?: string, branchId?: string) { const where: Record = { id }; if (userId) where.user = { id: userId }; + if (branchId) where.branch = { id: branchId }; const order = await this.orderRepository.findOne({ where: where, relations: [ @@ -242,8 +242,12 @@ export class OrderService { return order; } - async update(id: string, status: OrderStatus): Promise { - const order = await this.findOne(id); + async update( + id: string, + status: OrderStatus, + branchId?: string, + ): Promise { + const order = await this.findOne(id, undefined, branchId); if (order.status === OrderStatus.COMPLETED) { console.log('A COMPLETED order cannot be modified'); return order; @@ -276,10 +280,19 @@ export class OrderService { return await this.orderRepository.save(order); } - async bulkUpdate(ordersIds: string[], status: OrderStatus) { - const orders = await this.orderRepository.findBy({ - id: In(ordersIds), - }); + async bulkUpdate( + ordersIds: string[], + status: OrderStatus, + branchId?: string, + ) { + let where: Record = { id: In(ordersIds) }; + if (branchId) { + where = { + ...where, + branch: { id: branchId }, + }; + } + const orders = await this.orderRepository.findBy(where); if (orders.length === 0) { throw new NotFoundException('No orders found'); } @@ -292,152 +305,6 @@ export class OrderService { return await this.orderRepository.save(updatedOrders); } - async findAllOD( - user: User, - page: number, - pageSize: number, - filters?: { - status?: string; - branchId?: string; - employeeId?: string; - }, - ): Promise { - const query = this.orderDeliveryRepository - .createQueryBuilder('delivery') - .leftJoinAndSelect('delivery.order', 'order') - .leftJoinAndSelect('order.user', 'orderUser') - .leftJoinAndSelect('orderUser.profile', 'profile') - .leftJoinAndSelect('delivery.address', 'address') - .leftJoinAndSelect('address.city', 'city') - .leftJoinAndSelect('city.state', 'state') - .leftJoinAndSelect('state.country', 'country') - .leftJoinAndSelect('delivery.branch', 'branch') - .leftJoinAndSelect('delivery.employee', 'employee') - .where('delivery.deletedAt IS NULL'); - - if (user.role !== UserRole.ADMIN) { - query.andWhere('employee.id = :userId', { userId: user.id }); - } else if (filters?.employeeId) { - query.andWhere('employee.id = :employeeId', { - employeeId: filters.employeeId, - }); - } - - if (filters?.status) { - query.andWhere('delivery.deliveryStatus = :status', { - status: filters.status, - }); - } - - if (filters?.branchId) { - query.andWhere('branch.id = :branchId', { branchId: filters.branchId }); - } - - const delivery = query - .orderBy('delivery.createdAt', 'DESC') - .skip((page - 1) * pageSize) - .take(pageSize); - - return await delivery.getMany(); - } - - async countDeliveries( - user: User, - filters?: { - status?: string; - branchId?: string; - employeeId?: string; - }, - ): Promise { - const query = this.orderDeliveryRepository - .createQueryBuilder('delivery') - .leftJoin('delivery.branch', 'branch') - .leftJoin('delivery.employee', 'employee') - .where('delivery.deletedAt IS NULL'); - - if (user.role !== UserRole.ADMIN) { - query.andWhere('employee.id = :userId', { userId: user.id }); - } else if (filters?.employeeId) { - query.andWhere('employee.id = :employeeId', { - employeeId: filters.employeeId, - }); - } - - if (filters?.status) { - query.andWhere('delivery.deliveryStatus = :status', { - status: filters.status, - }); - } - - if (filters?.branchId) { - query.andWhere('branch.id = :branchId', { branchId: filters.branchId }); - } - - return await query.getCount(); - } - - async getDelivery(deliveryId: string): Promise { - const delivery = await this.orderDeliveryRepository.findOne({ - where: { id: deliveryId }, - relations: [ - 'order', - 'order.user', - 'order.user.profile', - 'address', - 'address.city', - 'address.city.state', - 'address.city.state.country', - 'employee', - 'branch', - ], - }); - if (!delivery) { - throw new NotFoundException('Delivery not found.'); - } - return delivery; - } - - async updateDelivery( - user: User, - deliveryId: string, - updateData: UpdateDeliveryDTO, - ): Promise { - const delivery = await this.orderDeliveryRepository.findOne({ - where: { id: deliveryId }, - relations: [ - 'order', - 'order.user', - 'address', - 'address.city', - 'address.city.state', - 'address.city.state.country', - 'employee', - 'branch', - ], - }); - if (!delivery) { - throw new NotFoundException('Delivery not found.'); - } - - const updateDelivery = this.orderDeliveryRepository.merge( - delivery, - updateData, - ); - if (updateData.employeeId) { - const employee = await this.userService.findUserById( - updateData.employeeId, - ); - if (!employee) { - throw new NotFoundException('Employee not found.'); - } - if (employee.role !== UserRole.DELIVERY) { - throw new BadRequestException('User is not an employee.'); - } - updateDelivery.employee = employee; - } - return await this.orderDeliveryRepository.save(updateDelivery); - } - async countOrdersCompleted( status: OrderStatus, startDate: Date, diff --git a/src/payments/services/payment-confirmation.service.ts b/src/payments/services/payment-confirmation.service.ts index dabc264..0aed084 100644 --- a/src/payments/services/payment-confirmation.service.ts +++ b/src/payments/services/payment-confirmation.service.ts @@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { PaymentConfirmation } from '../entities/payment-confirmation.entity'; import { CreatePaymentConfirmationDTO } from '../dto/payment-confirmation.dto'; -import { OrderService } from 'src/order/order.service'; +import { OrderService } from 'src/order/services/order.service'; @Injectable() export class PaymentConfirmationService { diff --git a/src/reports/reports.controller.ts b/src/reports/reports.controller.ts index f7a35f1..a446b91 100644 --- a/src/reports/reports.controller.ts +++ b/src/reports/reports.controller.ts @@ -4,12 +4,13 @@ import { Query, BadRequestException, UseGuards, + Req, } from '@nestjs/common'; -import { OrderService } from 'src/order/order.service'; +import { OrderService } from 'src/order/services/order.service'; import { UserService } from 'src/user/user.service'; import { OrderStatus } from 'src/order/entities/order.entity'; import { Roles } from 'src/auth/roles.decorador'; -import { AuthGuard } from 'src/auth/auth.guard'; +import { AuthGuard, CustomRequest } from 'src/auth/auth.guard'; import { RolesGuard } from 'src/auth/roles.guard'; import { UserRole } from 'src/user/entities/user.entity'; import { ApiBearerAuth, ApiQuery, ApiResponse } from '@nestjs/swagger'; @@ -57,6 +58,7 @@ export class ReportsController { }, }) async getDashboard( + @Req() req: CustomRequest, @Query('startDate') start: string, @Query('endDate') end: string, @Query('branchId') branchId?: string, @@ -64,6 +66,9 @@ export class ReportsController { if (!start || !end) { throw new BadRequestException('startDate and endDate are required'); } + if (req.user.role === UserRole.BRANCH_ADMIN) { + branchId = req.user.branch.id; + } const startDate = new Date(start); const endDate = new Date(end); const [openOrders, completedOrders, totalSales, totalNewUsers] = @@ -86,6 +91,7 @@ export class ReportsController { totalNewUsers, }; } + @Get('order') @ApiBearerAuth() @ApiQuery({ @@ -120,10 +126,14 @@ export class ReportsController { }, }) async getOrdersByStatus( + @Req() req: CustomRequest, @Query('startDate') start: string, @Query('endDate') end: string, @Query('branchId') branchId?: string, ) { + if (req.user.role === UserRole.BRANCH_ADMIN) { + branchId = req.user.branch.id; + } if (!start || !end) { throw new BadRequestException('startDate and endDate are required'); } @@ -160,10 +170,14 @@ export class ReportsController { type: FullSalesReportDTO, }) async getSalesReport( + @Req() req: CustomRequest, @Query('startDate') start: string, @Query('endDate') end: string, @Query('branchId') branchId?: string, ) { + if (req.user.role === UserRole.BRANCH_ADMIN) { + branchId = req.user.branch.id; + } if (!start || !end) { throw new BadRequestException('startDate and endDate are required'); }