Skip to content

Custo Médio Ponderado Móvel

Visão Geral

O PopinaFlow usa o método de Custo Médio Ponderado Móvel (weighted-average moving cost) para calcular o custo unitário de cada item do estoque. O custo é recalculado a cada entrada de mercadoria — NF-e importada, Pedido de Compra recebido ou ajuste manual.

Este método é o mais utilizado por restaurantes brasileiros e está alinhado com os critérios do Pronunciamento Técnico CPC 16 (Estoques) e com o leiaute do SPED.


Fórmula

novo_custo_unitario = ((qtd_atual × custo_atual) + (qtd_recebida × custo_recebido))
                      ÷ (qtd_atual + qtd_recebida)

Casos de borda

SituaçãoComportamento
qtd_recebida ≤ 0Custo inalterado — nenhuma entrada para calcular
qtd_atual ≤ 0Custo passa a ser o custo_recebido — evita divisão por zero

O resultado é arredondado a 4 casas decimais (Math.round(x * 10000) / 10000).

Arquivo: backend/src/inventory/utils/cost-calculator.ts — função computeMovingAverage()


Quando o custo é atualizado

EventoGatilhoComo
Importação de NF-eNfeImportPipelineService.applyImport() (Passo 10)Chama computeMovingAverage() e persiste via InventoryItem.$set costPrice = newAvgCost
Recebimento de Pedido de CompraPurchaseOrderService.receiveItems()Mesmo cálculo por item recebido
Ajuste de entrada manualInventoryService.createMovement() com type: 'entry'Custo médio atualizado se unitCost for fornecido

Exemplo prático (importação NF-e)

Estoque atual: 100 UN × R$ 2,00/UN = R$ 200,00
Entrada NF-e:   50 UN × R$ 2,40/UN = R$ 120,00

Rateio frete (10%): custo efetivo NF-e = R$ 2,40 × 1,10 = R$ 2,64/UN

novo_custo = (100 × 2,00 + 50 × 2,64) / 150
           = (200,00 + 132,00) / 150
           = R$ 2,2133/UN

O campo InventoryItem.costPrice passa a ser 2.2133.


Relação com a DRE (CMV)

O custo médio ponderado é usado pelo módulo DRE para calcular o Custo das Mercadorias Vendidas (CMV):

CMV = Σ (qty_vendida × costPrice) por item no período

As movimentações de saída por venda (type: 'exit', reason: 'sale') geradas em OrdersService.processOrderInventory() registram o unitCost vigente no momento da venda, preservando a rastreabilidade histórica independentemente de atualizações de custo futuras.


Método COGS por Lote (FIFO/FEFO/Média)

Para empresas com controle de lotes (InventoryLot), o serviço CogsCalculationService (backend/src/inventory/cogs-calculation.service.ts) suporta três métodos:

MétodoAlgoritmoIdeal para
FIFOLotes ordenados por receivedDate ASC — consome o mais antigo primeiroProdutos não perecíveis, industrial
FEFOLotes ordenados por expiryDate ASC (nulos por último) — consome o que vence antesPadrão para alimentos
weighted_avgCusto médio ponderado de todos os lotes ativosCommodities sem diferença de lote

O método é configurado por item no campo InventoryItem.costMethod. Se não configurado, o default é FEFO.

API de simulação COGS

POST /t/:slug/inventory/:itemId/cogs-simulation
Body: { "qtyConsumed": 30 }

Retorna CogsResult com:

  • totalCost — custo total da baixa
  • method — método aplicado
  • lotsConsumed — detalhamento por lote (lotId, qty, unitCost, lineCost)
  • qtyCostable — quantidade efetivamente custeable (pode ser < qtyConsumed se estoque insuficiente)
  • shortfall — quantidade sem cobertura de lote

Esta chamada é somente-leitura — não altera lotes.


Alertas de Variação de Preço

Ao importar uma NF-e, o pipeline verifica se o costPerSupplierUnit da nota difere mais de 5% do lastSeenPrice registrado no SupplierProductMap. Se sim, um alerta de variação aparece no Ledger de importação com badge âmbar.


Relacionados

Lançado sob a licença MIT.