Árvore de páginas

DADOS GERAIS SOBRE O RECURSO

O sistema disponibiliza o plugin de nome "Webhook", onde o sistema terá a possibilidade de notificar aplicações externas, a partir de requisição HTTP REST, em formato JSON, enviando informações referentes ao contexto do gatilho que foi disparado.

Por exemplo, o gatilho de "Sincronização online de pedidos" enviará dados referentes ao pedido sincronizado.

    ESCOPO FUNCIONAL/MANUAL

    O Plugin de integração com o Webhook tem como objetivo notificar aplicações externas, a partir de requisição HTTP REST, enviando informações referentes ao contexto do gatilho que foi disparado atráves de logs.

    Configuração 

    Credenciais

    Acesse "Configuração > Integração > Credenciais" para adicionar novos registros de credenciais. 

    Ao Adicionar novo registro, deve ser preenchido os seguintes campos:

    Campo Descrição
    Descrição Campo que exibe a descrição que será associada ao registro da credencial
    Tipo de Autenticação Campo que permite escolher a autenticação do registro da credencial
    Situação Campo que permite ativar ou inativar o registro da credencial

    Exemplo:

    Configuração do Plugin Webhooks

    Após a configuração das credenciais, acesse "Configuração > Integração > Plugin de Integração" e ative o card Webhooks

    Clique em Configurar para acessar os campos de configuração dos gatilhos do plugin:

    Nesta tela é possível editar/selecionar os seguintes campos:

    Campo Descrição
    Gatilho Permite selecionar qual momento será realizada a validação do registro, seja na sincronização manual ou automatica
    URL Link de conexão ao Plugin webhook (Exemplo: http://{ip_do_servidor}:{PORTA}/webhook)
    Credencial Campo selecionável que permite escolher qual credencial cadastrada no passo anterior será validado no plugin
    Timeout (s) Campo que permite cadastrar o Tempo em segundos que o plugin ficará aguardando a conexão sem gerar timeout
    Protocolo Campo selecoionável que permite escolher o modelo de retorno do protocolo, seja HTTP ou XML
    Botão Excluir Permite excluir o regitro criado

    Depois da configuração e o acesso ao Plugin estar ativo, é possível realizar as sincronizações nos dispositivos operando com o webhook.

    Implementação na Aplicação SFA

    Após realizado a configuração dos pontos acima, no momento que o profissional finalizar o pedido via Android e o pedido for sincronizado automaticamente, é gerado uma requisição no Plugin Webhook e exibido no log.

    Por exemplo:

    Log exibido no Plugin:

    Lembrando que a sincronização automática somente envia dados do aparelho ao servidor, atualmente. Portanto, ao finalizar um pedido e sincronizá-lo automaticamente, o sistema informa o webhook da alteração da entidade, porém, recebe a notificação de alteração do pedido para não finalizado através do módulo de notificação.

    O usuário deverá sincronizar manualmente para receber os dados atualizados para o status não finalizado.

    Já na sincronização manual, é realizado a validação de status e exibido no log da seguinte forma:

    Caso a requisição demore um tempo acima da quantidade de segundos cadastrada no campo pluginintvinculos.int1, ou o retorno for mal sucedido, o sistema manda a mensagem de Falha no log do serviço executado.

    ESCOPO TÉCNICO

    Aplicação

    Alterações em banco de dados


    Novo registro em pluginintegracao

    Contexto / Gatilho: 

    • Tools, opção 5

    Lógica:

    • Insere os seguintes registros na tabela pluginintegracao:

      <changeSet author="systemScript" failOnError="false" id="" runOnChange="true">
          <preConditions onError="HALT" onFail="MARK_RAN" onSqlOutput="IGNORE">
              <customPrecondition className="com.wealthsystems.sim3g.dao.hibernate.api.liquibase.custom.precondition.RegisterExistsPrecondition">
                  <param name="table" value="pluginintegracao"/>
                  <param name="column" value="codigo"/>
                  <param name="value" value="'WEBHOOK'"/>
              </customPrecondition>
          </preConditions>
          <insert tableName="pluginintegracao">
              <column name="IDPLUGININTEGRACAO" valueSequenceNext="SEQPKPLUGININTEGRACAO"/>
              <column name="CODIGO" valueComputed="'WEBHOOK'"/>
              <column name="IDNATIVO" valueComputed="0"/>
              <column name="IDNCUSTOMIZADO" valueComputed="0"/>
          </insert>
      </changeSet>
    Nova coluna em pedido

    Contexto / Gatilho: 

    • Tools, opção 3

    Lógica:

    • Insere os seguintes registros na tabela pedido:

      <changeSet author="System (generated)" failOnError="false" id="" objectQuotingStrategy="LEGACY">
          <addColumn tableName="Pedido">
              <column defaultValue="0" name="idnProcessadoWebHook" type="byte"/>
          </addColumn>
      </changeSet>
    Nova tabela credencial

    Contexto / Gatilho: 

    • Tools, opção 3

    Lógica:

    • Foi criado a tabela credencial, com os seguintes campos:

      <changeSet author="systemScript" failOnError="false" id="" objectQuotingStrategy="LEGACY">
      	<createTable tableName="Credencial">
      		<column name="idCredencial" type="LONG">
      			<constraints nullable="false"/>
      		</column>
      		<column name="descricao" type="VARCHAR(80)">
      			<constraints nullable="false"/>
      		</column>
      		<column name="sgltipoautenticacao" type="VARCHAR(20)">
      			<constraints nullable="false"/>
      		</column>
      		<column name="usuario" type="VARCHAR(120)"/>
      		<column name="senha" type="VARCHAR(200)"/>
      		<column defaultValue="0" name="idnAtivo" type="byte"/>
      	    <column name="codigoerp" type="VARCHAR(80)"/>
      		<column name="wsVersao" type="LONG"/>
      	</createTable>
      </changeSet>
    Nova colunas na tabela pluginintvinculos

    Contexto / Gatilho: 

    • Tools, opção 3

    Lógica:

    • Foi criado a coluna sglagrupador, nullable, para servir de agrupamento de registros para mostrar em uma ou outra grid do mesmo plugin

      • O campo deve possuir índice, visto que será usado para pesquisas frequentes

        <changeSet author="System (generated)" failOnError="false" id="" objectQuotingStrategy="LEGACY">
            <addColumn tableName="PluginIntVinculos">
                <column name="sglagrupador" type="varchar(20)"/>
            </addColumn>
        </changeSet>
    • Foi criado a coluna idcredencial, nullable, FK para tabela credencial

      <changeSet author="System (generated)" failOnError="false" id="" objectQuotingStrategy="LEGACY">
          <addColumn tableName="PluginIntVinculos">
              <column name="idCredencial" type="long"/>
          </addColumn>
      </changeSet>
      <changeSet author="System (generated)" failOnError="false" id="" objectQuotingStrategy="LEGACY">
          <addForeignKeyConstraint baseColumnNames="idCredencial" baseTableName="PluginIntVinculos" constraintName="" deferrable="false" initiallyDeferred="false" referencedColumnNames="idCredencial" referencedTableName="Credencial"/>
      </changeSet>
    • Foi criado colunas genéricas para receber colunas da grid, juntamente com suas descrições:

      <changeSet author="" failOnError="false" id="" objectQuotingStrategy="LEGACY">
          <addColumn tableName="PluginIntVinculos">
              <column name="texto1" type="varchar(400)"/>
              <column name="descricaotexto1" type="varchar(40)"/> 
              <column name="texto2" type="varchar(400)"/>
              <column name="descricaotexto2" type="varchar(40)"/> 
      		<column name="texto3" type="varchar(400)"/>
              <column name="descricaotexto3" type="varchar(40)"/> 
              <column name="int1" type="LONG"/>
              <column name="descricaoint1" type="varchar(40)"/> 
              <column name="int2" type="LONG"/>
              <column name="descricaoint2" type="varchar(40)"/> 
              <column name="decimal1" type="decimal(18,6)"/>
              <column name="descricaodecimal1" type="varchar(40)"/>
              <column name="decimal2" type="decimal(18,6)"/>
              <column name="descricaodecimal2" type="varchar(40)"/> 
              <column name="byte1" type="byte"/>
              <column name="descricaobyte1" type="varchar(40)"/>  
              <column name="byte2" type="byte"/>
              <column name="descricaobyte2" type="varchar(40)"/> 
          </addColumn>
      </changeSet>

     Criação de listagem de credenciais

    Contexto / Gatilho: 

    • Ambiente Web: Configuração → Integração

    Lógica:

    • Vinculado à regra de perfil de acesso de código "regra.acesso.configuracao.plugin.integracao.geral"
      • O sistema disponibiliza nova opção no menu do contexto Configuração → Integração, de nome "Credenciais"(en: "Credentials", es: "Credenciales")
      • Clicando sobre a opção do menu "Credenciais", o sistema exibe tela com os seguintes elementos:
        • "Credenciais"(en: "Credentials", es: "Credenciales"): Título da página
        • SlickGrid contendo as seguintes colunas não editáveis:
            • "Descrição"(en: "Description", es: "Descripción"): Campo texto, representando o valor da coluna credencial.descricao
            • "Tipo de autenticação"(en: "Authentication type", es: "Tipo de autenticación"): Campo texto, representando o valor da coluna credencial.sgltipoautenticacao
            • "Situação"(en: "Status", es: "Situación"): Texto, exibindo Ativo/Inativo quando o campo credencial.idnativo estiver com respectivos valores 1/0.
            • : botão "Editar"(en: "Edit", es: "Editar") que, quando clicado, enviará o usuário para o formulário de credencial, vinculado os valores dos campos ao registro selecionado.
          • A grid tem recurso de adicionar novo registro, disponibilizando botão "Adicionar" (en: "Add", es: "Agregar") que, quando clicado, enviará o usuário para o formulário de credencial
          • Não há necessidade dos botões "Cancelar alteração"(en: "Cancel changes", es: "Cancelar cambios") / "Gravar"(en: "Save", es: "Grabar"), visto que os registros não são editáveis pela grid
          • A pesquisa rápida considera o campo credencial.descricao
          • A pesquisa avançada disponibiliza os seguintes campos:
            • "Tipo de autenticação"(en: "Authentication type", es: "Tipo de autenticación"): campo de opções selecionáveis, com única opção "Básica"(en: "Basic", es: "Básica")
            • "Situação"(en: "Status", es: "Situación"): campos check-box com opções:
              • "Ativo"(en: "Active", es: "Activo"): Marcado por padrão. Quando marcado, filtra registros de credencial onde o campo credencial.idnativo = 1
              • "Inativo"(en: "Inactive", es: "Inactivo"): Desmarcado por padrão. Quando marcado, filtra registros de credencial onde o campo credencial.idnativo = 0

    Criação de formulário de credenciais

    Contexto / Gatilho: 

    • Ambiente Web: Configuração → Integração → Credenciais

    Lógica:

    • O sistema disponibiliza tela com os seguintes elementos:
      • "Formulário de credencial"(en: "Credential form", es: "Formulario de credencial"): título da página
      • "Situação"(en: "Status", es: "Situación"): Campo radio button, com opções Ativo/Inativo quando o campo credencial.idnativo estiver com respectivos valores 1/0.
        • Persiste no campo credencial.idnativo
      • "Descrição"(en: "Description", es: "Descripción"): Campo de input textual, obrigatório.
        • Persiste no campo credencial.descricao
      • "Tipo de autenticação"(en: "Authentication type", es: "Tipo de autenticación"): Campo de opções selecionáveis, obrigatório, com única opção fixa. 
          • "Básica"(en: "Basic", es: "Básica"): valor BASICA
        • Persiste sobre o campo credencial.sgltipoautenticacao
      • "Usuário"(en: "User", es: "Usuario"): campo de input textual
        • O campo somente exibe quando "Tipo de autenticação" = "Básica"
        • O campo é obrigatório quando "Tipo de autenticação" = "Básica"
        • Persiste sobre o campo credencial.usuario
      • "Senha"(en: "Password", es: "Contraseña"): campo de input textual, com máscara de senha (não deve ser possível visualizar seu valor pela DOM - F12)
        • O campo somente exibe quando "Tipo de autenticação" = "Básica"
        • O campo é obrigatório quando "Tipo de autenticação" = "Básica"
        • Persiste sobre o campo credencial.senha
      • "Gravar"(en: "Save", es: "Grabar"): Botão no canto superior direito da tela que, quando clicado, realiza as persistências do formulário em questão.
      • "Voltar"(en: "Back", es: "Volver"): Botão no canto superior direito da tela. Quando clicado, retorna à tela de listagem de credenciais

    Criação de plugin de integração "Webhooks" em tela

    Contexto / Gatilho: 

    • Ambiente Web: Configuração → Integração → Plugins de integração

    Lógica:

    • O sistema exibe card de plugin de integração, com os elementos:
      • (https://pictogrammers.com/library/mdi/icon/webhook/): Ícone do plugin de integração
      • "Webhooks": Título do card
      • Campo switch para ativar/desativar plugin de integração
        • Valor do campo Persiste sobre o campo pluginintegracao.idnativo
      • "Notifique aplicações externas com informações do sistema a partir de gatilhos estratégicos do sistema"(en: "Notify external applications with system information from strategic system triggers", es: "Notifique a aplicaciones externas con información del sistema desde disparadores estratégicos del sistema"): Descrição do card
      • "Configurar"(en: "Configure", es: "Configurar"): botão de ação que, quando clicado, disparará a lógica de acionamento do botão configurar
      • Quando clicado sobre o botão, o sistema deve abrir nova tela com os seguintes elementos:
        • "Webhook (Consulte o manual)"(en: "Webhook (Refer to the manual)", es: "Webhook (Consulte el manual)"): título da pagina, onde "Consulte o manual" é um link para a página Plugin de integração - Webhook
        • "Contratos de aplicações externas": Seção contendo grid referente à tabela pluginintvinculos, com informações agrupadas através do campo pluginintvinculos.sglagrupador = 'contratos' com as seguintes colunas:
          • "Gatilho"(en: "Trigger", es: "Gatillo"): Campo obrigatório, editável, tipo pesquisa, seleção única, abrindo modal de pesquisa com campo "Gatilho"
              • Valor persistido Gatilho
                SYNC_AUTO_PEDIDO_PP Sincronização automática de pedido finalizado
                SYNC_PEDIDO_PP Sincronização manual de pedido finalizado
            • O valor do campo Persiste em pluginintvinculos.texto1, com valor fixo no campo pluginintvinculos.descricaotexto1 = 'Gatilho'
          • "URL": Campo textual, editável, obrigatório.
            • O valor do campo Persiste em pluginintvinculos.texto2, com valor fixo no campo pluginintvinculos.descricaotexto2 = 'URL'
          • "Credencial"(en: "Credential", es: "Credencial"): Campo de opções selecionáveis (combo-box), não obrigatório, nenhuma opção selecionada por padrão, cujas opções virão da seguinte consulta:
              • select idcredencial as valor, descricao as descricao from credencial where idnativo = 1
            • O valor da opção selecionada Persiste no campo pluginintvinculos.idcredencial
          • "Timeout (s)"(en: "Timeout (s)", es: "Tiempo de espera (s)"): Campo editável, aceitando valores inteiros positivos. Valor padrão 10.
            • O valor da opção selecionada Persiste no campo pluginintvinculos.int1, com valor fixo no campo pluginintvinculos.descricaoint1 = 'Timeout (s)'
          • "Protocolo de Retorno"(en: "Return Protocol", es: "Protocolo de retorno"): Campo de opções selecionáveis (combo-box), obrigatório, com as seguintes opções fixas:
          • : Botão de lixeira para remover o registro em questão.
        • "Gravar"(en: "Save", es: "Guardar"): Botão no canto superior direito da tela que, quando clicado, realiza as persistências do formulário em questão.
        • "Voltar"(en: "Back", es: "Volver"): Botão no canto superior direito da tela. Quando clicado, retorna à tela de Configuração → Integração → Plugins de integração

    Implementação de webhook em pedidos de venda - Sincronização manual / Sincronização automática

    Contexto / Gatilho:

    • Sincronização manual de dados do aplicativo móvel para o servidor, após o commit no banco de dados, antes de realizar consulta de dados atualizados que vão para o aparelho.
    • Sincronização automática de dados do aplicativo móvel para o servidor, após o commit no banco de dados.

    Lógica:

    • Caso o plugin de integração "WEBHOOK" esteja com campo pluginintegracao.idnativo = 1
      • Caso exista registro na tabela pluginintvinculos, com os seguintes valores de campos:
          • pluginintvinculos.idpluginintegracao = (select idpluginintegracao from pluginintegracao where codigo = 'WEBHOOK'
          • pluginintvinculos.sglagrupador = 'contratos'
          • pluginintvinculos.texto1 = 'SYNC_PEDIDO_PP' (para sincronização manual) ou 'SYNC_AUTO_PEDIDO_PP' (para sincronização automática)
        • Caso existam pedidos alterados pela aplicação Mobile commitados no banco,
          • Para cada um dos registros cadastrados nesse gatilho (loop),
          • Realizar requisição HTTP POST para ${URL cadastrada no campo pluginintvinculos.texto2}
            • Body

              [
              	{
              		"idpedido": 1, //pedido.idpedido
              		"idusuario": 1, //pedido.idusuarioprofissional
              		"idparceiro": 1, //pedido.idparceiro
              		"idlocal": 2, //pedido.idlocal
              		"idlocalcobranca": 3, //pedido.idlocalcobranca
              		"idfilialvenda": 3, //pedido.idlocalfilialvenda
              		"idfilialretira": 4, //pedido.idlocalfilialretirada
              		"idfilialfaturamento": 5, //pedido.idlocalfilialfaturamento
              		"idtipopedido": 4, //pedido.idtipopedido
              		"idtipocobranca": 5, //pedido.idtipocobranca
              		"idtabelapreco": 6, //pedido.idtabelapreco
              		"idcondicaopagamento": 5, //pedido.idcondicaopagamento
              		"idsegmento": 8, //pedido.idsegmento
              		"idtipologia": 8, //pedido.idtipologia
              		"idoperacao": 8, //pedido.idoperacao
              		"idmoeda": 8, //pedido.idindexador
              		"idtipoestoque": 8, //pedido.idtipoestoque
              		"valortotalbruto": 8.00, //Campo "Valor total bruto do resumo"
              		"valortotalliquido": 9.00, //Campo "Valor total liquido do resumo",
                      "observacaopedido": "texto", //pedido.observacaopedido
                      "observacaonotafiscal": "texto", //pedido.observacaonotafiscal
                      "observacaosituacao": "texto", //pedido.observacaosituacao
                      "observacaoexpedicao": "texto", //pedido.observacaoexpedicao
                      "datapedido": "2020-01-01", //pedido.datapedido
                      "horapedido": "08:21:00", //pedido.horapedido
                      "datafinalizado": "2020-01-01", //pedido.datafinalizado
                      "horafinalizado": "08:21:00", //pedido.horafinalizado
              		"descontopedido": [
              			{
              				"codigo": "8", //pedidotipodesconto.idtipodesconto > tipodesconto.codigo
              				"percentual": 9.00, //pedidotipodesconto.percentual
              				"valor": 10.00 //pedidotipodesconto.valor
              			},
              			{
              				"codigo": "8", //pedidotipodesconto.idtipodesconto > tipodesconto.codigo
              				"percentual": 9.00, //pedidotipodesconto.percentual
              				"valor": 10.00 //pedidotipodesconto.valor
              			}
              		],
              		"pedidoproduto": [
              			{
              				"idpedidoproduto": 1, //pedidoproduto.idpedidoproduto
              				"ordem": 1, //pedidoproduto.ordem
              				"idproduto": 8, //pedidoproduto.idproduto
              				"idembalagem": 10, //pedidoproduto.idembalagem,
              				"quantidade": 9.00, //pedidoproduto.quantidade
              				"precovenda": 10.00, //pedidoproduto.precovenda PS:Valor unitário
              				"precotabela": 11.00, //pedidoproduto.precotabela PS:Valor unitário
              				"precooriginal": 12.00, //pedidoproduto.precooriginal PS:Valor unitário
              				"percentualdesconto": 13.00, //pedidoproduto.percentualdesconto
              				"valordesconto": 13.00, //pedidoproduto.valordesconto PS:Valor unitário
              				"percentualacrescimo": 13.00, //pedidoproduto.percentualacrescimo
              				"valoracrescimo": 13.00, //pedidoproduto.valoracrescimo PS:Valor unitário
              				"idtipopedido": 13.00, //pedidoproduto.idtipopedido
              				"idtipoestoque": 14, //pedidoproduto.idtipoestoque
              				"idtabelapreco": 15, //pedidoproduto.idtabelapreco
              			},
              			{  				
              				"idpedidoproduto": 2, //pedidoproduto.idpedidoproduto 
              				"ordem": 1, //pedidoproduto.ordem
              				"idproduto": 8, //pedidoproduto.idproduto
              				"idembalagem": 10, //pedidoproduto.idembalagem,
              				"quantidade": 9.00, //pedidoproduto.quantidade
              				"precovenda": 10.00, //pedidoproduto.precovenda PS:Valor unitário
              				"precotabela": 11.00, //pedidoproduto.precotabela PS:Valor unitário
              				"precooriginal": 12.00, //pedidoproduto.precooriginal PS:Valor unitário
              				"percentualdesconto": 13.00, //pedidoproduto.percentualdesconto
              				"valordesconto": 13.00, //pedidoproduto.valordesconto PS:Valor unitário
              				"percentualacrescimo": 13.00, //pedidoproduto.percentualacrescimo
              				"valoracrescimo": 13.00, //pedidoproduto.valoracrescimo PS:Valor unitário
              				"idtipopedido": 13.00, //pedidoproduto.idtipopedido
              				"idtipoestoque": 14, //pedidoproduto.idtipoestoque
              				"idtabelapreco": 15, //pedidoproduto.idtabelapreco
              			}
              		],
              		"pedidoentrega": [
              			{
              				"idpedidoentrega": 1, //pedidoentrega.idpedidoentrega
              				"idtipofrete": 4, //pedidoentrega.idtipofrete
              				"idtransportadora": 7, //pedidoentrega.idparceirotransportador
              				"idparceiroentrega": 8, //pedidoentrega.idparceiroentrega
              				"valorfrete": 5.00, //pedidoentrega.valorfrete
              				"valordespesa": 6.00, //pedidoentrega.valordespesa
              				"valorseguro": 7.00 //pedidoentrega.valorseguro       
              			},
              			{
                				"idpedidoentrega": 2, //pedidoentrega.idpedidoentrega 
                              "idtipofrete": 4, //pedidoentrega.idtipofrete
              				"idtransportadora": 7, //pedidoentrega.idparceirotransportador
              				"idparceiroentrega": 8, //pedidoentrega.idparceiroentrega
              				"valorfrete": 5.00, //pedidoentrega.valorfrete
              				"valordespesa": 6.00, //pedidoentrega.valordespesa
              				"valorseguro": 7.00 //pedidoentrega.valorseguro       
              			}
              		],
                      "pedidoparcela": [
              			{
              				"idpedidoparcela": 1, //pedidoentrega.idpedidoparcela
              				"ordem": 1, //pedidoentrega.ordem
              				"valor": 4, //pedidoentrega.valor
              				"datavencimento": 7 //pedidoentrega.datavencimento
              			},
              			{
                				"idpedidoparcela": 2, //pedidoentrega.idpedidoparcela 
                              "ordem": 2, //pedidoentrega.ordem
                              "valor": 4, //pedidoentrega.valor
              				"datavencimento": 7 //pedidoentrega.datavencimento
              			}
              		]
              	},
              	{ /* outro objeto com template acima */ },
              	{ /* outro objeto com template acima */ }
              ]
            • Resposta esperada quando pluginintvinculos.texto3 = 'CARTE' 

              /* Considerando já o PARSE DA resposta do pentaho que é realizada de maneira assíncrona, retornando xml 
              Na tag result.result-rows, o retorno será feito através de 2 campos:
              
              	RETURN: string
              	STATUS: int
              */
              
              Quando bem sucedido:
              {
              	"status": 200
              	"retorno": "" 
              }
              
              Quando mal sucedido:
              {
              	"status": ${<> 200, 201}
              	"retorno": "Mensagem para ser anexada ao log do servidor" 
              }
            • Resposta esperada quando pluginintvinculos.texto3 = '2XX' 

              Quando bem sucedido:
              http_status 2XX 
              Body: No content
              
              Quando mal sucedido:
              http_status <> 2XX
              {
              	"erro": "Mensagem para ser anexada ao log do servidor" 
              }
            • Caso a requisição demore um tempo acima da quantidade de segundos cadastrada no campo pluginintvinculos.int1, ou o retorno for mal sucedido, o sistema deve mandar mensagem no log do serviço executado: 
              • "Falha em requisição WebHook:
                {
                    "gatilho": ${pluginintvinculos.texto1}
                    "url": ${pluginintvinculos.texto2}
                    "descricao": ${quando existe conteúdo no campo "erro", então ${erro}, caso contrário: "Erro inesperado sem mensagem retornada". Caso for erro de timeout: "Tempo esgotado para retorno da requisição"}
                    "entidades": ${Identificadores das entidades enviadas no gatilho. Por exemplo: Pedido -188265, Pedido -188266}
                }"