A ordem das chamadas
- M410INIC gravação
- A410Grava gravação
- M410STTS gravação
MT410TOK — Ao clicar OK, antes da validação do grid.
O padrão descarta o retorno: não dá para bloquear aqui. Ler o artigo.
MTA410 — Cabeçalho e itens validados, antes de gravar.
O padrão descarta o retorno: não dá para bloquear aqui.
MT410INC — Depois de gravar, fora da transação.
O padrão descarta o retorno: não dá para bloquear aqui. Ler o artigo.
MTA410 em resumo
- Onde fica
- função
A410TudOk(), a validação final do pedido. - Quando dispara
- com cabeçalho e itens já validados pelo padrão, antes de gravar.
- PARAMIXB
- não recebe.
- Retorno
- usado —
.F.interrompe. - Serve para bloquear?
- Sim, e é o lugar certo para regra que depende dos itens.
Consulta rápida6 seções
Para o mecanismo geral, veja Ponto de entrada no Protheus.
A diferença que define este PE
No MATA410, a chamada é assim:
If lRetorna.AND. ExistTemplate("MTA410",, .T.)
lRetorna := ExecTemplate("MTA410", .F., .F.)
EndIf
If lRetorna.AND. ExistBlock("MTA410",, .T.)
lRetorna := ExecBlock("MTA410", .F., .F.)
EndIfAquele If lRetorna.AND. na frente muda tudo. O seu ponto de entrada só é
chamado se a validação padrão já passou. Se o padrão reprovou, ele nem roda.
A consequência é boa: aqui você não tem como derrubar uma validação nativa.
Sua regra só consegue apertar. É o oposto do
MT410TOK, cujo
retorno é atribuído sem essa checagem — lá um Return .T. distraído desfaz o
que o padrão tinha barrado.
Se você pode escolher entre os dois, e a regra depende dos itens, o MTA410 é o lugar mais seguro.
Repare também que o Template roda antes, e se ele reprovar, o seu PE não é chamado. Vale saber quando o cliente tem template de segmento instalado.
O que ele tem que o MT410TOK não tem
O momento. Quando o MTA410 roda, o padrão já validou cabeçalho e itens:
aCols está completo e consistente, com os gatilhos disparados e os campos
calculados preenchidos.
No MT410TOK, que roda antes da validação do grid, o aCols está lá — mas você
está olhando dados que o padrão ainda não conferiu.
Regra prática:
- Regra de cabeçalho (cliente, condição de pagamento, tipo de pedido) → MT410TOK, que é mais barato e falha mais cedo.
- Regra que depende dos itens → MTA410.
O detalhe que surpreende: ele não é só do pedido de venda
Este é o achado que explica um trecho estranho que aparece em código de campo.
No documento de entrada e na nota fiscal de saída, rotinas de Compras, existe esta linha:
PRIVATE lMTA410 := (ExistBlock("MTA410"))Ela só guarda se o bloco existe. Não aparece lida em nenhum outro ponto do
padrão, e nenhuma das duas rotinas chama MATA410() depois disso — não é
essa linha que executa o seu ponto de entrada. Quem só olhar essa variável e
concluir “então o MTA410 roda a partir daqui” está seguindo uma pista morta.
Quem executa é A410TudOk() — a função já citada no início
deste artigo —, que testa ExistBlock("MTA410",, .T.) por conta própria, sem
depender daquela variável de Compras. A rota comprovada para um fluxo que não
é a tela de pedido de venda está em outra rotina: MATA310(), a
transferência de saldos entre filiais, chama MATA410(aCabec,aItens,3)
diretamente. Essa chamada cai no trecho de
A410Inclui() que roda via ExecAuto — o bloco {|| A410VldTOk(nOpc) .and. A410TudOk()} —, e é A410TudOk(), de novo, quem dispara o MTA410.
Na prática: o seu MTA410 pode ser chamado de fluxos que não são a tela de pedido de venda — comprovadamente, da transferência de saldos entre filiais. Uma regra escrita presumindo “estou incluindo um pedido” passa a rodar em contexto onde ela não faz sentido.
É por isso que código de produção sério guarda o contexto. Dois padrões que aparecem no campo:
// 1. Pela rotina que está no topo da pilha
If AllTrim(FunName()) <> "MATA310" // MATA310 = transferência de saldos entre filiais
//... a regra...
EndIf
// 2. Pelo caminho específico dentro da própria rotina
If IsInCallStack("A410COPIA") .And. !l410Auto
//... regra que vale só na cópia de pedido, e só com tela...
EndIfFunName() devolve a rotina corrente; IsInCallStack() responde se uma função
específica está na pilha de chamadas. Os dois juntos dão o contexto que o
PARAMIXB daria — se ele existisse aqui, que não é o caso.
Exemplo
Validação de cabeçalho que só vale na tela de pedido, escrita como se vê em produção:
#Include "Protheus.ch"
/*/{Protheus.doc} MTA410
Executado em A410TudOk(), com cabeçalho e itens já validados pelo padrão
e ANTES da gravação. Só é chamado se a validação padrão passou.
Exige vendedor preenchido, exceto em devolução e beneficiamento.
@type user function
@return logical, .F. interrompe a gravação
/*/
User Function MTA410()
Local aArea := SC5->(GetArea())
Local lRet := .T.
// Este PE também é alcançado por rotinas de Compras e pela transferência
// de saldos entre filiais (MATA310). Sem este guard, a regra roda onde
// não deveria.
If AllTrim(FunName()) <> "MATA410"
RestArea(aArea)
Return .T.
EndIf
// Nada foi gravado ainda: o cabeçalho vive em M->
If !(M->C5_TIPO $ "DB") .And. Empty(M->C5_VEND1)
MsgStop("Informe o vendedor antes de concluir o pedido.", ;
"Vendedor em branco — MTA410")
lRet := .F.
EndIf
ConOut("[MTA410] Pedido " + M->C5_NUM + " | Retorno: " + cValToChar(lRet))
RestArea(aArea)
Return lRetDuas coisas nesse código.
M->C5_TIPO $ "DB" — devolução (D) e beneficiamento (B) não têm
vendedor, então a regra não se aplica. Regra que ignora os tipos de pedido
existentes vira chamado no dia em que alguém precisa lançar uma devolução.
MsgStop antes de lRet := .F. — sem a mensagem, o usuário vê o botão
simplesmente não funcionar.
Armadilhas específicas
Presumir que veio da tela de pedido. É a principal. Use FunName() ou
IsInCallStack().
Abrir diálogo sem checar contexto. MsgStop numa carga ExecAuto trava a
thread até o timeout do server. Type("l410Auto") == "U" .Or. !l410Auto
resolve — e é exatamente o teste que aparece em código de campo.
Trabalho pesado aqui. Este PE roda a cada confirmação de pedido. Consulta não indexada dentro dele custa em toda inclusão, inclusive nas cargas automáticas.
Esquecer o Return lógico. O retorno é usado. Sem ele, o padrão avalia com
Nil.
Os vizinhos
| PE | Momento | Retorno é usado? |
|---|---|---|
MT410TOK | Ao clicar OK, antes da validação do grid | Sim, sobrescrevendo |
MTA410 | Cabeçalho e itens validados, antes de gravar | Sim, só aperta |
MT410INC | Depois de gravar, fora da transação | Não |
Se a sua regra precisa acontecer depois de o pedido existir — auditoria, integração, marcar campo no registro gravado — o lugar é o MT410INC.
Referências
TDNtdn.totvs.com
TDN — MATA410, Pedidos de Venda
Continue por aqui
- Vídeo
DesenvolvimentoReferência técnica
M410STTS: como identificar a operação do pedido de venda
M410STTS não descreve por completo a mudança de status: o padrão passa um número, o código da operação, e o retorno não é usado. Serve para observar.