A ordem das chamadas
- A410Grava gravação
M410INIC — Antes de montar a tela de inclusão.
O padrão descarta o retorno: não dá para bloquear aqui.
MT410TOK — Ao clicar OK, antes da validação do grid.
O padrão usa o retorno: dá para bloquear aqui. Ler o artigo.
MTA410 — Cabeçalho e itens validados, antes de gravar.
O padrão usa o retorno: dá para bloquear aqui. Ler o artigo.
MT410INC — Depois de gravar, fora da transação.
O padrão descarta o retorno: não dá para bloquear aqui.
M410STTS — Logo após o MT410INC.
O padrão descarta o retorno: não dá para bloquear aqui.
MT410INC em resumo
- Localização
A410Inclui(), na rotinaMATA410.- Execução
- depois de
A410Grava(), fora da transação, quando o usuário confirmou. - PARAMIXB
- não recebe.
- Retorno
- descartado pelo padrão.
Não impede a gravação do pedido. Quando este ponto de entrada executa, o pedido já está gravado.
Consulta rápida6 seções
Se você veio parar aqui porque retornou .F. e o pedido gravou assim mesmo, a
resposta está nessas cinco linhas. O resto do texto explica por quê e mostra o
que fazer.
Para o mecanismo geral — como o padrão chama um PE, por que às vezes ele não dispara, como provar que rodou — veja Ponto de entrada no Protheus.
O momento exato
No padrão, o disparo deste ponto de entrada acontece perto do fim de A410Inclui(), dentro de
If (nOpcA == 1) — só quando o usuário confirmou — e dentro de If lContinua,
depois de a gravação ter acontecido e depois do End Transaction:
If lContinua
If lTMt410Inc
ExecTemplate("MT410INC", .F., .F.)
Endif
If lMt410Inc
Execblock("MT410INC", .F., .F.)
Endif
EndIfTrês leituras diretas:
- O pedido já existe no banco. SC5 e SC6 estão gravados. Você não está validando nada — está reagindo a um fato consumado.
- O retorno não é usado.
Execblock(...)aparece como comando, não como expressão atribuída. - Roda fora da transação. Se o seu código estourar aqui, o pedido continua gravado. Não há rollback.
E se existir um Template com o mesmo nome, ele roda antes do seu ponto de entrada — vale saber quando o cliente tem template de segmento instalado.
Se não bloqueia, para que serve?
Para tudo que depende de o pedido já existir:
- gravar auditoria de quem incluiu, com o número do pedido em mãos;
- marcar um campo customizado no pedido recém-gravado;
- alimentar fila de integração ou disparar workflow de aviso;
- bloquear o pedido depois de gravado, por regra própria — que é diferente de impedir a gravação.
Esse último é o uso mais comum em campo, e é o que o exemplo abaixo faz.
O que está disponível dentro dele
Não há PARAMIXB, então o contexto vem das áreas de trabalho e das variáveis
Private que o MATA410 declarou acima na pilha:
| Origem | O que é |
|---|---|
SC5-> | Posicionado no pedido recém-gravado |
aHeader / aCols | Estrutura e conteúdo do grid de itens |
M->C5_* | Variáveis de memória do cabeçalho |
Como são Private de outra função, todo acesso merece guarda de tipo —
Type("aCols") == "A". A mesma customização copiada para outro PE quebra sem
isso.
Exemplo
O padrão que aparece em código de produção: marcar o pedido para bloqueio quando ele veio por um canal externo e feriu uma regra de preço mínimo.
#Include "Protheus.ch"
/*/{Protheus.doc} MT410INC
Executado em A410Inclui(), APÓS a gravação do pedido e fora da transação.
Bloqueia o pedido recém-gravado quando o preço de venda ficou abaixo do
mínimo da tabela. Não impede a gravação — impedir é MT410TOK ou MTA410.
@type user function
@return Nil, o retorno é descartado pela rotina padrão
/*/
User Function MT410INC()
Local aArea := GetArea()
Local nPosPrc := 0
Local nX := 0
Local lBloqueia := .F.
// Primeira instrução: o rastro que prova que o PE rodou.
ConOut("[MT410INC] Pedido " + SC5->C5_NUM + " | Portal: " + ;
cValToChar(Type("oMainWnd") == "U"))
// Sem o grid não há o que avaliar. aCols é Private do MATA410.
If Type("aCols") <> "A" .Or. Type("aHeader") <> "A"
RestArea(aArea)
Return Nil
EndIf
nPosPrc := GDFieldPos("C6_PRCVEN", aHeader)
For nX := 1 To Len(aCols)
If aCols[nX, nPosPrc] > 0 .And. aCols[nX, nPosPrc] < PrecoMinimo(nX)
lBloqueia := .T.
Exit
EndIf
Next nX
// Repare: RecLock em ALTERAÇÃO (.F.) sobre um registro que já existe.
// Isto só é possível porque a gravação já aconteceu — é a prova, em
// código, de que este PE roda depois do commit.
If lBloqueia
RecLock("SC5", .F.)
SC5->C5_BLQ := "1"
SC5->(MsUnlock())
ConOut("[MT410INC] Pedido " + SC5->C5_NUM + " bloqueado por preco")
EndIf
RestArea(aArea)
Return NilDuas coisas nesse código merecem atenção, porque não são óbvias.
RecLock("SC5", .F.) — alteração, não inclusão. Você está mudando um
registro que já existe. Se o MT410INC rodasse antes da gravação, essa linha não
teria o que travar. É a demonstração mais direta do momento em que ele dispara.
Type("oMainWnd") == "U" — o teste de “tem tela?”. Quando o pedido entra
por portal, integração ou job, não há janela principal. Isso importa porque
qualquer MsgAlert ou Pergunte nesse contexto trava a thread até o timeout
do server — não dá erro no log, deixa a conexão pendurada. Vale o mesmo para
IsBlind().
E quando eu preciso mesmo bloquear?
Aí a regra está no PE errado. Estes são os vizinhos, com o momento de cada um:
| PE | Momento | Retorno é usado? |
|---|---|---|
M410INIC | Antes de montar a tela de inclusão | Não |
MT410TOK | Ao clicar OK, antes da validação do grid | Sim |
MTA410 | Cabeçalho e itens validados, antes de gravar | Sim |
MT410INC | Depois de gravar, fora da transação | Não |
M410STTS | Logo após o MT410INC | Não |
M410ABN | Quando o usuário abandona a inclusão | Não |
Em uma frase cada:
MT410TOK— o usuário clicou OK e nada foi validado em profundidade ainda. É o lugar barato para regra de cabeçalho: cliente, condição de pagamento, tipo de pedido.MTA410— cabeçalho e itens já validados pelo padrão,aColscompleto e consistente. É o lugar para regra que depende dos itens.MT410INC— acabou. É o lugar para efeito colateral.
Três armadilhas específicas deste PE
Achar que ele pode desfazer a inclusão. Não pode: o commit já ocorreu.
Não tratar erro. O pedido já está gravado. Um erro não tratado aqui derruba
a tela do usuário depois de uma gravação bem-sucedida — o pior cenário de
suporte que existe. Envolva a regra em Try..Catch e deixe o pedido em paz.
Ignorar o custo sob carga. Uma importação de 20 mil pedidos por ExecAuto
dispara este PE 20 mil vezes. Um DbSeek com varredura em SE1 aqui dentro
transforma uma carga de 10 minutos numa de 4 horas.
Se um ponto de entrada seu está custando tempo e você quer uma segunda leitura, fale com a gente.
Referências
TDNtdn.totvs.com
TDN — MATA410, Pedidos de Venda
Continue por aqui
- Vídeo
DesenvolvimentoReferência técnica
MT410TOK: o ponto de entrada do OK do pedido de venda
MT410TOK bloqueia de verdade, recebe PARAMIXB e pode alterar o pedido antes de gravar — mas o padrão sobrescreve o retorno sem conferir.