order report by food
This commit is contained in:
@@ -12,6 +12,7 @@ import { UpdateOrderStatusDto } from '../dto/update-order-status.dto';
|
||||
import { Permissions } from 'src/common/decorators/permissions.decorator';
|
||||
import { Permission } from 'src/common/enums/permission.enum';
|
||||
import { AdminCreateOrderDto } from '../dto/admin-create-order.dto';
|
||||
import { FoodOrderReportDto } from '../dto/food-order-report.dto';
|
||||
|
||||
@ApiTags('orders')
|
||||
@ApiBearerAuth()
|
||||
@@ -127,4 +128,12 @@ export class OrdersController {
|
||||
getFoodSalesPieChart(@RestId() restId: string) {
|
||||
return this.ordersService.getFoodSalesPieChart(restId);
|
||||
}
|
||||
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(Permission.VIEW_REPORTS)
|
||||
@ApiOperation({ summary: 'Get order report grouped by food' })
|
||||
@Get('admin/orders/report/by-food')
|
||||
getFoodOrderReport(@RestId() restId: string, @Query() dto: FoodOrderReportDto) {
|
||||
return this.ordersService.getFoodOrderReport(restId, dto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { IsOptional, IsDateString, IsEnum } from 'class-validator';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export enum FoodOrderReportSortBy {
|
||||
Count = 'count',
|
||||
Price = 'price',
|
||||
}
|
||||
|
||||
export class FoodOrderReportDto {
|
||||
@ApiPropertyOptional({
|
||||
format: 'date-time',
|
||||
description: 'Filter orders from this date and time',
|
||||
example: '2024-01-01T08:00:00.000Z',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
from?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
format: 'date-time',
|
||||
description: 'Filter orders until this date and time',
|
||||
example: '2024-12-31T23:59:59.000Z',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
to?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
enum: FoodOrderReportSortBy,
|
||||
default: FoodOrderReportSortBy.Count,
|
||||
description: 'Sort results by order count or food price',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEnum(FoodOrderReportSortBy)
|
||||
sortBy: FoodOrderReportSortBy = FoodOrderReportSortBy.Count;
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events';
|
||||
import { OrderMessage } from 'src/common/enums/message.enum';
|
||||
import { AdminCreateOrderDto } from '../dto/admin-create-order.dto';
|
||||
import { FoodOrderReportDto, FoodOrderReportSortBy } from '../dto/food-order-report.dto';
|
||||
import { normalizePhone } from 'src/modules/utils/phone.util';
|
||||
type OrderItemData = { food: Food; quantity: number; unitPrice: number; discount: number };
|
||||
|
||||
@@ -766,4 +767,54 @@ console.log(cart);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async getFoodOrderReport(restId: string, dto: FoodOrderReportDto) {
|
||||
const { from, to, sortBy = FoodOrderReportSortBy.Count } = dto;
|
||||
|
||||
const params: unknown[] = [restId];
|
||||
const dateFilters: string[] = [];
|
||||
|
||||
if (from) {
|
||||
params.push(new Date(from));
|
||||
dateFilters.push(`AND o.created_at >= ?`);
|
||||
}
|
||||
|
||||
if (to) {
|
||||
params.push(new Date(to));
|
||||
dateFilters.push(`AND o.created_at <= ?`);
|
||||
}
|
||||
|
||||
const orderColumn = sortBy === FoodOrderReportSortBy.Price ? 'f.price' : 'count';
|
||||
|
||||
const result = await this.em.execute(
|
||||
`
|
||||
SELECT
|
||||
f.id as food_id,
|
||||
f.title as food_title,
|
||||
f.price as food_price,
|
||||
COALESCE(SUM(oi.quantity), 0)::int as count,
|
||||
COALESCE(SUM(oi.total_price), 0)::numeric as total_price
|
||||
FROM order_items oi
|
||||
INNER JOIN orders o ON oi.order_id = o.id
|
||||
INNER JOIN foods f ON oi.food_id = f.id
|
||||
WHERE o.restaurant_id = ?
|
||||
${dateFilters.join('\n ')}
|
||||
AND o.status NOT IN ('pendingPayment', 'canceled')
|
||||
GROUP BY f.id, f.title, f.price
|
||||
HAVING SUM(oi.quantity) > 0
|
||||
ORDER BY ${orderColumn} DESC
|
||||
`,
|
||||
params,
|
||||
);
|
||||
|
||||
return result.map((row: Record<string, unknown>) => ({
|
||||
food: {
|
||||
id: row.food_id,
|
||||
title: row.food_title,
|
||||
},
|
||||
count: Number(row.count || 0),
|
||||
price: Number(row.food_price || 0),
|
||||
totalPrice: Number(row.total_price || 0),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user