Pragiva — Tecnologia na prática

MT410INC o ponto de entrada da inclusão do pedido de venda

Ele dispara depois de o pedido estar gravado, fora da transação, sem PARAMIXB e com o retorno descartado. Isso define exatamente para que ele serve.

Desenvolvimento Referência técnica 4 min de leitura

Assista o vídeo

A ordem das chamadas
  1. A410Grava gravação

MT410INC — Depois de gravar, fora da transação.

O padrão descarta o retorno: não dá para bloquear aqui.

MT410INC em resumo

Localização
A410Inclui(), na rotina MATA410.
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:

ADVPL / TLPP
If lContinua
    If lTMt410Inc
        ExecTemplate("MT410INC", .F., .F.)
    Endif

    If lMt410Inc
        Execblock("MT410INC", .F., .F.)
    Endif
EndIf

Três leituras diretas:

  1. O pedido já existe no banco. SC5 e SC6 estão gravados. Você não está validando nada — está reagindo a um fato consumado.
  2. O retorno não é usado. Execblock(...) aparece como comando, não como expressão atribuída.
  3. 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:

OrigemO que é
SC5->Posicionado no pedido recém-gravado
aHeader / aColsEstrutura 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.

MT410INC.prwADVPL / TLPP
#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 Nil

Duas 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:

PEMomentoRetorno é usado?
M410INICAntes de montar a tela de inclusãoNão
MT410TOKAo clicar OK, antes da validação do gridSim
MTA410Cabeçalho e itens validados, antes de gravarSim
MT410INCDepois de gravar, fora da transaçãoNão
M410STTSLogo após o MT410INCNão
M410ABNQuando o usuário abandona a inclusãoNã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, aCols completo 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

  1. TDNtdn.totvs.com

    TDN — MATA410, Pedidos de Venda

Continue por aqui