Hoje iremos continuar nossa série de mensagens para o WhatsApp, mostrando como enviar mensagens com quebra linhas, texto negrito, texto itálico e também com pontos de entrada para enviar uma mensagem de boas vindas quando um novo Cliente, Fornecedor ou Vendedor for cadastrado.
Primeiramente pessoal, tenha os fontes NETiZAP.prw e zZapSend.prw disponibilizados na primeira semana da série – clique aqui para saber mais.
Agora, o que precisamos entender, é que o próprio WhatsApp trata situações para deixar o texto personalizado, como por exemplo, itálico ser com underscore/underline, negrito ser com asterisco, tachado ser com um til e monoespaçado com crases.
Para o nosso contexto, iremos usar apenas o itálico e o negrito. Além deles, também iremos usar a quebra de linha, que podemos usar simplesmente o \n para quebra. Mas para deixar nosso fonte de maneira mais fácil o entendimento, iremos adaptar para que ele entenda tags HTML, assim ao receber por exemplo <b>, ele já entenda que irá deixar aquele trecho negrito.
Então abaixo segue o zZapSend com as mudanças realizadas:
//Bibliotecas
#Include "TOTVS.ch"
/*/{Protheus.doc} User Function zZapSend
Função que dispara uma mensagem para um smartphone com o aplicativo do WhatsApp
@type Function
@author Atilio
@since 05/08/2021
@version version
@param cTelDestin, Caractere, Telefone de destino com o país 55 e o ddd - por exemplo 5514999998888
@param cMensagem, Caractere, Mensagem que será enviada para esse WhatsApp
@return aRet, Array, Posição 1 define se deu certo o envio com .T. ou .F. e a Posição 2 é o JSON obtido como resposta do envio com o protocolo
@obs É necessário baixar a classe NETiZAP desenvolvida pelo grande Júlio Wittwer
disponível em https://github.com/siga0984/NETiZAP/blob/master/NETiZAP.prw
/*/
User Function zZapSend(cTelDestin, cMensagem)
Local aArea := GetArea()
Local cLinha := SuperGetMV("MV_X_ZAPLI", .F., "5521986855299")
Local nPorta := SuperGetMV("MV_X_ZAPPO", .F., 13155)
Local cChave := SuperGetMV("MV_X_ZAPCH", .F., "fUzanE5ncxlTAWBjMO30")
Local aRet := {.F., ""}
Local oZap
Default cTelDestin := ""
Default cMensagem := ""
//Retira caracteres em branco dos lados
cTelDestin := Alltrim(cTelDestin)
cMensagem := Alltrim(cMensagem)
//Transforma o texto em UTF-8
cMensagem := EncodeUTF8(cMensagem)
//Retira caracteres especiais do telefone por exemplo +55 (14) 9 9999-8888
cTelDestin := StrTran(cTelDestin, " ", "")
cTelDestin := StrTran(cTelDestin, "+", "")
cTelDestin := StrTran(cTelDestin, "(", "")
cTelDestin := StrTran(cTelDestin, ")", "")
cTelDestin := StrTran(cTelDestin, "-", "")
//Se houver telefone, mensagem, o número for menor que 12 caracteres (551400000000) e não iniciar com 55 não irá enviar a mensagem
If Empty(cTelDestin) .And. Empty(cMensagem) .And. Len(cTelDestin) < 12 .And. SubStr(cTelDestin, 1, 2) != "55"
aRet[1] := .F.
aRet[2] := '[{"error":"Parametro(s) enviado(s) para zZapSend, invalido(s)"}]'
Else
//Se na mesma mensagem, tiver o -Enter- normal e tags br, retira os -Enter-
If CRLF $ cMensagem .And. "<br>" $ cMensagem
cMensagem := StrTran(cMensagem, CRLF, '')
EndIf
//Agora, irá converter o restante para o formato que o WhatsApp entenda
cMensagem := StrTran(cMensagem, CRLF , '\n')
cMensagem := StrTran(cMensagem, '<br>' , '\n')
cMensagem := StrTran(cMensagem, '<b>' , '*')
cMensagem := StrTran(cMensagem, '</b>' , '*')
cMensagem := StrTran(cMensagem, '<i>' , '_')
cMensagem := StrTran(cMensagem, '</i>' , '_')
//Instancia a classe, e passa os parametros da NETiZAP
oZap := NETiZAP():New(cLinha, cChave, nPorta)
//Define o destino e a mensagem de envio
oZap:SetDestiny(cTelDestin)
oZap:SetText(cMensagem)
//Atualiza o retorno conforme se a mensagem foi enviada ou houve falha
If oZap:MessageSend()
aRet[1] := .T.
aRet[2] := oZap:GetResponse()
Else
aRet[1] := .F.
aRet[2] := oZap:GetLastError()
EndIf
EndIf
RestArea(aArea)
Return aRet
Agora, iremos fazer 3 pontos de entrada, para que, ao ser criado um vendedor, um cliente ou um fornecedor, seja enviado uma mensagem de boas-vindas. No caso, os pontos de entrada que usaremos serão:
- Cadastro de Vendedores: MA040TOK
- Cadastro de Fornecedores: CUSTOMERVENDOR – MODELCOMMITNTTS
- Cadastro de Clientes: CRMA980 – MODELCOMMITNTTS
Em cada um desses citados acima, iremos adicionar uma chamada para nosso zZapSend, para que seja enviado uma mensagem personalizada para cada caso. Iremos criar 1 fonte só com as 3 User Function, e iremos chamar de zZapNew.prw. Abaixo o código fonte desenvolvido:
//Bibliotecas
#Include "TOTVS.ch"
/*/{Protheus.doc} User Function MA040TOK
Função na validação do cadastro de vendedores
@type Function
@author Atilio
@since 06/08/2021
@version version
@see https://tdn.totvs.com/pages/releaseview.action?pageId=6784256
/*/
User Function MA040TOK()
Local aArea := GetArea()
Local lRet := .T.
Local cNome := ""
Local cDDD := ""
Local cTelefone := ""
Local cApertoMao := "\uD83E\uDD1D"
Local cBraco := "\uE14C"
Local cMaosJuntas := "\uE41D"
Local cMensagem := ""
Local aZap := {}
//Se for inclusão
If INCLUI
//Se tiver o nome reduzido, usa ele, do contrário, usa o nome
If ! Empty(M->A3_NREDUZ)
cNome := Alltrim(M->A3_NREDUZ)
Else
cNome := Alltrim(M->A3_NOME)
EndIf
cNome := Capital(cNome)
//Pega o DDD, e se o usuário ter digitado 3 caracteres, retira o primeiro, por exemplo, 014 -> 14
cDDD := Alltrim(M->A3_DDDTEL)
If Len(cDDD) == 3
cDDD := SubStr(cDDD, 2)
EndIf
//Pega o Telefone e retira os espaços
cTelefone := Alltrim(M->A3_TEL)
//Se tiver DDD e Telefone
If ! Empty(cDDD) .And. ! Empty(cTelefone)
//Monta a mensagem que será enviada ao vendedor
cMensagem := 'Olá <b>' + cNome + '</b> ' + cApertoMao + '<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += 'Seja bem vindo ao nosso time de Vendedores e Representantes ' + cBraco + '<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += 'Esperamos que a parceria seja próspera e duradoura ' + cMaosJuntas + '<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += 'Atenciosamente,<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += '<i>Família Terminal de Informação</i>' + CRLF
//Faz o envio da mensagem
aZap := u_zZapSend("55" + cDDD + cTelefone, cMensagem)
//Se houve falha, mostra a mensagem de erro
If ! aZap[1]
MsgStop(aZap[2], "Falha no envio")
EndIf
EndIf
EndIf
RestArea(aArea)
Return lRet
/*/{Protheus.doc} User Function CUSTOMERVENDOR
Ponto de Entrada no padrão MVC acionado no cadastro de Fornecedores
@type Function
@author Atilio
@since 06/08/2021
@version version
@see https://centraldeatendimento.totvs.com/hc/pt-br/articles/360016405952-Cross-Segmento-TOTVS-Backoffice-Linha-Protheus-ADVPL-Ponto-de-entrada-MVC-para-as-rotinas-MATA010-MATA020-e-MATA030
/*/
User Function CUSTOMERVENDOR()
Local aArea := GetArea()
Local aParam := PARAMIXB
Local xRet := .T.
Local oObj := Nil
Local cIdPonto := ""
Local cIdModel := ""
Local lIsGrid := .F.
Local cMensagem := ""
Local nOpc
Local cAceno := "\uE41E"
Local cSorriso := "\uE056"
Local cPiscada := "\uE405"
//Se tiver parâmetros
If (aParam != Nil)
//Pega informações dos parâmetros
oObj := aParam[1]
cIdPonto := aParam[2]
cIdModel := aParam[3]
lIsGrid := (Len(aParam) > 3)
nOpc := oObj:GetOperation()
//Chamada após a gravação total do modelo e fora da transação
If (cIdPonto == "MODELCOMMITNTTS")
//Se for inclusão
If nOpc == 3
//Se tiver o contato, usa ele, do contrário, usa o nome reduzido
If ! Empty(SA2->A2_CONTATO)
cNome := Alltrim(SA2->A2_CONTATO)
Else
cNome := Alltrim(SA2->A2_NREDUZ)
EndIf
cNome := Capital(cNome)
//Pega o DDD, e se o usuário ter digitado 3 caracteres, retira o primeiro, por exemplo, 014 -> 14
cDDD := Alltrim(SA2->A2_DDD)
If Len(cDDD) == 3
cDDD := SubStr(cDDD, 2)
EndIf
//Pega o Telefone e retira os espaços
cTelefone := Alltrim(SA2->A2_TEL)
//Se tiver DDD e Telefone
If ! Empty(cDDD) .And. ! Empty(cTelefone)
//Monta a mensagem que será enviada ao fornecedor
cMensagem := 'Olá <b>' + cNome + '</b> ' + cAceno + '<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += 'Estamos felizes em fazer negócios com você e sua empresa ' + cSorriso + '<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += 'Esperamos atender as expectativas e do que precisar conte com nossa equipe ' + cPiscada + '<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += 'Atenciosamente,<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += '<i>Família Terminal de Informação</i>' + CRLF
//Faz o envio da mensagem
aZap := u_zZapSend("55" + cDDD + cTelefone, cMensagem)
//Se houve falha, mostra a mensagem de erro
If ! aZap[1]
MsgStop(aZap[2], "Falha no envio")
EndIf
EndIf
EndIf
EndIf
EndIf
RestArea(aArea)
Return xRet
/*/{Protheus.doc} User Function CRMA980
Ponto de Entrada no padrão MVC acionado no cadastro de Clientes
@type Function
@author Atilio
@since 06/08/2021
@version version
@see https://centraldeatendimento.totvs.com/hc/pt-br/articles/360016405952-Cross-Segmento-TOTVS-Backoffice-Linha-Protheus-ADVPL-Ponto-de-entrada-MVC-para-as-rotinas-MATA010-MATA020-e-MATA030
@obs A função MATA030 será descontinuada em 04/04/2022, então foi usado esse CRMA980 no lugar, veja:
https://tdn.totvs.com/pages/releaseview.action?pageId=604230458
/*/
User Function CRMA980()
Local aArea := GetArea()
Local aParam := PARAMIXB
Local xRet := .T.
Local oObj := Nil
Local cIdPonto := ""
Local cIdModel := ""
Local lIsGrid := .F.
Local cMensagem := ""
Local nOpc
Local cOculos := "\uD83D\uDE0E"
Local cComputador := "\uD83D\uDDA5"
Local cSacola := "\uD83D\uDECD"
//Se tiver parâmetros
If (aParam != Nil)
//Pega informações dos parâmetros
oObj := aParam[1]
cIdPonto := aParam[2]
cIdModel := aParam[3]
lIsGrid := (Len(aParam) > 3)
nOpc := oObj:GetOperation()
//Chamada após a gravação total do modelo e fora da transação
If (cIdPonto == "MODELCOMMITNTTS")
//Se for inclusão
If nOpc == 3
//Se tiver o contato, usa ele, do contrário, usa o nome reduzido
If ! Empty(SA1->A1_CONTATO)
cNome := Alltrim(SA1->A1_CONTATO)
Else
cNome := Alltrim(SA1->A1_NREDUZ)
EndIf
cNome := Capital(cNome)
//Pega o DDD, e se o usuário ter digitado 3 caracteres, retira o primeiro, por exemplo, 014 -> 14
cDDD := Alltrim(SA1->A1_DDD)
If Len(cDDD) == 3
cDDD := SubStr(cDDD, 2)
EndIf
//Pega o Telefone e retira os espaços
cTelefone := Alltrim(SA1->A1_TEL)
//Se tiver DDD e Telefone
If ! Empty(cDDD) .And. ! Empty(cTelefone)
//Monta a mensagem que será enviada ao cliente
cMensagem := 'Olá <b>' + cNome + '</b> ' + cOculos + '<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += 'Lhe desejamos as boas vindas, e saiba que do que precisar, pode nos acionar pelo fone <b>(14) 9 9738-5495</b><br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += 'Caso queira dar uma olhada no nosso portfolio, acesse ' + cComputador + ' https://atiliosistemas.com/projetos/<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += 'Boas compras ' + cSacola + '<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += 'Atenciosamente,<br>' + CRLF
cMensagem += '<br>' + CRLF
cMensagem += '<i>Família Terminal de Informação</i>' + CRLF
//Faz o envio da mensagem
aZap := u_zZapSend("55" + cDDD + cTelefone, cMensagem)
//Se houve falha, mostra a mensagem de erro
If ! aZap[1]
MsgStop(aZap[2], "Falha no envio")
EndIf
EndIf
EndIf
EndIf
EndIf
RestArea(aArea)
Return xRet
Abaixo um print com as mensagens enviadas para vendedores (SA3), fornecedores (SA2) e clientes (SA1):
Obs.: Os códigos desenvolvidos nessa série do WhatsApp, estão dentro do nosso GitHub, o link é https://github.com/dan-atilio/AdvPL.
Lembrando também pessoal, se tiverem interesse em adquirir uma licença da API, entrem em contato com o pessoal da NETiZAP clicando aqui, e digam que conhecem o Atilio do Terminal de Informação.
Bom pessoal, por hoje é só.
Abraços e até a próxima.

Boa tarde Atílio, tudo bem, vê se pode me ajudar?
Baixei o fonte compilei, liberei a porta 13155, e quando efetuo a rotina u_zZapTest(), da o erro http error (10060): Comunication time out.
Bom dia Jeferson, tudo joia?
Que estranho, se você realizar testes com a NETiZAP via Postman também dá o erro?
Outro ponto, o token que eles nos liberaram para testes (em 2021) acho que já expirou. Você esta usando um token gerado por vocês mesmo?
Fico no aguardo.
Tenha uma ótima e abençoada quinta feira.
Um grande abraço.