Pular para o conteúdo principal

HR_INTERVALOAGEND - Intervalo mínimo entre agendamentos de prova (locação)

Tela: MFA001 - Parâmetros de Faturamento Localização: Parâmetros → Faturamento → aba Locações (pagLocacao em UMFA001.dfm:10630-10631, Caption = 'Locações') → GroupBox5 ' Parâmetros de Locações ' → campo Intervalo Minímo entre Agendamentos (label lbl62 em UMFA001.dfm:10744-10756, Caption = 'Intervalo Minímo entre Agendamentos', posicionado em Left=32, Top=191) Tabela: PARMFATUR.HR_INTERVALOAGEND Tipo: Hora / Intervalo (DOM_TIME no DDL — docs/schema/tables/PARMFATUR.sql:174); TTimeField no client (UdmMFA001.pas:225); editado via TwwDBDateTimePicker edtHR_INTERVALOAGEND (UMFA001.dfm:11000-11024) com UnboundDataType = wwDTEdtTime e DisplayFormat = 'HH:mm:ss', posicionado em Left=221, Top=187 (imediatamente ao lado do label lbl62) Valor padrão: NULL — o AfterInsert de tabPARMFATUR em UdmMFA001.pas:434 não atribui default para este campo (a inspeção dos 150+ defaults do AfterInsert não lista HR_INTERVALOAGEND). O DDL DOM_TIME em PARMFATUR.sql:174 também não define DEFAULT, então o parâmetro nasce vazio quando uma nova PARMFATUR é criada. Validação (MFA001): não há OnValidate para tabPARMFATURHR_INTERVALOAGEND em UdmMFA001.pas (grep HR_INTERVALOAGEND em UMFA001.pas/UdmMFA001.pas retorna apenas a declaração do field na linha 225 e uma regra de navegação ActiveControl.Name = 'edtHR_INTERVALOAGEND' em UMFA001.pas:1166-1170 que direciona TAB para a aba de Layout — nenhum handler de validação de conteúdo).

O que o parâmetro faz​

HR_INTERVALOAGEND é o intervalo mínimo de tempo (hora/minuto/segundo) que deve existir entre dois agendamentos de prova numa mesma empresa. Faz parte do bloco de Parâmetros de Locações da MFA001 (ao lado de QT_MAXPROVAS, HR_INTERVALORET, NR_DIASRETIRADA, etc.) e é usado pela stored procedure VALIDA_INTERVALOAGENDA para decidir se um novo agendamento de data de prova (LOCACAO.DT_PROVA) pode ser confirmado.

A procedure recebe a data/hora que se pretende agendar (I_DT_PROVA), o número da locação atual (I_NR_LOCACAO) e o próprio valor do parâmetro (I_HR_INTERVALOAGEND). Ela calcula uma janela de exclusão antes e depois de DT_PROVA, somando e subtraindo o intervalo em horas/minutos/segundos, e verifica se já existe alguma locação (LOCACAO) com DT_PROVA caindo dentro dessa janela. Se existir, devolve O_ST_DISPONIVEL = 'N', indicando que o horário escolhido conflita com outra prova já agendada e que o operador precisa escolher outro.

O objetivo operacional é distribuir as provas de locação ao longo do dia, evitando que o mesmo atendente receba dois clientes para prova muito próximos um do outro.

Telas impactadas​

MóduloCódigoPapel
Parâmetros de FaturamentoMFA001Produtora — cadastra/edita o valor no campo edtHR_INTERVALOAGEND (aba Locações, UMFA001.dfm:11000-11024). CRUD da PARMFATUR inclui o campo em SELECT/INSERT/UPDATE/RefreshSQL (UdmMFA001.dfm:239, 1642-1645, 2414, 2820, 3119).

Observação sobre consumidoras: a stored procedure VALIDA_INTERVALOAGENDA (Scripts/VALIDA_INTERVALOAGENDA.sql) recebe HR_INTERVALOAGEND como parâmetro de entrada (I_HR_INTERVALOAGEND time), portanto cabe à tela chamadora fazer o SELECT HR_INTERVALOAGEND FROM PARMFATUR WHERE CD_EMPRESA = ... e repassar o valor. O grep em source/ não encontrou nenhuma referência a VALIDA_INTERVALOAGENDA em código Delphi (source/**/*.pas, source/**/*.dfm) — a procedure existe no banco mas o call site no cliente não está implementado (ou foi removido) nesta branch. Qualquer tela que passe a agendar locações/provas e invocar a procedure será a consumidora natural (tipicamente telas do grupo de locação como MPD043 ou telas que manipulem LOCACAO.DT_PROVA).

Procedures impactadas​

ProcedureArquivoPapel
VALIDA_INTERVALOAGENDAScripts/VALIDA_INTERVALOAGENDA.sqlRecebe I_HR_INTERVALOAGEND e verifica se existe LOCACAO com DT_PROVA dentro da janela [DT_PROVA − intervalo, DT_PROVA + intervalo] para a mesma CD_EMPRESA. Retorna O_ST_DISPONIVEL = 'S' ou 'N'.

Campos envolvidos​

CampoTabelaPapel
HR_INTERVALOAGENDPARMFATURIntervalo mínimo entre agendamentos (este parâmetro)
CD_EMPRESAPARMFATUR / LOCACAOFiltro — a validação é feita por empresa
DT_PROVALOCACAOData/hora da prova comparada com a janela [DT_PROVA ± HR_INTERVALOAGEND]
NR_LOCACAOLOCACAOA locação atual é excluída da busca de conflitos (NR_LOCACAO <> :I_NR_LOCACAO)
ST_LOCACAOLOCACAOLocações com ST_LOCACAO IN ('C','D') (Cancelada / Devolvida) são ignoradas na checagem
QT_MAXPROVASPARMFATURParâmetro irmão na mesma aba — controla quantas provas simultâneas são permitidas no mesmo horário

Comportamento / Uso​

Valor = NULL (em branco)​

AspectoComportamento
Em VALIDA_INTERVALOAGENDA (Scripts/VALIDA_INTERVALOAGENDA.sql:38-43)IF (I_HR_INTERVALOAGEND IS NULL) THEN ... SUSPEND; EXIT;
Mensagem devolvidaO_DS_MENSAGEM = ' VALIDA_INTERVALOAGENDA: É Obrigatório informar o intervalo entre os Agendamentos. Verifique! '
O_ST_DISPONIVELNão é alterado de 'S' (valor default na linha 22) — mas a procedure sai antes de fazer a varredura, com mensagem de erro preenchida

Resultado esperado: sem o parâmetro preenchido, a procedure rejeita o agendamento devolvendo mensagem de obrigatoriedade. Ou seja, para que a validação de intervalo funcione (em qualquer sentido), o parâmetro precisa estar preenchido em MFA001 → Locações.

Valor = 00:00:00​

AspectoComportamento
IF (I_HR_INTERVALOAGEND IS NULL)Falso (00:00:00 ≠ NULL no Firebird) — segue em frente
Janela calculada (linhas 48-55)V_HORA = V_MINUTO = V_SEGUNDO = 0 → V_DT_INTERVALOPROVA = I_DT_PROVA (sem adição)
BETWEEN I_DT_PROVA AND V_DT_INTERVALOPROVAJanela colapsa num único instante — só pega locações com DT_PROVA exatamente igual a I_DT_PROVA
O_ST_DISPONIVEL'N' apenas se houver outra locação no mesmíssimo timestamp; caso contrário 'S'

Resultado esperado: equivalente a desligar o espaçamento entre agendamentos — apenas o choque exato no mesmo segundo é detectado.

Valor > 00:00:00​

AspectoComportamento
Extração dos componentes (linhas 48-50)V_HORA = EXTRACT(HOUR ...), V_MINUTO = EXTRACT(MINUTE ...), V_SEGUNDO = EXTRACT(SECOND ...)
Janela posterior (linhas 52-55)V_DT_INTERVALOPROVA = I_DT_PROVA + V_HORA h + V_MINUTO min + V_SEGUNDO s
1ª busca (linhas 59-67)SELECT SUM(L.NR_LOCACAO) FROM LOCACAO L WHERE L.CD_EMPRESA = I_CD_EMPRESA AND L.DT_PROVA BETWEEN I_DT_PROVA AND V_DT_INTERVALOPROVA AND L.ST_LOCACAO NOT IN ('C','D') AND L.NR_LOCACAO <> I_NR_LOCACAO — detecta provas agendadas depois de I_DT_PROVA dentro da janela
Curto-circuitoSe V_CONTROLA > 0 → O_ST_DISPONIVEL = 'N'; SUSPEND; EXIT;
Janela anterior (linhas 78-81)V_DT_INTERVALOPROVA = I_DT_PROVA − V_HORA h − V_MINUTO min − V_SEGUNDO s
2ª busca (linhas 84-92)Mesma query, agora com BETWEEN V_DT_INTERVALOPROVA AND I_DT_PROVA — detecta provas antes de I_DT_PROVA dentro da janela
Retorno finalO_ST_DISPONIVEL = 'N' se houve conflito em qualquer das duas buscas, senão 'S'

Observações importantes:

  • A procedure usa EXECUTE STATEMENT com concatenação de valores (linhas 59-66 e 84-92). Mesmo que os parâmetros sejam numéricos/datas de fonte confiável, o padrão viola a regra de segurança do projeto (rules/sql/quality.md — SQL injection); em código novo deve ser refatorado para query estática com parâmetros :I_CD_EMPRESA, :I_DT_PROVA, etc.
  • A janela inclui os extremos (BETWEEN é inclusivo). Uma prova agendada exatamente na ponta da janela (por ex., I_DT_PROVA + HR_INTERVALOAGEND ao segundo exato) também é considerada conflito.
  • Locações ST_LOCACAO IN ('C','D') (Cancelada, Devolvida) são descartadas — apenas provas ativas entram no teste.
  • A própria locação em edição é excluída pela cláusula L.NR_LOCACAO <> :I_NR_LOCACAO, permitindo que o operador reconfirme a locação sem que ela conflite consigo mesma.

Simulação passo a passo​

Pré-requisitos do cenário:

  • PARMFATUR.HR_INTERVALOAGEND = 00:30:00 (30 minutos) definido em MFA001 → Locações para CD_EMPRESA = 1.
  • Empresa 1 já tem duas locações com prova agendada:
    • Locação 2001 → DT_PROVA = 15/05/2026 14:00:00, ST_LOCACAO = 'P'.
    • Locação 2002 → DT_PROVA = 15/05/2026 15:10:00, ST_LOCACAO = 'P'.
  • Operador está criando a Locação 2003 e tenta agendar DT_PROVA = 15/05/2026 14:20:00.
  1. Em MFA001 → aba Locações → informe Intervalo Minímo entre Agendamentos = 00:30:00. Salve (F6). Valor grava em PARMFATUR.HR_INTERVALOAGEND.

  2. Ao tentar confirmar a prova da Locação 2003, a tela consumidora executa:

    EXECUTE PROCEDURE VALIDA_INTERVALOAGENDA(
    1, -- I_CD_EMPRESA
    TIMESTAMP '2026-05-15 14:20:00', -- I_DT_PROVA
    2003, -- I_NR_LOCACAO
    TIME '00:30:00' -- I_HR_INTERVALOAGEND
    );
  3. Dentro da procedure:

    1. Nenhum I_* é NULL → passa pelos três IF IS NULL das linhas 24-43.
    2. V_HORA = 0, V_MINUTO = 30, V_SEGUNDO = 0.
    3. Janela posterior: V_DT_INTERVALOPROVA = 15/05/2026 14:50:00. Query busca locações entre 14:20:00 e 14:50:00 (empresa 1, não canceladas, ≠ 2003). Nenhuma — a Locação 2001 está em 14:00 (antes) e a 2002 em 15:10 (depois).
    4. Janela anterior: V_DT_INTERVALOPROVA = 15/05/2026 13:50:00. Query busca locações entre 13:50:00 e 14:20:00. Acha a Locação 2001 (14:00:00). V_CONTROLA = 2001 > 0.
    5. Seta O_ST_DISPONIVEL = 'N', SUSPEND, EXIT.
  4. A tela consumidora recebe ST_DISPONIVEL = 'N' e deve bloquear/avisar o operador que já existe prova agendada nos 30 minutos anteriores.

  5. O operador ajusta para 14:35:00 e reenvia. Agora:

    • Janela posterior: [14:35, 15:05] — não pega 2002 (15:10 está fora). OK.
    • Janela anterior: [14:05, 14:35] — não pega 2001 (14:00 está fora). OK.
    • O_ST_DISPONIVEL = 'S'. Prova pode ser agendada.

Resultado esperado: o parâmetro distribui as provas no tempo, rejeitando agendamentos que fiquem a menos de HR_INTERVALOAGEND de qualquer outra prova ativa na mesma empresa — seja antes ou depois do horário proposto.

Casos de borda​

CenárioComportamento
Locações em empresas diferentesIgnoradas (filtro L.CD_EMPRESA = :I_CD_EMPRESA em ambas as buscas). Cada empresa tem sua própria janela.
Locações com ST_LOCACAO = 'C' (Cancelada) ou 'D' (Devolvida)Ignoradas (filtro L.ST_LOCACAO NOT IN ('C','D')).
Mesmo número de locação em ediçãoIgnorada (filtro L.NR_LOCACAO <> :I_NR_LOCACAO) — permite reconfirmar sem conflito consigo mesma.
Nova locação ainda sem NR_LOCACAO geradoPasse um valor que não exista na base (ex.: 0) para que o filtro <> não exclua nenhuma locação existente.
CD_EMPRESA ou DT_PROVA não informadosA procedure retorna mensagem de obrigatoriedade em O_DS_MENSAGEM (linhas 24-36) e sai sem alterar O_ST_DISPONIVEL (que permanece 'S').
Prova agendada exatamente na ponta da janela (14:20:00 − 00:30:00 = 13:50:00)Conflito — BETWEEN é inclusivo no Firebird.

Referências no Código Fonte​

Delphi — MFA001 (cadastro do parâmetro)​

ArquivoLinhasPapel
source/MFA001/UMFA001.dfm10630-10631TTabSheet pagLocacao com Caption = 'Locações', ImageIndex = 3
source/MFA001/UMFA001.dfm10633-10645TGroupBox GroupBox5 ' Parâmetros de Locações ' (container visual)
source/MFA001/UMFA001.dfm10744-10756TLabel lbl62 com Caption = 'Intervalo Minímo entre Agendamentos', Left=32, Top=191
source/MFA001/UMFA001.dfm11000-11024TwwDBDateTimePicker edtHR_INTERVALOAGEND — DataField = 'HR_INTERVALOAGEND', DataSource = dmMFA001.dsPARMFATUR, UnboundDataType = wwDTEdtTime, DisplayFormat = 'HH:mm:ss', Left=221, Top=187
source/MFA001/UMFA001.pas339Declaração do componente visual edtHR_INTERVALOAGEND: TwwDBDateTimePicker
source/MFA001/UMFA001.pas1166-1170Handler de navegação TAB — quando ActiveControl.Name = 'edtHR_INTERVALOAGEND', direciona para paginas.ActivePage := pagLAYOUT e foca edtCD_LAYPEDVENDA
source/MFA001/UdmMFA001.pas225Declaração tabPARMFATURHR_INTERVALOAGEND: TTimeField
source/MFA001/UdmMFA001.pas434tabPARMFATURAfterInsert não atribui default para HR_INTERVALOAGEND (o campo nasce NULL)
source/MFA001/UdmMFA001.dfm239SelectSQL: lista PARMFATUR.QT_MAXPROVAS, PARMFATUR.HR_INTERVALOAGEND, PARMFAT...
source/MFA001/UdmMFA001.dfm1642-1645Definição do TTimeField com FieldName = 'HR_INTERVALOAGEND', Origin = '"PARMFATUR"."HR_INTERVALOAGEND"'
source/MFA001/UdmMFA001.dfm2414InsertSQL: inclui HR_INTERVALOAGEND na cláusula de colunas do INSERT
source/MFA001/UdmMFA001.dfm2820UpdateSQL: HR_INTERVALOAGEND = :HR_INTERVALOAGEND,
source/MFA001/UdmMFA001.dfm3119RefreshSQL: PARMFATUR.QT_MAXPROVAS, PARMFATUR.HR_INTERVALOAGEND, PARMFAT...

DDL​

  • docs/schema/tables/PARMFATUR.sql:174 — HR_INTERVALOAGEND DOM_TIME, (sem NOT NULL, sem default → permite NULL).

SQL — Procedures​

ArquivoLinhasPapel
Scripts/VALIDA_INTERVALOAGENDA.sql1-102Procedure VALIDA_INTERVALOAGENDA completa
Scripts/VALIDA_INTERVALOAGENDA.sql7Parâmetro de entrada I_HR_INTERVALOAGEND time
Scripts/VALIDA_INTERVALOAGENDA.sql38-43Validação IS NULL → retorna mensagem de obrigatoriedade
Scripts/VALIDA_INTERVALOAGENDA.sql48-50Extração de HOUR / MINUTE / SECOND do intervalo
Scripts/VALIDA_INTERVALOAGENDA.sql52-67Janela posterior (DT_PROVA → DT_PROVA + intervalo) e busca por conflito
Scripts/VALIDA_INTERVALOAGENDA.sql78-98Janela anterior (DT_PROVA − intervalo → DT_PROVA) e busca por conflito
Scripts/VALIDA_INTERVALOAGENDA.sql69-74, 94-99Se encontrou locação conflitante → O_ST_DISPONIVEL = 'N' e sai

Observação sobre chamadores​

O grep VALIDA_INTERVALOAGENDA em D:/Desenvolvimento/JunsoftERP_V2/source/ não retornou nenhuma chamada a esta procedure em código Delphi (.pas/.dfm). A procedure existe no banco e foi claramente projetada para validar agendamentos de prova de locação, mas o call site no cliente não foi localizado nesta branch — pode ter sido removido em refactor ou estar ainda por integrar. Quando for integrada, a tela chamadora deverá:

  1. Ler PARMFATUR.HR_INTERVALOAGEND (via dataset já aberto ou SELECT dedicado) filtrando por CD_EMPRESA.
  2. Chamar EXECUTE PROCEDURE VALIDA_INTERVALOAGENDA(:CD_EMPRESA, :DT_PROVA, :NR_LOCACAO, :HR_INTERVALOAGEND).
  3. Bloquear/avisar baseado em O_ST_DISPONIVEL e exibir O_DS_MENSAGEM quando presente.