orders pagination

This commit is contained in:
2025-12-06 10:36:51 +03:30
parent 63ab227290
commit 8336e7f81a
5 changed files with 176 additions and 26 deletions
+127
View File
@@ -0,0 +1,127 @@
import { IsOptional, IsString, IsNumber, Min, IsIn, IsEnum, IsDateString } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiPropertyOptional } from '@nestjs/swagger';
import { OrderStatus } from '../interface/order-status';
import { PaymentStatusEnum } from '../../payments/interface/payment';
// Define the valid sort directions
const sortOrderOptions = ['asc', 'desc'] as const;
type SortOrder = (typeof sortOrderOptions)[number];
export class FindOrdersDto {
/**
* The page number to retrieve.
* @default 1
*/
@ApiPropertyOptional({
description: 'Page number',
type: Number,
default: 1,
minimum: 1,
})
@IsOptional()
@IsNumber()
@Min(1)
@Type(() => Number)
page?: number = 1;
/**
* The number of items per page.
* @default 10
*/
@ApiPropertyOptional({
description: 'Number of items per page',
type: Number,
default: 10,
minimum: 1,
})
@IsOptional()
@IsNumber()
@Min(1)
@Type(() => Number)
limit?: number = 10;
/**
* Filter by order status
*/
@ApiPropertyOptional({
description: 'Filter by order status',
enum: OrderStatus,
})
@IsOptional()
@IsEnum(OrderStatus)
status?: OrderStatus;
/**
* Filter by payment status
*/
@ApiPropertyOptional({
description: 'Filter by payment status',
enum: PaymentStatusEnum,
})
@IsOptional()
@IsEnum(PaymentStatusEnum)
paymentStatus?: PaymentStatusEnum;
/**
* Search by order number or user information
*/
@ApiPropertyOptional({
description: 'Search by order number or user information',
type: String,
})
@IsOptional()
@IsString()
search?: string;
/**
* Filter orders from this date (ISO date string)
*/
@ApiPropertyOptional({
description: 'Filter orders from this date (ISO date string)',
type: String,
format: 'date-time',
})
@IsOptional()
@IsDateString()
startDate?: string;
/**
* Filter orders until this date (ISO date string)
*/
@ApiPropertyOptional({
description: 'Filter orders until this date (ISO date string)',
type: String,
format: 'date-time',
})
@IsOptional()
@IsDateString()
endDate?: string;
/**
* The field to sort the results by.
* @default "createdAt"
*/
@ApiPropertyOptional({
description: 'Field to sort by (createdAt, total, orderNumber)',
type: String,
default: 'createdAt',
})
@IsOptional()
@IsString()
orderBy?: string = 'createdAt';
/**
* The direction to sort the results.
* @default "desc"
*/
@ApiPropertyOptional({
description: 'Sort direction (asc or desc)',
enum: sortOrderOptions,
default: 'desc',
})
@IsOptional()
@IsIn(sortOrderOptions)
order?: SortOrder = 'desc';
}
@@ -1,5 +1,8 @@
export enum OrderStatus { export enum OrderStatus {
Pending = 'pending', Pending = 'pending',
// PendingConfirmation = 'pendingConfirmation',
Confirmed = 'confirmed', Confirmed = 'confirmed',
RejectedByRestaurant = 'rejectedByRestaurant', RejectedByRestaurant = 'rejectedByRestaurant',
CancelledByUser = 'cancelledByUser', CancelledByUser = 'cancelledByUser',
+15 -12
View File
@@ -1,10 +1,11 @@
import { Controller, Get, Post, Param, UseGuards, Patch } from '@nestjs/common'; import { Controller, Get, Post, Param, UseGuards, Patch, Query } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam } from '@nestjs/swagger'; import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam } from '@nestjs/swagger';
import { OrdersService } from './orders.service'; import { OrdersService } from './orders.service';
import { AuthGuard } from '../auth/guards/auth.guard'; import { AuthGuard } from '../auth/guards/auth.guard';
import { UserId } from '../../common/decorators/user-id.decorator'; import { UserId } from '../../common/decorators/user-id.decorator';
import { RestId } from 'src/common/decorators/rest-id.decorator'; import { RestId } from 'src/common/decorators/rest-id.decorator';
import { AdminAuthGuard } from '../auth/guards/adminAuth.guard'; import { AdminAuthGuard } from '../auth/guards/adminAuth.guard';
import { FindOrdersDto } from './dto/find-orders.dto';
@ApiTags('orders') @ApiTags('orders')
@Controller() @Controller()
@@ -22,9 +23,9 @@ export class OrdersController {
@UseGuards(AuthGuard) @UseGuards(AuthGuard)
@ApiBearerAuth() @ApiBearerAuth()
@Get('public/orders') @Get('public/orders')
@ApiOperation({ summary: 'Get all orders' }) @ApiOperation({ summary: 'Get all orders with pagination and filters' })
findAll(@RestId() restId: string) { findAll(@RestId() restId: string, @Query() dto: FindOrdersDto) {
return this.ordersService.findAll(restId); return this.ordersService.findAll(restId, dto);
} }
@UseGuards(AuthGuard) @UseGuards(AuthGuard)
@@ -34,12 +35,19 @@ export class OrdersController {
return this.ordersService.findOne(+id); return this.ordersService.findOne(+id);
} }
@UseGuards(AuthGuard)
@ApiBearerAuth()
@Patch('public/orders/:id/cancel')
cancelOrder(@Param('id') id: string) {
return this.ordersService.findOne(+id);
}
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
@ApiBearerAuth() @ApiBearerAuth()
@Get('admin/orders') @Get('admin/orders')
@ApiOperation({ summary: 'Get all orders' }) @ApiOperation({ summary: 'Get all orders with pagination and filters' })
findAllAdmin(@RestId() restId: string) { findAllAdmin(@RestId() restId: string, @Query() dto: FindOrdersDto) {
return this.ordersService.findAll(restId); return this.ordersService.findAll(restId, dto);
} }
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
@@ -68,9 +76,4 @@ export class OrdersController {
readyForPickup(@Param('orderId') orderId: string) { readyForPickup(@Param('orderId') orderId: string) {
return this.ordersService.readyForDelivery(orderId); return this.ordersService.readyForDelivery(orderId);
} }
// @Delete(':id')
// remove(@Param('id') id: string) {
// return this.ordersService.remove(+id);
// }
} }
+3 -1
View File
@@ -14,6 +14,7 @@ import { UtilsModule } from '../utils/utils.module';
import { AuthModule } from '../auth/auth.module'; import { AuthModule } from '../auth/auth.module';
import { PaymentsModule } from '../payments/payments.module'; import { PaymentsModule } from '../payments/payments.module';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { OrderRepository } from './repositories/order.repository';
@Module({ @Module({
imports: [ imports: [
@@ -25,6 +26,7 @@ import { JwtModule } from '@nestjs/jwt';
JwtModule, JwtModule,
], ],
controllers: [OrdersController], controllers: [OrdersController],
providers: [OrdersService], providers: [OrdersService, OrderRepository],
exports: [OrderRepository],
}) })
export class OrdersModule {} export class OrdersModule {}
+27 -12
View File
@@ -16,6 +16,9 @@ import { PaymentsService } from '../payments/services/payments.service';
import { DeliveryMethodEnum } from '../delivery/interface/delivery'; import { DeliveryMethodEnum } from '../delivery/interface/delivery';
import { Delivery } from '../delivery/entities/delivery.entity'; import { Delivery } from '../delivery/entities/delivery.entity';
import { Cron, CronExpression } from '@nestjs/schedule'; import { Cron, CronExpression } from '@nestjs/schedule';
import { OrderRepository } from './repositories/order.repository';
import { FindOrdersDto } from './dto/find-orders.dto';
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
@Injectable() @Injectable()
export class OrdersService { export class OrdersService {
@@ -25,6 +28,7 @@ export class OrdersService {
private readonly em: EntityManager, private readonly em: EntityManager,
private readonly cartService: CartService, private readonly cartService: CartService,
private readonly paymentsService: PaymentsService, private readonly paymentsService: PaymentsService,
private readonly orderRepository: OrderRepository,
// private readonly paymentGatewayService: PaymentGatewayService, // private readonly paymentGatewayService: PaymentGatewayService,
) {} ) {}
@@ -234,16 +238,18 @@ export class OrdersService {
}; };
} }
async findAll(restId: string) { async findAll(restId: string, dto: FindOrdersDto): Promise<PaginatedResult<Order>> {
const orders = await this.em.find( return this.orderRepository.findAllPaginated(restId, {
Order, page: dto.page,
{ restaurant: { id: restId } }, limit: dto.limit,
{ populate: ['user', 'restaurant', 'deliveryMethod', 'address', 'paymentMethod'] }, status: dto.status,
); paymentStatus: dto.paymentStatus,
if (!orders) { search: dto.search,
throw new NotFoundException('No orders found'); startDate: dto.startDate,
} endDate: dto.endDate,
return orders; orderBy: dto.orderBy,
order: dto.order,
});
} }
findOne(id: number) { findOne(id: number) {
@@ -299,8 +305,17 @@ export class OrdersService {
return order; return order;
} }
remove(id: number) { async cancelOrder(orderId: string) {
return `This action removes a #${id} order`; const order = await this.em.findOne(Order, { id: orderId });
if (!order) {
throw new NotFoundException('Order not found');
}
if (order.status !== OrderStatus.Pending) {
throw new BadRequestException('Order is not pending');
}
order.status = OrderStatus.CancelledByUser;
await this.em.persistAndFlush(order);
return order;
} }
/** /**