Pular para o conteúdo principal

Ordens de produção: bulk, envase e lote

Visão production-centric: a produção química/industrial em bulk (sem SKU no lote de saída) está separada do envase (empacotamento em variante/SKU). O lote é o centro do estoque; a variante qualifica o lote quando existir.

flowchart TB
subgraph bulk [Produção bulk]
PO[ProductionOrder]
LB[Lot ProductVariantId null]
PO --> LB
end
subgraph envase [Envase]
PKO[PackagingOrder]
LV[Lot com ProductVariantId]
LB --> PKO
PKO --> LV
end
subgraph serial [Opcional]
SN[SerialNumber]
LV --> SN
end

Relacionamento lógico: 1 ProductionOrder → 1 lote de saída bulk; N PackagingOrders podem consumir o mesmo lote bulk (por SourceLotId), cada uma gerando (ou preenchendo) 1 lote de saída com a variante alvo.


Princípios e regras críticas

RegraSignificado
Estoque por loteO saldo físico é sempre no Lot (Quantity em unidade base do produto).
Variante no loteLot.ProductVariantId: null = matéria-prima ou bulk; preenchido = semi/acabado com SKU (envase).
OP não gera SKUProductionOrder produz apenas bulk: lote de saída com ProductVariantId == null.
Envase separadoPackagingOrder consome um lote bulk e produz um lote com ProductVariantId == TargetVariantId.
Fórmula só na OPPackagingOrder não altera fórmula; BOM permanece em ProductionOrder + Formula / ProductionOrderComponent.
Quantidades em basePlanejado, produzido e perdas de envase usam unidade base do produto.
Movimento alinhado ao loteEm StockMovementItem, se LotId estiver preenchido, ProductVariantId do item deve coincidir com Lot.ProductVariantId (ambos null ou o mesmo id).
Serial no lote embaladoSerialNumber opcional; unicidade (ProductId, Serial); deve estar coerente com lote/variante quando ambos definidos.

O que não fazer

  • Envase “de verdade” dentro do fluxo de ProductionOrder (etapa Packaging em ProductionOrderStageType é legado/informativa, não substitui PackagingOrder).
  • Duplicar produto por volume (usar ProductVariant).
  • Estoque “só por variant” sem lote.
  • Serial sem associação ao lote quando o processo é envase rastreado por lote.

ProductionOrder (bulk)

Ordem de produção ligada à fórmula (FormulaId), ao produto base (ProductId) e ao lote de saída (LotId). Mantém Quantity planejada/real na própria ordem; o lote de saída é sincronizado como bulk (sem variant).

ProductionOrder
- Id
- Code
- Quantity // unidade base
- FormulaId
- ProductId // produto base
- LotId // lote de saída (output)
- StatusId // ProductionOrderStatus
- ProductionRouteId // opcional
- CurrentStageTypeId // ProductionOrderStageType (MaterialSeparation … Packaging legado)
- StagesInitialized
- StartDate, EndDate
- Notes
- CreatedAt, UpdatedAt

Regras

  • Saída da OP: lote referenciado por LotId deve ter ProductVariantId == null e quantidade coerente com a ordem quando a OP é criada/atualizada ou finalizada.
  • Consumo de insumos: via ProductionOrderComponent (ligação à fórmula por FormulaComponentId, mais LotId e quantidade em base).
ProductionOrderComponent
- Id
- ProductionOrderId
- FormulaComponentId
- LotId
- Quantity // base

Lot (centro do estoque)

Lot
- Id
- ProductId
- ProductVariantId // null = bulk / MP; preenchido = lote com SKU
- Code
- Quantity // unidade base
- ManufactureDate, ExpirationDate
- IsActive
- CreatedAt, UpdatedAt

Regras

ContextoProductVariantId
Matéria-prima / bulknull
Saída de envase / SKUIgual à variante alvo (TargetVariantId da PackagingOrder)

Unicidade (persistência): índice único composto (ProductId, ProductVariantId, Code). Em bases onde NULL em colunas únicas comporta-se de forma especial, convém convenção de códigos de lote distintos entre bulk e variantes.

Navegação opcional: um lote pode ser saída de ProductionOrder; pode ser SourceLot ou OutputLot de PackagingOrder.


Etapas de produção (ProductionOrderStage)

Estrutura existente: instâncias por ProductionRouteStep, com linha, datas planejadas/reais, ProductionOrderStageStatus, análises (ProductionOrderStageAnalysis) e observações (ProductionOrderStageObservation).

ProductionOrderStageType (semântica)

Valores típicos: MaterialSeparation, Production, QualityControl, Correction, Packaging.

Regra: ProductionOrderStage não executa o envase industrial real; o envase operacional é PackagingOrder. O tipo Packaging na OP permanece como legado ou informativo.


PackagingOrder (envase)

Novo agregado no módulo Production. Consome quantidade do lote bulk e gera (ou atualiza) o lote com variante.

PackagingOrder
- Id
- Code
- ProductId
- SourceLotId // lote bulk (ProductVariantId null)
- TargetVariantId // ProductVariant (SKU)
- OutputLotId // opcional até conclusão; criado automaticamente se ausente
- StatusId // PackagingOrderStatus
- PlannedQuantity // base
- ProducedQuantity // preenchido na conclusão
- LossQuantity // perda de bulk na conclusão
- StartDate, EndDate
- CreatedAt, UpdatedAt

Regras

  1. SourceLot.ProductId == ProductId e SourceLot.ProductVariantId == null.
  2. TargetVariant.ProductId == ProductId.
  3. Lote de saída: ProductId coerente e ProductVariantId == TargetVariantId.
  4. Consumo de bulk na conclusão: ProducedQuantity + LossQuantity retirados do SourceLot.Quantity.
  5. Acréscimo no lote de saída: ProducedQuantity (base).
  6. TrackSerial na variante: ProducedQuantity inteiro na base; geração de SerialNumber por unidade, com LotId e ProductVariantId do output.

Status: enum espelhando o ciclo da OP (Created, Planned, InProgress, Paused, Finished, Canceled), com tabela de definição DefPackagingOrderStatus.


PackagingOrderStage

Etapas de execução do envase (sem ProductionRouteStep na primeira versão): linha de produção opcional, datas e status de etapa reutilizando ProductionOrderStageStatus / DefProductionOrderStageStatus.

PackagingOrderStage
- Id
- PackagingOrderId
- ProductionLineId // opcional
- StatusId // ProductionOrderStageStatus
- PlannedStart, PlannedEnd
- ActualStart, ActualEnd
- Notes
- CreatedAt, UpdatedAt

Observações: PackagingOrderStageObservation (espelho do modelo de observações da OP). Análises de qualidade por etapa de envase podem evoluir em fase posterior (ex.: ligação a ProductQualityAnalysis).


PackagingOrderComponent (opcional)

Materiais de embalagem (rótulo, caixa, etc.), por produto e lote.

PackagingOrderComponent
- Id
- PackagingOrderId
- ProductId
- LotId
- Quantity // base

SerialNumber (envase)

SerialNumber
- Id
- ProductId
- ProductVariantId // opcional; alinhado ao lote quando aplicável
- LotId // lote embalado
- Serial
- Status
- ...

Unicidade: (ProductId, Serial). Na API de validação, ProductVariantId e LotId devem ser coerentes com o lote quando informados.


StockMovementItem (ajuste de regra)

StockMovementItem
- ProductId
- ProductVariantId // nullable; se LotId preenchido, igual ao lote
- LotId
- Quantity // base
- TrackSerial

Na conclusão do envase, a API gera movimentos Consumption (bulk) e Production (saída com variant), ambos em estado concluído, com notas referenciando o id da PackagingOrder para rastreabilidade.


Exposição HTTP (contrato)

RecursoRotas
Ordens de produção/api/production-orders, /api/production-orders/{id}, … (existente)
Ordens de envaseGET/POST /api/packaging-orders, GET/PUT/DELETE /api/packaging-orders/{id}, POST .../start, POST .../complete, POST .../stages, POST .../stages/{stageId}/observations, POST .../components

Políticas de autorização alinhadas às de produção (ProductionView, ProductionCreate, ProductionUpdate, ProductionDelete).


Ver também

  • Produto, variantes, serial e lote — catálogo, conversão, movimentos e índices.
  • Código de domínio: Production.Domain/Modules/Production/Entities, Products/Entities/Lots, StockMovements/Entities.