API — Fichas Técnicas (BOM)
Autenticação
Todos os endpoints requerem JWT com role admin ou superadmin e permissão manage_inventory.
Base: /t/:slug/bom
GET /t/:slug/bom
Lista todos os itens do cardápio com o custo atual (último snapshot).
Response 200:
json
[
{
"menuItemId": "...",
"name": "Filé ao Molho",
"sellingPrice": 8500,
"latestSnapshot": {
"totalDirectCost": 3200,
"totalIndirectCost": 480,
"totalCostPerUnit": 3680,
"triggeredBy": "nfe_import",
"createdAt": "2026-04-02T10:00:00.000Z"
},
"marginPercent": 56.7
}
]GET /t/:slug/bom/:menuItemId
Retorna o detalhe completo do BOM de um item: ingredientes, custos indiretos e último snapshot.
Response 200:
json
{
"menuItem": { "_id": "...", "name": "Filé ao Molho", "price": 8500 },
"ingredients": [
{
"inventoryItemId": "...",
"inventoryItemName": "Filé Mignon",
"quantityPerUnit": 0.3,
"unit": "kg",
"currentCostPrice": 12000,
"lineCost": 3600
}
],
"indirectCosts": [
{ "_id": "...", "type": "packaging", "label": "Embalagem descartável", "valuePerUnit": 150, "unitType": "fixed" },
{ "_id": "...", "type": "labor", "label": "Mão de obra", "valuePerUnit": 0.12, "unitType": "percentage_of_direct" }
],
"latestSnapshot": {
"totalDirectCost": 3600,
"totalIndirectCost": 582,
"totalCostPerUnit": 4182,
"suggestedSellingPrice": null,
"triggeredBy": "nfe_import",
"ingredientSnapshot": [...],
"createdAt": "2026-04-02T10:00:00.000Z"
}
}POST /t/:slug/bom/:menuItemId/calculate
Recalcula o custo e gera um novo BomCostSnapshot.
Body:
json
{
"targetMargin": 0.60
}| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
targetMargin | number | Não | Margem desejada 0–0.99 (ex: 0.60 = 60%). Gera suggestedSellingPrice. |
Response 201:
json
{
"_id": "...",
"menuItem": "...",
"totalDirectCost": 3600,
"totalIndirectCost": 582,
"totalCostPerUnit": 4182,
"suggestedSellingPrice": 10455,
"targetMargin": 0.60,
"triggeredBy": "manual",
"ingredientSnapshot": [...],
"indirectSnapshot": [...],
"createdAt": "2026-04-02T11:00:00.000Z"
}GET /t/:slug/bom/:menuItemId/history
Retorna o histórico de snapshots de custo (mais recentes primeiro).
Query params:
| Param | Tipo | Descrição |
|---|---|---|
limit | number | Máximo de snapshots (padrão 20) |
Response 200:
json
[
{ "_id": "...", "totalCostPerUnit": 4182, "triggeredBy": "nfe_import", "createdAt": "2026-04-02T10:00:00.000Z" },
{ "_id": "...", "totalCostPerUnit": 3950, "triggeredBy": "manual", "createdAt": "2026-03-15T08:00:00.000Z" }
]POST /t/:slug/bom/indirect-costs
Cria um custo indireto para um item do cardápio.
Body:
json
{
"menuItemId": "...",
"type": "packaging",
"label": "Embalagem descartável",
"valuePerUnit": 0.50,
"unitType": "fixed"
}| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
menuItemId | string | Sim | ID do item do cardápio |
type | string | Sim | labor | energy | packaging | other |
label | string | Sim | Descrição |
valuePerUnit | number | Sim | Valor fixo (R$) ou fração (0.15 = 15%) |
unitType | string | Sim | fixed | percentage_of_direct |
Response 201: BomIndirectCost criado.
PUT /t/:slug/bom/indirect-costs/:id
Atualiza um custo indireto.
Body: Campos parciais do POST.
Response 200: Objeto atualizado.
DELETE /t/:slug/bom/indirect-costs/:id
Remove um custo indireto.
Response 200: { "deleted": true }