diff --git a/src/modules/order/controllers/orders.controller.ts b/src/modules/order/controllers/orders.controller.ts index 8bc0272..58e171d 100644 --- a/src/modules/order/controllers/orders.controller.ts +++ b/src/modules/order/controllers/orders.controller.ts @@ -1,11 +1,11 @@ import { Controller, Get, Post, Param, UseGuards, Patch, Query, Body } from '@nestjs/common'; -import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiHeader, ApiBody } from '@nestjs/swagger'; +import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiHeader, ApiBody, ApiQuery } from '@nestjs/swagger'; import { OrdersService } from '../providers/orders.service'; import { AuthGuard } from '../../auth/guards/auth.guard'; import { UserId } from '../../../common/decorators/user-id.decorator'; import { AdminAuthGuard } from '../../auth/guards/adminAuth.guard'; import { FindOrdersDto } from '../dto/find-orders.dto'; -import { OrderStatus } from '../interface/order.interface'; +import { OrderStatusEnum } from '../interface/order.interface'; import { UpdateOrderStatusDto } from '../dto/update-order-status.dto'; import { Permissions } from 'src/common/decorators/permissions.decorator'; import { Permission } from 'src/common/enums/permission.enum'; @@ -25,13 +25,21 @@ export class OrdersController { return this.ordersService.createOrder(userId, body); } - // @UseGuards(AuthGuard) - // @Get('public/orders') - - // @ApiOperation({ summary: 'Get all orders with pagination and filters' }) - // findAll(@Query() dto: FindOrdersDto, @UserId() userId: string) { - // return this.ordersService.findAllForUser(dto, userId); - // } + @Get('public/orders') + @UseGuards(AuthGuard) + @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: 'statuses', required: false, enum: OrderStatusEnum }) + @ApiQuery({ name: 'from', required: false, type: Date }) + @ApiQuery({ name: 'to', required: false, type: Date }) + @ApiOperation({ summary: 'Get all orders with pagination and filters' }) + async findAll(@Query() dto: FindOrdersDto, @UserId() userId: string) { + const orders=await this.ordersService.findAllForUser(userId, dto); + return orders + } // @UseGuards(AuthGuard) // @ApiOperation({ summary: 'Get an order By id for User' }) diff --git a/src/modules/order/dto/find-orders.dto.ts b/src/modules/order/dto/find-orders.dto.ts index 5f64874..941a134 100644 --- a/src/modules/order/dto/find-orders.dto.ts +++ b/src/modules/order/dto/find-orders.dto.ts @@ -10,7 +10,7 @@ import { } from 'class-validator'; import { Type, Transform } from 'class-transformer'; import { ApiPropertyOptional } from '@nestjs/swagger'; -import { OrderStatus } from '../interface/order.interface'; +import { OrderStatusEnum } from '../interface/order.interface'; import { PaymentStatusEnum } from '../../payment/interface/payment'; const sortOrderOptions = ['asc', 'desc'] as const; @@ -31,13 +31,10 @@ export class FindOrdersDto { @Min(1) limit: number = 10; - /** - * ?statuses=paid,confirmed - * ?statuses=paid&statuses=confirmed - */ + @ApiPropertyOptional({ description: 'Filter by order statuses', - enum: OrderStatus, + enum: OrderStatusEnum, isArray: true, }) @IsOptional() @@ -45,13 +42,13 @@ export class FindOrdersDto { Array.isArray(value) ? value : value?.split(',') ) @IsArray() - @IsEnum(OrderStatus, { each: true }) - statuses?: OrderStatus[]; + @IsEnum(OrderStatusEnum, { each: true }) + statuses?: OrderStatusEnum[]; - @ApiPropertyOptional({ enum: PaymentStatusEnum }) - @IsOptional() - @IsEnum(PaymentStatusEnum) - paymentStatus?: PaymentStatusEnum; + // @ApiPropertyOptional({ enum: PaymentStatusEnum }) + // @IsOptional() + // @IsEnum(PaymentStatusEnum) + // paymentStatus?: PaymentStatusEnum; @ApiPropertyOptional() @IsOptional() @@ -61,12 +58,12 @@ export class FindOrdersDto { @ApiPropertyOptional({ format: 'date-time' }) @IsOptional() @IsDateString() - startDate?: string; + from?: string; @ApiPropertyOptional({ format: 'date-time' }) @IsOptional() @IsDateString() - endDate?: string; + to?: string; @ApiPropertyOptional({ default: 'createdAt' }) @IsOptional() diff --git a/src/modules/order/entities/order.entity.ts b/src/modules/order/entities/order.entity.ts index d0b13db..f9d4cf2 100644 --- a/src/modules/order/entities/order.entity.ts +++ b/src/modules/order/entities/order.entity.ts @@ -10,7 +10,7 @@ import { PrimaryKey, } from '@mikro-orm/core'; import { BaseEntity } from '../../../common/entities/base.entity'; -import { OrderStatus } from '../interface/order.interface'; +import { OrderStatusEnum } from '../interface/order.interface'; import { User } from '../../user/entities/user.entity'; import { OrderItem } from './order-item.entity'; import { Payment } from 'src/modules/payment/entities/payment.entity'; @@ -68,7 +68,7 @@ export class Order extends BaseEntity { // description?: string; - @Enum(() => OrderStatus) - status!: OrderStatus; + @Enum(() => OrderStatusEnum) + status!: OrderStatusEnum; } diff --git a/src/modules/order/events/order.events.ts b/src/modules/order/events/order.events.ts index f7713fe..f937188 100644 --- a/src/modules/order/events/order.events.ts +++ b/src/modules/order/events/order.events.ts @@ -1,4 +1,4 @@ -import type { OrderStatus } from '../interface/order.interface'; +import type { OrderStatusEnum } from '../interface/order.interface'; export class OrderCreatedEvent { constructor( @@ -15,7 +15,7 @@ export class OrderStatusChangedEvent { public readonly userId: string, public readonly orderNumber: string, public readonly: string, - public readonly previousStatus: OrderStatus, - public readonly newStatus: OrderStatus, + public readonly previousStatus: OrderStatusEnum, + public readonly newStatus: OrderStatusEnum, ) { } } diff --git a/src/modules/order/interface/order.interface.ts b/src/modules/order/interface/order.interface.ts index 58767a5..3914d08 100644 --- a/src/modules/order/interface/order.interface.ts +++ b/src/modules/order/interface/order.interface.ts @@ -1,5 +1,6 @@ -export enum OrderStatus { +export enum OrderStatusEnum { NEW = 'new', + INVOICE = 'invoice', PREPARING = 'preparing', COMPLETED = 'completed', CANCELED = 'canceled', diff --git a/src/modules/order/listeners/order.listeners.ts b/src/modules/order/listeners/order.listeners.ts index a52a592..9b214d1 100644 --- a/src/modules/order/listeners/order.listeners.ts +++ b/src/modules/order/listeners/order.listeners.ts @@ -7,10 +7,10 @@ import { NotifTitleEnum } from 'src/modules/notification/interfaces/notification import { NotificationService } from 'src/modules/notification/services/notification.service'; import { ConfigService } from '@nestjs/config'; import { OrderRepository } from '../repositories/order.repository'; -import { OrderStatus } from '../interface/order.interface'; +import { OrderStatusEnum } from '../interface/order.interface'; import { PaymentMethodEnum } from 'src/modules/payment/interface/payment'; import { UserService } from 'src/modules/user/providers/user.service'; - + @Injectable() export class OrderListeners { private readonly logger = new Logger(OrderListeners.name); @@ -63,7 +63,7 @@ export class OrderListeners { // })); // await this.notificationService.sendNotification({ - + // message: { // title: NotifTitleEnum.ORDER_CREATED, // content: `سفارش شماره ${event.orderNumber} با مبلغ ${event.total} تومان با موفقیت ایجاد شد`, diff --git a/src/modules/order/providers/orders.service.ts b/src/modules/order/providers/orders.service.ts index cc510d4..d57e65a 100644 --- a/src/modules/order/providers/orders.service.ts +++ b/src/modules/order/providers/orders.service.ts @@ -3,23 +3,18 @@ import { EntityManager } from '@mikro-orm/postgresql'; import { Order } from '../entities/order.entity'; import { OrderItem } from '../entities/order-item.entity'; import { User } from '../../user/entities/user.entity'; - import { PaymentMethodEnum, PaymentStatusEnum } from '../../payment/interface/payment'; - import { PaymentsService } from '../../payment/services/payments.service'; - import { OrderRepository } from '../repositories/order.repository'; import { FindOrdersDto } from '../dto/find-orders.dto'; import { PaginatedResult } from 'src/common/interfaces/pagination.interface'; import { Payment } from 'src/modules/payment/entities/payment.entity'; - - import { EventEmitter2 } from '@nestjs/event-emitter'; import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events'; import { OrderMessage } from 'src/common/enums/message.enum'; import { CreateOrderDto } from '../dto/create-order.dto'; import { UserService } from 'src/modules/user/providers/user.service'; -import { OrderItemStatus, OrderStatus } from '../interface/order.interface'; +import { OrderItemStatus, OrderStatusEnum } from '../interface/order.interface'; import { OrderItemRepository } from '../repositories/order-item.repository'; import { ProductService } from 'src/modules/product/providers/product.service'; import { ProductRepository } from 'src/modules/product/repositories/product.repository'; @@ -62,7 +57,7 @@ export class OrdersService { total: 0, paidAmount: 0, balance: 0, - status: OrderStatus.NEW + status: OrderStatusEnum.NEW }) em.persist(order) @@ -109,4 +104,8 @@ export class OrdersService { return order } + async findAllForUser(userId: string, dto: FindOrdersDto) { + const orders = await this.orderRepository.findAllPaginated({ userId, ...dto }) + return orders + } } diff --git a/src/modules/order/repositories/order.repository.ts b/src/modules/order/repositories/order.repository.ts index 1262042..3c05e95 100644 --- a/src/modules/order/repositories/order.repository.ts +++ b/src/modules/order/repositories/order.repository.ts @@ -3,22 +3,13 @@ import { EntityManager, EntityRepository } from '@mikro-orm/postgresql'; import { FilterQuery } from '@mikro-orm/core'; import { Order } from '../entities/order.entity'; import { PaginatedResult } from 'src/common/interfaces/pagination.interface'; -import { OrderStatus } from '../interface/order.interface'; +import { OrderStatusEnum } from '../interface/order.interface'; import { PaymentMethodEnum, PaymentStatusEnum } from '../../payment/interface/payment'; - +import { FindOrdersDto } from '../dto/find-orders.dto'; -type FindOrdersOpts = { - page?: number; - limit?: number; - statuses?: OrderStatus[]; - paymentStatus?: PaymentStatusEnum; - search?: string; - startDate?: string; - endDate?: string; - orderBy?: string; - order?: 'asc' | 'desc'; + +class FindOrdersOpts extends FindOrdersDto { userId?: string; - excludeOnlinePendingPayment?: boolean; }; @Injectable() @@ -31,30 +22,29 @@ export class OrderRepository extends EntityRepository { * Find orders with pagination and optional filters. * Supports: statuses, paymentStatus, search (orderNumber), date range, ordering. */ - async findAllPaginated( opts: FindOrdersOpts = {}): Promise> { + async findAllPaginated(opts: FindOrdersOpts): Promise> { const { page = 1, limit = 10, statuses, search, - startDate, - endDate, orderBy = 'createdAt', order = 'desc', userId, - excludeOnlinePendingPayment = false, + from, + to } = opts; const offset = (page - 1) * limit; - const where: FilterQuery = { }; + const where: FilterQuery = {}; // Filter by statuses if (statuses) { // Ensure statuses is always an array and normalize it const normalizedStatuses = Array.isArray(statuses) ? statuses : [statuses]; // Filter out any empty values - const validStatuses = normalizedStatuses.filter((s): s is OrderStatus => !!s); + const validStatuses = normalizedStatuses.filter((s): s is OrderStatusEnum => !!s); if (validStatuses.length > 0) { // Use direct equality for single value, $in for multiple values to avoid SQL generation issues @@ -71,13 +61,13 @@ export class OrderRepository extends EntityRepository { } // Filter by date range - if (startDate || endDate) { + if (from || to) { where.createdAt = {}; - if (startDate) { - where.createdAt.$gte = new Date(startDate); + if (from) { + where.createdAt.$gte = new Date(from); } - if (endDate) { - where.createdAt.$lte = new Date(endDate); + if (to) { + where.createdAt.$lte = new Date(to); } } @@ -99,40 +89,38 @@ export class OrderRepository extends EntityRepository { where.$or = searchConditions; } - - // First, fetch orders without reviews const [data, total] = await this.findAndCount(where, { limit, offset, orderBy: { [orderBy]: order.toLowerCase() as 'asc' | 'desc' }, - populate: ['user', 'restaurant', 'deliveryMethod', 'paymentMethod', 'items', 'items.product'] as never, + populate: ['items','items.product'], }); // Collect all (orderId, productId) pairs for efficient review lookup - const orderproductPairs: Array<{ orderId: string; productId: bigint }> = []; - for (const order of data) { - for (const item of order.items.getItems()) { - if (item.product?.id) { - orderproductPairs.push({ orderId: order.id, productId: item.product.id }); - } - } - } + // const orderproductPairs: Array<{ orderId: string; productId: bigint }> = []; + // for (const order of data) { + // for (const item of order.items.getItems()) { + // if (item.product?.id) { + // orderproductPairs.push({ orderId: order.id, productId: item.product.id }); + // } + // } + // } + - // Map reviewIds to products - for (const order of data) { - for (const item of order.items.getItems()) { - if (item.product) { - const key = `${order.id}-${item.product.id}`; - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const product = item.product as any; - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - - } - } - } + // for (const order of data) { + // for (const item of order.items.getItems()) { + // if (item.product) { + // const key = `${order.id}-${item.product.id}`; + // // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + // const product = item.product as any; + // // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + + // } + // } + // } const totalPages = Math.ceil(total / limit); diff --git a/src/modules/payment/services/payments.service.ts b/src/modules/payment/services/payments.service.ts index 5a377ea..2ddb18e 100644 --- a/src/modules/payment/services/payments.service.ts +++ b/src/modules/payment/services/payments.service.ts @@ -5,13 +5,13 @@ import { EntityManager } from '@mikro-orm/postgresql'; import { Order } from '../../order/entities/order.entity'; import { Logger } from '@nestjs/common'; import { GatewayManager } from '../gateways/gateway.manager'; - import { OrderPaymentContext } from '../interface/payment'; -import { OrderStatus } from 'src/modules/order/interface/order.interface'; +import { OrderPaymentContext } from '../interface/payment'; +import { OrderStatusEnum } from 'src/modules/order/interface/order.interface'; import { ChartPeriodEnum, PaymentChartDto } from '../dto/payment-chart.dto'; import { PaymentMessage, OrderMessage } from 'src/common/enums/message.enum'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { onlinePaymentSucceedEvent, paymentSucceedEvent } from '../events/payment.events'; - + @Injectable() export class PaymentsService { private readonly logger = new Logger(PaymentsService.name); @@ -91,7 +91,7 @@ export class PaymentsService { // }); // } - + // private async handleWalletPayment(ctx: OrderPaymentContext): Promise { // await this.em.transactional(async em => { // const order = await em.findOne(Order, { id: ctx.order.id }, { populate: ['user', 'restaurant'] });