Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
113 changes: 113 additions & 0 deletions src/modules/kpi/kpi.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
}
}
14 changes: 8 additions & 6 deletions src/modules/kpi/kpi.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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 =
Expand Down Expand Up @@ -189,8 +193,6 @@ export class KpiService extends DB {
});
});

console.log(dishMap);

const resultArray = [];
for (const [food, times] of dishMap.entries()) {
const averageTime =
Expand Down
11 changes: 11 additions & 0 deletions src/modules/kpi/pipe/useCase.pipe.ts
Original file line number Diff line number Diff line change
@@ -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;
}
}