Como quebrar linhas em mensagens do WhatsApp usando AdvPL/TL++

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 , 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. "
" $ 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, '
' , '\n') cMensagem := StrTran(cMensagem, '' , '*') cMensagem := StrTran(cMensagem, '' , '*') cMensagem := StrTran(cMensagem, '' , '_') cMensagem := StrTran(cMensagem, '' , '_') //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á ' + cNome + ' ' + cApertoMao + '
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Seja bem vindo ao nosso time de Vendedores e Representantes ' + cBraco + '
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Esperamos que a parceria seja próspera e duradoura ' + cMaosJuntas + '
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Atenciosamente,
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Família Terminal de Informação' + 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á ' + cNome + ' ' + cAceno + '
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Estamos felizes em fazer negócios com você e sua empresa ' + cSorriso + '
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Esperamos atender as expectativas e do que precisar conte com nossa equipe ' + cPiscada + '
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Atenciosamente,
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Família Terminal de Informação' + 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á ' + cNome + ' ' + cOculos + '
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Lhe desejamos as boas vindas, e saiba que do que precisar, pode nos acionar pelo fone (14) 9 9738-5495
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Caso queira dar uma olhada no nosso portfolio, acesse ' + cComputador + ' https://atiliosistemas.com/projetos/
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Boas compras ' + cSacola + '
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Atenciosamente,
' + CRLF cMensagem += '
' + CRLF cMensagem += 'Família Terminal de Informação' + 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):

Exemplo das mensagens acionadas nos pontos de entrada

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.

Dan (Daniel Atilio)
Cristão de ramificação protestante. Especialista em Engenharia de Software pela FIB, graduado em Banco de Dados pela FATEC Bauru e técnico em informática pelo CTI da Unesp. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor e mantenedor do portal Terminal de Informação.

2 Responses

  1. Jeferson disse:

    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.

Deixe uma resposta

Terminal de Informação