diff --git a/docs/swagger.json b/docs/swagger.json index 7268359..4946a04 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -3402,6 +3402,103 @@ } ] } + }, + "/{restaurant_id}/kpi/displayKpi": { + "summary": "KPI endpoints", + "get": { + "tags": [ + "KPI" + ], + "summary": "Récupérer les KPIs pour un cas d'usage spécifique (POS ou KDS)", + "parameters": [ + { + "name": "restaurant_id", + "in": "path", + "description": "ID du restaurant", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "type": "integer" + } + }, + { + "name": "useCase", + "in": "query", + "description": "Cas d'usage (POS ou KDS)", + "required": true, + "schema": { + "type": "string", + "enum": ["POS", "KDS"] + } + } + ], + "responses": { + "200": { + "description": "KPIs pour le cas d'usage demandé", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "ordersInProgress": { "type": "integer", "description": "Nombre de commandes en cours" }, + "clientsCount": { "type": "integer", "description": "Nombre de clients sur place aujourd'hui" }, + "averageWaitingTime1h": { "type": "object", "description": "Temps d'attente moyen sur 1h", "properties": { "hours": { "type": "integer" }, "minutes": { "type": "integer" }, "seconds": { "type": "integer" } } }, + "averageWaitingTime15m": { "type": "object", "description": "Temps d'attente moyen sur 15min", "properties": { "hours": { "type": "integer" }, "minutes": { "type": "integer" }, "seconds": { "type": "integer" } } }, + "averagePrepTime1h": { "type": "object", "description": "Temps de préparation moyen sur 1h", "properties": { "hours": { "type": "integer" }, "minutes": { "type": "integer" }, "seconds": { "type": "integer" } } }, + "averagePrepTime15m": { "type": "object", "description": "Temps de préparation moyen sur 15min", "properties": { "hours": { "type": "integer" }, "minutes": { "type": "integer" }, "seconds": { "type": "integer" } } } + }, + "example": { + "ordersInProgress": 100, + "clientsCount": 100, + "averageWaitingTime1h": { "hours": 0, "minutes": 10, "seconds": 0 }, + "averageWaitingTime15m": { "hours": 0, "minutes": 8, "seconds": 30 }, + "averagePrepTime1h": { "hours": 0, "minutes": 12, "seconds": 0 }, + "averagePrepTime15m": { "hours": 0, "minutes": 9, "seconds": 45 } + } + }, + { + "type": "object", + "properties": { + "last15mOrders": { "type": "integer", "description": "Nombre de commandes sur les 15 dernières minutes" }, + "clientsCount": { "type": "integer", "description": "Nombre de clients sur place aujourd'hui" }, + "averageWaitingTime1h": { "type": "object", "description": "Temps d'attente moyen sur 1h", "properties": { "hours": { "type": "integer" }, "minutes": { "type": "integer" }, "seconds": { "type": "integer" } } }, + "averageWaitingTime15m": { "type": "object", "description": "Temps d'attente moyen sur 15min", "properties": { "hours": { "type": "integer" }, "minutes": { "type": "integer" }, "seconds": { "type": "integer" } } }, + "averagePrepTime1h": { "type": "object", "description": "Temps de préparation moyen sur 1h", "properties": { "hours": { "type": "integer" }, "minutes": { "type": "integer" }, "seconds": { "type": "integer" } } }, + "averagePrepTime15m": { "type": "object", "description": "Temps de préparation moyen sur 15min", "properties": { "hours": { "type": "integer" }, "minutes": { "type": "integer" }, "seconds": { "type": "integer" } } } + }, + "example": { + "last15mOrders": 20, + "clientsCount": 100, + "averageWaitingTime1h": { "hours": 0, "minutes": 10, "seconds": 0 }, + "averageWaitingTime15m": { "hours": 0, "minutes": 8, "seconds": 30 }, + "averagePrepTime1h": { "hours": 0, "minutes": 12, "seconds": 0 }, + "averagePrepTime15m": { "hours": 0, "minutes": 9, "seconds": 45 } + } + } + ] + } + } + } + }, + "400": { + "description": "Paramètres invalides" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "5XX": { + "$ref": "#/components/responses/ServerError" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } } }, "components": { diff --git a/src/modules/kpi/kpi.controller.ts b/src/modules/kpi/kpi.controller.ts index b82800b..1d84fa9 100644 --- a/src/modules/kpi/kpi.controller.ts +++ b/src/modules/kpi/kpi.controller.ts @@ -15,6 +15,7 @@ import { JwtAuthGuard } from '../../shared/guards/jwt-auth.guard'; import { BreakdownPipe } from './pipe/breakdown.pipe'; import { ChannelPipe } from './pipe/channel.pipe'; import { ServedPipe } from './pipe/served.pipe'; +import { UseCasePipe } from './pipe/useCase.pipe'; @Controller('api/:idRestaurant/kpi') @UseGuards(JwtAuthGuard) @@ -325,4 +326,116 @@ export class KpiController { throw new InternalServerErrorException('Server error'); } } + + /** + * Get the KPIs for a specific use case + * @param idRestaurant - The restaurant identifier (must be positive) + * @param useCase - The use case (POS or KDS) + * @returns The KPIs for the specified use case + * @throws {BadRequestException} When input parameters are invalid + * @throws {InternalServerErrorException} When server encounters an error + * @example + * GET /api/1/kpi/displayKpi?useCase=POS + * // returns { ordersInProgress: 100, clientsCount: 100, averageWaitingTime1h: 100, averageWaitingTime15m: 100, averagePrepTime1h: 100, averagePrepTime15m: 100 } + */ + @Get('displayKpi') + async kpiDisplayKpi( + @Param('idRestaurant', PositiveNumberPipe) idRestaurant: number, + @Query('useCase', UseCasePipe) useCase: string, + ) { + const today = new Date().toISOString(); + const tomorrow = new Date(today); + tomorrow.setDate(tomorrow.getDate() + 1); + const oneHourAgo = new Date( + new Date().getTime() - 1 * 60 * 60 * 1000, + ).toISOString(); + const fifteenMinutesAgo = new Date( + new Date().getTime() - 15 * 60 * 1000, + ).toISOString(); + if (useCase === 'POS') { + const res = { + ordersInProgress: await this.kpiService.clientsCount( + idRestaurant, + today.split('T')[0], + tomorrow.toISOString().split('T')[0], + undefined, + undefined, + ), + clientsCount: await this.kpiService.clientsCount( + idRestaurant, + today.split('T')[0], + tomorrow.toISOString().split('T')[0], + 'Sur place', + undefined, + ), + averagePrepTime1h: await this.kpiService.averageAllDishesTime( + idRestaurant, + oneHourAgo, + today, + true, + ), + averagePrepTime15m: await this.kpiService.averageAllDishesTime( + idRestaurant, + fifteenMinutesAgo, + today, + true, + ), + averageWaitingTime1h: await this.kpiService.averageTimeOrders( + idRestaurant, + oneHourAgo, + today, + undefined, + ), + averageWaitingTime15m: await this.kpiService.averageTimeOrders( + idRestaurant, + fifteenMinutesAgo, + today, + undefined, + ), + }; + return res; + } else { + const res = { + last15mOrders: await this.kpiService.clientsCount( + idRestaurant, + fifteenMinutesAgo, + today, + undefined, + undefined, + ), + clientsCount: await this.kpiService.clientsCount( + idRestaurant, + today.split('T')[0], + tomorrow.toISOString().split('T')[0], + 'Sur place', + undefined, + ), + averagePrepTime1h: await this.kpiService.averageAllDishesTime( + idRestaurant, + oneHourAgo, + today, + true, + ), + averagePrepTime15m: await this.kpiService.averageAllDishesTime( + idRestaurant, + fifteenMinutesAgo, + today, + true, + ), + averageWaitingTime1h: await this.kpiService.averageTimeOrders( + idRestaurant, + oneHourAgo, + today, + undefined, + ), + averageWaitingTime15m: await this.kpiService.averageTimeOrders( + idRestaurant, + fifteenMinutesAgo, + today, + undefined, + ), + }; + return res; + } + } } diff --git a/src/modules/kpi/kpi.service.ts b/src/modules/kpi/kpi.service.ts index 8d7f47f..dc47e43 100644 --- a/src/modules/kpi/kpi.service.ts +++ b/src/modules/kpi/kpi.service.ts @@ -137,10 +137,7 @@ export class KpiService extends DB { }); } - console.log(breakdown); - if (breakdown) { - console.log('breakdown'); result.map((item) => { const orderDate = new Date(item.orders.date); @@ -152,7 +149,14 @@ export class KpiService extends DB { }); if (preparationTimes.length === 0) { - return null; + return { + time: { + hours: 0, + minutes: 0, + seconds: 0, + }, + nbrOrders: 0, + }; } const averageTime = @@ -189,8 +193,6 @@ export class KpiService extends DB { }); }); - console.log(dishMap); - const resultArray = []; for (const [food, times] of dishMap.entries()) { const averageTime = diff --git a/src/modules/kpi/pipe/useCase.pipe.ts b/src/modules/kpi/pipe/useCase.pipe.ts new file mode 100644 index 0000000..060aa17 --- /dev/null +++ b/src/modules/kpi/pipe/useCase.pipe.ts @@ -0,0 +1,11 @@ +import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common'; + +@Injectable() +export class UseCasePipe implements PipeTransform { + transform(value: any) { + if (value === undefined) return value; + if (typeof value !== 'string') throw new BadRequestException(); + if (value !== 'POS' && value !== 'KDS') return undefined; + return value; + } +}