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
86 changes: 58 additions & 28 deletions docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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
}
}
}
}
]
}
}
}
Expand Down
3 changes: 3 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 @@ -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) {
Expand Down
84 changes: 64 additions & 20 deletions src/modules/kpi/kpi.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<number, number> = {};

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<number, number> = {};

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,
}));
}
}
}
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;
}
}