diff --git a/docs/swagger.json b/docs/swagger.json index 7268359..6660daa 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -3339,6 +3339,20 @@ "type": "string", "format": "date-time" } + }, + { + "name": "useCase", + "in": "query", + "description": "specific return for POS or KDS", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string", + "enum": [ + "POS" + ] + } } ], "responses": { @@ -3347,38 +3361,54 @@ "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "ingredients": { - "type": "array", - "description": "List of ingredients and required quantities", - "items": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "Ingredient ID", - "example": 12 - }, - "name": { - "type": "string", - "description": "Ingredient name", - "example": "Steak" - }, - "quantity": { - "type": "number", - "description": "Total quantity required", - "example": 42 - }, - "unit": { - "type": "string", - "description": "Ingredient unit", - "example": "Slice" - } + "oneOf": [ + { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Ingredient ID", + "example": 12 + }, + "name": { + "type": "string", + "description": "Ingredient name", + "example": "Steak" + }, + "quantity": { + "type": "number", + "description": "Total quantity required", + "example": 42 + }, + "unit": { + "type": "string", + "description": "Ingredient unit", + "example": "Slice" + } + } + } + }, + { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Ingredient ID", + "example": 12 + }, + "quantity": { + "type": "number", + "description": "Total quantity required", + "example": 42 } } } } + ] } } } diff --git a/src/modules/kpi/kpi.controller.ts b/src/modules/kpi/kpi.controller.ts index b82800b..277d7c7 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) @@ -308,12 +309,14 @@ export class KpiController { async kpiIngredientForecast( @Param('idRestaurant', PositiveNumberPipe) idRestaurant: number, @Query('date', DatePipe) date?: string, + @Query('useCase', UseCasePipe) useCase?: string, ) { try { const forecast = await this.kpiService.dishForecast(idRestaurant, date); const ingredients = await this.kpiService.ingredientsForecast( idRestaurant, forecast, + useCase, ); return ingredients; } catch (error) { diff --git a/src/modules/kpi/kpi.service.ts b/src/modules/kpi/kpi.service.ts index 8d7f47f..1d2c132 100644 --- a/src/modules/kpi/kpi.service.ts +++ b/src/modules/kpi/kpi.service.ts @@ -536,35 +536,79 @@ export class KpiService extends DB { async ingredientsForecast( idRestaurant: number, forecast: { food: number; forecast: number }[], + useCase: string = undefined, ) { const db = this.getDbConnection(); const foodIds = forecast.map((f) => f.food); const restaurant = await db .collection('restaurant') - .findOne({ id: idRestaurant }, { projection: { _id: 0, foods: 1 } }); - if (!restaurant || !restaurant.foods) return {}; + .findOne( + { id: idRestaurant }, + { projection: { _id: 0, foods: 1, ingredients: 1 } }, + ); + if (!restaurant || !restaurant.foods) return []; const forecastMap = new Map(forecast.map((f) => [f.food, f.forecast])); - const ingredientCount: Record = {}; - - restaurant.foods - .filter((food: any) => foodIds.includes(food.id)) - .forEach((food: any) => { - const forecastQty = forecastMap.get(food.id) || 0; - if (food.ingredients && Array.isArray(food.ingredients)) { - food.ingredients.forEach( - (ingredient: { id_ingredient: number; quantity: number }) => { - if (!ingredientCount[ingredient.id_ingredient]) - ingredientCount[ingredient.id_ingredient] = 0; - ingredientCount[ingredient.id_ingredient] += - (ingredient.quantity || 1) * forecastQty; - }, - ); - } - }); + if (useCase === 'POS') { + const ingredientCount: Record< + number, + { id: number; name: string; quantity: number; unit: string } + > = {}; + + restaurant.foods + .filter((food: any) => foodIds.includes(food.id)) + .forEach((food: any) => { + const forecastQty = forecastMap.get(food.id) || 0; + if (Array.isArray(food.ingredients)) { + food.ingredients.forEach( + (ingredient: { id_ingredient: number; quantity: number }) => { + const id = ingredient.id_ingredient; + const base = + restaurant.ingredients?.find((ing: any) => ing.id === id) || + {}; + + if (!ingredientCount[id]) { + ingredientCount[id] = { + id, + name: base.name || '', + quantity: 0, + unit: base.unit || '', + }; + } + ingredientCount[id].quantity += + (ingredient.quantity || 1) * forecastQty; + }, + ); + } + }); - return ingredientCount; + return Object.values(ingredientCount); + } else { + const ingredientCount: Record = {}; + + restaurant.foods + .filter((food: any) => foodIds.includes(food.id)) + .forEach((food: any) => { + const forecastQty = forecastMap.get(food.id) || 0; + if (Array.isArray(food.ingredients)) { + food.ingredients.forEach( + (ingredient: { id_ingredient: number; quantity: number }) => { + const id = ingredient.id_ingredient; + if (!ingredientCount[id]) { + ingredientCount[id] = 0; + } + ingredientCount[id] += (ingredient.quantity || 1) * forecastQty; + }, + ); + } + }); + + return Object.entries(ingredientCount).map(([id, quantity]) => ({ + id: parseInt(id, 10), + quantity, + })); + } } } 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; + } +}