Fichas Técnicas (BOM — Bill of Materials)
Visão Geral
O módulo de Fichas Técnicas calcula o custo de produção de cada item do cardápio, combinando:
- Custo direto: insumos da composição (
ProductIngredient) × custo unitário atual do estoque - Custo indireto: mão de obra, energia, embalagens, etc. (fixo por unidade ou % do custo direto)
O custo é recalculado automaticamente sempre que:
- Uma NF-e de entrada é confirmada (novo
costPriceno estoque) - O custo de um insumo é atualizado manualmente no estoque
Localização
frontend-react/src/features/bom/index.tsx
Rota: /t/:slug/admin/bom
Estrutura de Dados
MenuItem
└──< ProductIngredient (existente) ← composição: item → insumo + qty
└──< BomIndirectCost (novo) ← custos indiretos por prato
└──< BomCostSnapshot (novo, append-only) ← histórico de custo
ProductIngredienté o schema existente do módulo de inventário — não foi alterado. O BOM constrói sobre ele sem duplicar.
Tipos de Custo Indireto
| Tipo | Label sugerido | unitType |
|---|---|---|
labor | Mão de Obra | fixed ou percentage_of_direct |
energy | Energia / Gás | fixed |
packaging | Embalagem | fixed |
other | Outro | qualquer |
fixed: valor em R$ por unidade produzidapercentage_of_direct: fração do custo direto (ex:0.15= 15%)
Fórmula de Cálculo
directCost = Σ(ProductIngredient.quantityPerUnit × InventoryItem.costPrice)
fixedIndirect = Σ(BomIndirectCost.valuePerUnit WHERE unitType='fixed')
percentIndirect = directCost × Σ(valuePerUnit WHERE unitType='percentage_of_direct')
totalCost = directCost + fixedIndirect + percentIndirect
suggestedPrice = totalCost / (1 − targetMargin) ← se targetMargin informadoBomCostSnapshot — Histórico Append-Only
Cada recálculo cria um novo snapshot, nunca atualiza o anterior. Isso garante auditoria completa.
O custo "atual" é sempre o snapshot mais recente: findOne().sort({ createdAt: -1 }).
| Campo | Descrição |
|---|---|
totalDirectCost | Custo direto de insumos |
totalIndirectCost | Total de custos indiretos |
totalCostPerUnit | Custo total por unidade |
suggestedSellingPrice | Preço sugerido de venda (se targetMargin fornecido) |
triggeredBy | manual | nfe_import | cost_update |
ingredientSnapshot | Detalhamento por ingrediente no momento do cálculo |
Indicadores na Lista
| Badge | Margem | Significado |
|---|---|---|
| Verde | ≥ 60% | Boa rentabilidade |
| Amarelo | 40–59% | Atenção |
| Vermelho | < 40% | Preço de venda inadequado |
Fórmula da margem: (preçoVenda − custo) / preçoVenda × 100
Componentes Frontend
| Componente | Descrição |
|---|---|
BomEditor | Layout 2 colunas: ingredientes (esq) + custos indiretos (dir); rodapé com resumo, input de margem e botão Calcular |
BomCostBreakdownCard | Barra visual diretos vs. indiretos |
BomHistoryChart | Sparkline de totalCostPerUnit por snapshot |
BomIndirectCostForm | Modal para criar/editar custo indireto |
Backend
backend/src/bom/bom.module.tsbackend/src/bom/bom.service.tsbackend/src/bom/bom.controller.tsbackend/src/bom/schemas/bom-indirect-cost.schema.tsbackend/src/bom/schemas/bom-cost-snapshot.schema.ts
Dependência Circular
InventoryModule ↔ BomModule e InboundNfeModule → BomModule são resolvidos com forwardRef().
Relacionados
- NF-e Entrada — Dispara recálculo automático
- Estoque — Fonte de
costPrice - API — Fichas Técnicas