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
| Regra | Significado |
|---|---|
| Estoque por lote | O saldo físico é sempre no Lot (Quantity em unidade base do produto). |
| Variante no lote | Lot.ProductVariantId: null = matéria-prima ou bulk; preenchido = semi/acabado com SKU (envase). |
| OP não gera SKU | ProductionOrder produz apenas bulk: lote de saída com ProductVariantId == null. |
| Envase separado | PackagingOrder consome um lote bulk e produz um lote com ProductVariantId == TargetVariantId. |
| Fórmula só na OP | PackagingOrder não altera fórmula; BOM permanece em ProductionOrder + Formula / ProductionOrderComponent. |
| Quantidades em base | Planejado, produzido e perdas de envase usam unidade base do produto. |
| Movimento alinhado ao lote | Em StockMovementItem, se LotId estiver preenchido, ProductVariantId do item deve coincidir com Lot.ProductVariantId (ambos null ou o mesmo id). |
| Serial no lote embalado | SerialNumber 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(etapaPackagingemProductionOrderStageTypeé legado/informativa, não substituiPackagingOrder). - 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
LotIddeve terProductVariantId == nulle quantidade coerente com a ordem quando a OP é criada/atualizada ou finalizada. - Consumo de insumos: via
ProductionOrderComponent(ligação à fórmula porFormulaComponentId, maisLotIde 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
| Contexto | ProductVariantId |
|---|---|
| Matéria-prima / bulk | null |
| Saída de envase / SKU | Igual à 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
SourceLot.ProductId == ProductIdeSourceLot.ProductVariantId == null.TargetVariant.ProductId == ProductId.- Lote de saída:
ProductIdcoerente eProductVariantId == TargetVariantId. - Consumo de bulk na conclusão:
ProducedQuantity + LossQuantityretirados doSourceLot.Quantity. - Acréscimo no lote de saída:
ProducedQuantity(base). TrackSerialna variante:ProducedQuantityinteiro na base; geração deSerialNumberpor unidade, comLotIdeProductVariantIddo 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)
| Recurso | Rotas |
|---|---|
| Ordens de produção | /api/production-orders, /api/production-orders/{id}, … (existente) |
| Ordens de envase | GET/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.