Seleção Automática do Lote mais Antigo (FIFO por validade)
Tela de configuração: MFA001 - Parâmetros de Faturamento Localização: Parâmetros → Faturamento → Opção 2 → campo Selecionar Lote mais Antigo [MPD002/MNF002] (habilitado somente quando
TP_CONTROLELOTE = 'A'Agrupado) Tabela:PARMFATUR.ST_SELECIONALOTEANTIGOValor padrão: não há default explícito noAfterInsert— o campo nasce vazio/NULL e é forçado a'N'toda vez que o usuário muda TP_CONTROLELOTE para'I'(Individual). Só pode ser editado comTP_CONTROLELOTE = 'A'(Agrupado) — verUMFA001.pas:920, 2444, 2461-2465.
Telas impactadas
| Módulo | Código | Onde lê | Papel |
|---|---|---|---|
Tela de Rateio de Lote Agrupado (chamada por todo módulo que executa RateioLoteProducao com tipo 'SA') | jLoteProducao/ULoteSaidaAgrupado | ULoteSaidaAgrupado.pas:183-189 (SELECT em CarregarSaidaAgrupada), ULoteSaidaAgrupado.pas:1289 (bloco ativo if parmFatur.Values['ST_SELECIONALOTEANTIGO'] = 'S') | Consumidora ativa — seleciona automaticamente os lotes mais antigos por DT_VALIDADE para cobrir a quantidade solicitada |
| Pedido de Venda | MPD002 | citado no label do parâmetro — consome indiretamente via RateioLoteProducao (tipo 'SA') do jLoteProducao quando TP_CONTROLELOTE = 'A' | Consumidora indireta |
| Nota Fiscal | MNF002 | citado no label do parâmetro — consome indiretamente via RateioLoteProducao (tipo 'SA') do jLoteProducao quando TP_CONTROLELOTE = 'A' | Consumidora indireta |
| Parâmetros Faturamento (tela de configuração) | MFA001 | UMFA001.dfm:3991 (label), UMFA001.dfm:4713-4741 (ComboBox cmbST_SELECIONALOTEANTIGO, items Sim=S / Não=N), UdmMFA001.dfm:1860-1865 (campo), UdmMFA001.dfm:2606, 2857 (INSERT/UPDATE de PARMFATUR) | Produtora — onde o usuário configura o valor |
Procedures impactadas
| Procedure / Script | Papel |
|---|---|
CONSOME_LOTEMATERIAPRIMA (Scripts/CONSOME_LOTEMATERIAPRIMA.sql) | Consumidora — se ST_SELECIONALOTEANTIGO = 'S' e o item é semente (ST_SEMENTE <> 'N') e ainda não há lote amarrado à ordem de produção, a procedure percorre LOTESEMENTE ordenado por COALESCE(DT_VALIDADE, DT_REGISTRO) e insere os lotes mais antigos em ORDEMPRODUCAOLOTE até cobrir QT_MATERIAPRIMA. Chamada por GERA_ORDEMPRODUCAO (Scripts/GERA_ORDEMPRODUCAO.sql:199, 446). |
Campos envolvidos
| Campo | Tabela | Descrição |
|---|---|---|
ST_SELECIONALOTEANTIGO | PARMFATUR | Habilita seleção automática FIFO de lotes por validade |
TP_CONTROLELOTE | PARMFATUR | Gate de edição — só permite editar ST_SELECIONALOTEANTIGO quando = 'A' (Agrupado); se = 'I' a UI força 'N' e bloqueia o combobox (UMFA001.pas:2444, 2452) |
ST_VALIDAVENCIMENTOLOTE | PARMFATUR | Lido junto no mesmo SELECT (ULoteSaidaAgrupado.pas:184) — complementa a lógica de validade do lote |
ST_LOTENEGATIVO | PARMESTOQUE | Lido logo antes (ULoteSaidaAgrupado.pas:177) — controla se lote pode ficar negativo |
QT_LOTEORIGEM | ITEM (grid do rateio) | Quantidade que o auto-seleção precisa cobrir |
DT_VALIDADE / DT_REGISTRO | LOTESEMENTE | Critério de ordenação — o "antigo" aqui é o de validade mais próxima (ou, na falta dela, o mais antigo pela data de registro) |
NR_LOTE, QT_LOTE, CD_EMPRLOTE, CD_ITEM | LOTESEMENTE | Lotes candidatos à seleção automática |
ST_SEMENTE | ITEM | Na procedure CONSOME_LOTEMATERIAPRIMA, só consome automaticamente se <> 'N' |
Tabelas gravadas
| Tabela | Operação | Origem |
|---|---|---|
Grid interno tabLote (campos STATUS = 'Å', QT_LOTE) | UPDATE em memória antes do commit | ULoteSaidaAgrupado.pas:1304-1349 |
ORDEMPRODUCAOLOTE | INSERT (apenas via procedure CONSOME_LOTEMATERIAPRIMA) | Scripts/CONSOME_LOTEMATERIAPRIMA.sql:53-56 |
Opções disponíveis
S - Sim (Seleciona lote mais antigo automaticamente)
| O que faz | Detalhe |
|---|---|
| Pré-seleção automática na tela de Rateio Agrupado | Ao abrir a tela TfrmLoteAgrupado pela primeira vez (StAbrindoTela = True), o sistema soma o saldo de todos os lotes disponíveis; se a soma cobre a QT_LOTEORIGEM solicitada, percorre LOTESEMENTE ordenado por DT_VALIDADE e marca os lotes mais antigos como selecionados (STATUS = 'Å') até completar a quantidade (ULoteSaidaAgrupado.pas:1289-1349) |
| Consumo automático em Ordem de Produção | A procedure CONSOME_LOTEMATERIAPRIMA percorre LOTESEMENTE ordenado por COALESCE(DT_VALIDADE, DT_REGISTRO) e insere em ORDEMPRODUCAOLOTE os lotes mais antigos até cobrir a QT_MATERIAPRIMA (Scripts/CONSOME_LOTEMATERIAPRIMA.sql:34-63) |
| Requisitos na tela de configuração | Só fica editável quando TP_CONTROLELOTE = 'A' (Agrupado) — com 'I' (Individual) o sistema força o valor para 'N' e desabilita o combobox |
| Se o saldo total dos lotes é menor que a quantidade solicitada | A pré-seleção não ocorre — if (vlSaldo >= tabITEMQT_LOTEORIGEM.AsFloat) em ULoteSaidaAgrupado.pas:1289; usuário precisa escolher manualmente |
Se já havia lotes marcados (iAchou > 0) | A rotina é pulada — evita refazer a seleção quando o usuário já escolheu |
Simulação passo a passo (Rateio Agrupado em pedido)
- Vá em MFA001 → Parâmetros → Pedidos / O.S. → Opção 1
- Ajuste
TP_CONTROLELOTE= "Agrupado" ('A') — só assim o combobox deST_SELECIONALOTEANTIGOfica editável - Marque Selecionar Lote mais Antigo = "Sim"
- Salve os parâmetros (F6)
- Cadastre um item semente (
ST_SEMENTE = 'S') com dois lotes emLOTESEMENTE: lote A comDT_VALIDADE= hoje + 30 dias, lote B comDT_VALIDADE= hoje + 180 dias, ambos com saldo - Em MPD002, abra pedido que dispare o rateio agrupado de lote (item semente com operação de lote)
- A tela de Rateio Agrupado abre — o lote A (validade mais próxima) já aparece pré-marcado com a quantidade necessária
- Confirme — a seleção automática evita que o usuário esqueça de usar o lote vencendo primeiro
Resultado esperado: FIFO automático por validade — lotes com vencimento mais próximo são consumidos primeiro, reduzindo perda por vencimento sem depender de escolha manual do usuário.
Simulação passo a passo (Geração de Ordem de Produção)
- Mesma configuração (
ST_SELECIONALOTEANTIGO = 'S') - Item de matéria-prima com
ST_SEMENTE <> 'N'e lotes emLOTESEMENTE - Gere uma ordem de produção que chame
GERA_ORDEMPRODUCAO(linhas 199 e 446 executamCONSOME_LOTEMATERIAPRIMA) - Sem lotes pré-amarrados (
COUNT(ORDEMPRODUCAOLOTE) = 0), a procedure percorreLOTESEMENTEporDT_VALIDADE/DT_REGISTROascendente e insere automaticamente emORDEMPRODUCAOLOTEos lotes mais antigos até cobrirQT_MATERIAPRIMA
Resultado esperado: A ordem de produção nasce com os lotes de matéria-prima mais antigos já amarrados, sem intervenção manual.
N - Não (Usuário escolhe manualmente)
| O que faz | Detalhe |
|---|---|
| Rateio Agrupado em tela | A tela abre com a grid de lotes sem seleção automática; usuário marca manualmente os lotes desejados |
| Consumo automático em Ordem de Produção | A procedure CONSOME_LOTEMATERIAPRIMA sai no IF da linha 34 (V_ST_SELECIONALOTEANTIGO = 'S' é falso) — nenhum registro em ORDEMPRODUCAOLOTE é criado pela procedure |
Quando é forçado para 'N' | Sempre que TP_CONTROLELOTE muda para 'I' (Individual), o evento cmbTP_CONTROLELOTEChange em UMFA001.pas:2444 grava ST_SELECIONALOTEANTIGO = 'N' e desabilita o combobox |
Simulação passo a passo
- MFA001 → Selecionar Lote mais Antigo = "Não" (ou simplesmente deixe
TP_CONTROLELOTE='I'— o sistema força) - Salve (F6)
- No fluxo de pedido/nota com rateio agrupado, a grid de lotes abre sem pré-seleção — usuário escolhe os lotes manualmente
- Na geração de Ordem de Produção, nenhum lote de matéria-prima é amarrado automaticamente via
CONSOME_LOTEMATERIAPRIMA— o controle fica a cargo do usuário
Resultado esperado: Controle 100% manual de lotes; útil quando as regras de consumo não são puramente FIFO por validade.
Interação com TP_CONTROLELOTE e parâmetros de lote relacionados
| Parâmetro | Relação |
|---|---|
TP_CONTROLELOTE | Gate de edição. ST_SELECIONALOTEANTIGO só é editável quando TP_CONTROLELOTE = 'A' (Agrupado). Ao trocar para 'I' (Individual), o sistema grava 'N' e desabilita o combobox (UMFA001.pas:2442-2452). Na reabertura da tela, a mesma regra é aplicada em UMFA001.pas:920. |
ST_VALIDAVENCIMENTOLOTE | Lido no mesmo SELECT de CarregarSaidaAgrupada (ULoteSaidaAgrupado.pas:184-188) — ambos tratam do ciclo de vida do lote na saída agrupada. |
ST_LOTEPEDIDO | É quem dispara o rateio de lote no pedido. Sem ST_LOTEPEDIDO = 'S' a tela de rateio nem chega a abrir, e portanto ST_SELECIONALOTEANTIGO nunca é usado no fluxo de pedido. |
ST_LOTENEGATIVO (PARMESTOQUE) | Também lido em CarregarSaidaAgrupada (ULoteSaidaAgrupado.pas:177-181) — permite (ou não) que a seleção automática consuma lotes com saldo zerado. |
Tabela Comparativa Resumida
| Opção | Descrição | Pré-seleção FIFO na tela de Rateio Agrupado? | CONSOME_LOTEMATERIAPRIMA consome auto? | Exige TP_CONTROLELOTE = 'A' para editar? |
|---|---|---|---|---|
| S | Sim — seleciona lote mais antigo | Sim (se saldo total cobre a quantidade) | Sim (quando ST_SEMENTE <> 'N' e não há lote amarrado) | Sim |
| N | Não — seleção manual | Não | Não | — (valor forçado quando TP_CONTROLELOTE = 'I') |
Referências no Código Fonte
| Arquivo | Linha(s) | Papel |
|---|---|---|
source/MFA001/UMFA001.dfm | 3991-4004 (label "Selecionar Lote mais Antigo [MPD002/MNF002]"), 4713-4741 (ComboBox cmbST_SELECIONALOTEANTIGO, items Sim=S / Não=N) | UI do parâmetro |
source/MFA001/UMFA001.pas | 538-539 (declaração), 920 (habilita combobox só quando TP_CONTROLELOTE = 'A'), 2444 (força 'N' quando muda para Individual), 2448/2452 (ReadOnly+Enabled=False no modo Individual), 2461/2465 (libera no modo Agrupado) | Regra de edição |
source/MFA001/UdmMFA001.dfm | 1860-1865 (TStringField), 2606 (parâmetro no INSERT), 2857 (parâmetro no UPDATE) | Persistência |
source/MFA001/UdmMFA001.pas | 263 (declaração do campo). Não há atribuição no AfterInsert (campo nasce vazio) | Persistência |
source/jLoteProducao/ULoteSaidaAgrupado.pas | 104 (var iST_SELECIONALOTEANTIGO), 183-189 (SELECT em CarregarSaidaAgrupada), 1289-1349 (bloco ativo: pré-seleção FIFO dos lotes mais antigos na grid tabLote com STATUS = 'Å') | Consumidora principal (UI) |
source/jLoteProducao/jLote.pas | 54-55 (roteamento tipo = 'SA' → CarregarSaidaAgrupada) | Entry point do rateio agrupado (RateioLoteProducao) |
Scripts/CONSOME_LOTEMATERIAPRIMA.sql | 15-20 (SELECT do parâmetro), 34-63 (bloco ativo V_ST_SELECIONALOTEANTIGO = 'S' — loop FIFO por COALESCE(DT_VALIDADE, DT_REGISTRO) inserindo em ORDEMPRODUCAOLOTE) | Consumidora principal (SQL) |
Scripts/GERA_ORDEMPRODUCAO.sql | 199, 446 (chamadas a CONSOME_LOTEMATERIAPRIMA) | Invoca o consumo FIFO na geração da ordem |
Observação 1: O label do parâmetro cita
[MPD002/MNF002], mas essas telas não referenciamST_SELECIONALOTEANTIGOdiretamente — o consumo é transitivo viajLoteProducao.RateioLoteProducao(tipo'SA'= Saída Agrupada).Observação 2: "Lote mais antigo" no contexto deste parâmetro significa validade mais próxima (
DT_VALIDADEascendente), não data de criação. Na procedure SQL, como fallback usaDT_REGISTROquandoDT_VALIDADEé NULL (COALESCE(DT_VALIDADE, DT_REGISTRO)).Observação 3: O parâmetro depende do gate
TP_CONTROLELOTE = 'A'— em modo Individual o sistema obriga'N'. Consequência prática: ambientes com rateio Individual nunca têm seleção FIFO automática.