segunda-feira, 30 de janeiro de 2023

Como chamar uma action no Script Include


Hoje vamos falar sobre "como chamar uma action no Script Include". Se você já precisou fazer uma integração via IntegrationHub, deve estar se perguntando porque você chamaria uma action via Script Include ao inves de usar direto a action na chamada de um flow designer. Sabemos que o comum é usar actions dentro do flow designer, chamar fora é apenas mais uma das possibilidades para atender algum requisito. Um exemplo disso é quando toda a estrutura de integração foi construida no IntegrationHub, mas você precisa de chamar uma integração no Service Portal (dentro do widget), onde não terá a necessidade de seguir um fluxo no flow designer, ao invés de colocar o script direto no widget, como boas praticas você cria o Script Include que poderá ser reutilizado para o mesmo proposito. Lembrando que existem outras possibilidades e você deve sempre considerar o licenciamento do cliente para integrações via IntegrationHub.



Abaixo temos alguns exemplos da estrutura dentro do Script Include.

Exemplo 1 - Retorna todo output conforme criação da action.

getCompanyQuote: function(symbol) {

        try {
            var inputs = {};
            inputs['symbol'] = symbol; //todos input(s) criado(s) dentro da action
seguem esse padrão ao ser inserido aqui.

            //Executa de forma síncrona: Executa em primeiro plano. O código snippet tem
acesso aos outputs.

            //var que chama a action criado no flow designer e seta parametro dentro
do(s) input(s).
            var outputs = sn_fd.FlowAPI.executeAction('global.get_company_quote', inputs);

            //retorna dados via output(s) conforme definido na action.
            return outputs;    

        } catch (ex) {

            var message = ex.getMessage();
            gs.error("ERROR getCompanySearch: " + message);
        }
    },


Exemplo 2 - Retorna apenas o response_body, caso tenha criado algum objeto especifico na action, você pode trocar o response_body pelo seu output que o atenda. E se necessário retorne todos os outputs e dê um dot walking conforme requisito.

getCompanySearch: function(keyword) {
        try {
            var inputs = {};
            inputs['keyword'] = keyword; //todos input(s) criado(s) dentro da action
seguem esse padrão ao ser inserido aqui.

            //Executa de forma síncrona: Executa em primeiro plano. O código snippet
tem acesso aos outputs.

            //var que chama a action criado no flow designer e seta parametro dentro
do(s) input(s).
            var outputs = sn_fd.FlowAPI.executeAction('global.get_company_search', inputs);

            //Nota: os outputs só podem ser recuperados quando a execução é sincronizada.

            //converte output em JSON e dá um dot walking no 'response_body'
(conversão necessária apenas não tenha feito nenhum tratamento no payload direto na action e
ela ainda estiver como string).
            outputs = JSON.parse(outputs['response_body']);

            //retorna dados conforme definido na var outputs da linha anterior.
            return outputs;    

        } catch (ex) {
            var message = ex.getMessage();
            gs.error("ERROR getCompanySearch: " + message);
        }
    },

Para mais informações consulte FlowAPI Methods Scripting with Flows, Subflows, and Actions | ServiceNow Developer

quarta-feira, 18 de janeiro de 2023

Definindo Contextos Para Activies PAD(Process Automation Designer)(Avançado)

    

    Crie uma nova activity clicando no botão New



    Preencha os campos e submeta




    Novos campos estarão visíveis na aba Automation Plan(depende da configuração dos inputs do        flow definido ou ação) podemos definir valores fixos clicando em seu data pill picker, no entanto        observamos um pequeno detalhe não é possível setar os valores de context apenas activity.
    
    Como podemos solucionar tal problema.


       
    Seguimos até a aba Process Automation Designer 



    Entraremos em um PAD criado anteriormente





    Adicionaremos a activity já criada

    
    Adicionando Activity Definindo Contexto


    Na activity conseguimos perceber que podemos pegar valores de outras activies. No entanto não conseguimos deixar como definição padrão. Isso seria muito útil para inserir valores que não deveriam ser modificados ou o qual não necessitaria de inserção todas as vezes que a activity fosse adicionada 


    Iremos definir o sys id da activity do sexto passo no campo comentários



    Segure CRTL + SHIFT + I OU COMMAND + SHIFT + I.
    Vá até a aba Elements, clique primeiro na seta do lado direito, em seguida no campo no lado                 esquerdo     como indicado na figura abaixo.


      Procure por este elemento <sn-ihub-pill>


      Clique com o botão direito em data-pill-value, selecione edit attribute


      Copie o valor do campo(Primeiro Atributo)


Vá até a edição da activity e selecione o data pill activity > Activity Instance > Label e Salve o Registro


Segure CRTL + SHIFT + I OU COMMAND + SHIFT + I, repita os mesmos processos dos passos anteriores selecione o campo e procure pelo seu data-pillvalue



       Copie o atributo(Segundo Atributo)



        Substitua o atributo pelo primeiro atributo copiado


     Pressione CTRL + F e procure pelo segundo atributo copiado


        Substitua o valor pelo primeiro atributo copiado


       Substitua o valor pelo primeiro atributo copiado


       Substitua o valor pelo primeiro atributo copiado



      Não substitua valores que contenham em seu nome o texto sys_original


       Após isso salve o registro


      Assim deve se parecer sua activity após as modificações



Remova a activity anterior e insira novamente, agora temos o contexto definido automaticamente






























































segunda-feira, 16 de janeiro de 2023

IntegrationHub - Como criar um Spoke para buscar empresas listadas na Bolsa de Valores (Action) - Rest API


Passo 1 - Ative o plugin do IntegrationHub.

Passo 2 - Gere uma API Key no link abaixo.


https://www.alphavantage.co/


Endpoint utilizado neste tutorial


https://www.alphavantage.co/query?function=SYMBOL_SEARCH&keywords={PalavraChave}&apikey={SuaApiKey}

Passo 3 - Entre na tabela de properties [sys_properties.list] do ServiceNow e Crie 2 property.


1- Com a Base URL do endpoint que será utilizado.

2- Com a sua API Key.


Obs: Serão usados nos próximos passos dentro da Action.



**Coloque o API Key no value

Passo 4 - Abra o Flow Designer e crie uma nova Action.



*Coloque o mesmo nome, pois será utilizado no Script Include.

Criando o Spoke (Action):


Passo 1

  • Crie um input [keyword] do tipo string.



Passo 2

  • Clique em [Add a new Step] e adicione o Script Step.
  • Crie uma variável output [apikey] do tipo string.
  • Adicione o script: outputs.apikey = gs.getProperty("apiKeyStockExchange");



Passo 3

  • Clique em [Add a new Step] e adicione o REST Step.


*IMPORTANTE: Só estará disponível se você seguiu o Passo 1 que era ativar o IntegrationHub.

[Durante cada etapa na criação da Action vá salvando a cada passo pra não correr o risco de perder o que já foi feito.]

Passo 4
  • Escolha o tipo de connection conforme imagem abaixo.


Adicione a chamada da 2º property na [Base URL]  return gs.getProperty("endpointBaseURL");

  • Adicione o Resource Path conforme o endpoint disponibilizado alguns passos acima.

Ex: BASE URLhttps://www.alphavantage.co/
(já está sendo chamado no passo acima)
Path - query?function=SYMBOL_SEARCH&keywords={code}&apikey={apiKey}
Replique o conteúdo da imagem abaixo.


  • Adicione método do tipo GET.
  • Para evitar possíveis erros adicione no Headers:

            Name: Content-Type | Value: application/json


Passo 5
  • Crie as variáveis de output conforme a imagem baixo, e depois clique em [Exit Edit Mode]
  • Clique, arraste e solte no value dos outputs criados.

*Não esqueça de salvar o último passo desenvolvido.

    Passo 6
  •  clique em [Test]

         Digite dentro da caixinha keyWord o código vale3 e clique em [Run Test].



  • Após rodar clique no link gerado para analisar o response body.
            O Status HTTP desse endpoint utilizado sempre retorna 200, mas a diferença será dentro do response body.


Test de sucesso



Cenário com erro utilizando um valor incorreto




sexta-feira, 6 de janeiro de 2023

Criando um Widget para integração Rest API ViaCep - Service Portal (Avançado)



O primeiro passo é criar um Script Include que será responsável pela integração, utilize o mesmo nome pois será utilizado em outros Scripts.



var ZipCodeDetails = Class.create();
ZipCodeDetails.prototype = {
    initialize: function() {},
    searchForCEP: function(cep) {
        try {

            var request = new sn_ws.RESTMessageV2();
            var endpoint = "https://viacep.com.br/ws/" + cep + "/json/";
            request.setEndpoint(endpoint);
            request.setHttpMethod('get');
            request.setRequestHeader("Accept", "application/json");
            request.setRequestHeader('Content-Type', 'application/json');

            var response = request.execute();
            var responseBody = JSON.parse(response.getBody());
            var httpStatus = response.getStatusCode();

            if (httpStatus == '200') {
            return responseBody;

            }

        } catch (ex) {
            var message = ex.message;

        }
    },

    type: 'ZipCodeDetails'
};

Faça o download da imagem que será usada como ícone lupa no botão de busca clique aqui e selecione a opção 32px, Insira a imagem na tabela db_image, mantenha o nome lupa.png.

Crie um novo Widget de Portal e adicione os Scripts abaixo, tome um tempo para entender o funcionamento de cada Script.


HTML

<!-- todas as classes usadas estão dentro do CSS -->
  <div class="panel">
  <div class="panel-heading">
    <h5>Consulta de CEP</h5>
  </div>
   
<div class="container-search">
 
  <div class="search-field">
    <input class="cep" type="text" ng-model="cep" maxlength="9" required="required">
    &nbsp; &nbsp;
    <button class="button-search" ng-click="c.search(cep)">
        Buscar CEP
    <img src=lupa.png />
    </button>
  </div>
 
  <div class="info-cep" ng-if="data.cepIntegration">
    <div class="info">
      <span>CEP: </span>{{c.data.cepIntegration.cep}}<br/>
      <span>Endereço: </span>{{c.data.cepIntegration.logradouro}}<br/>
      <span>Bairro: </span>{{c.data.cepIntegration.bairro}}<br/>
      <span>Localidade: </span>{{c.data.cepIntegration.localidade}}<br/>
      <span>UF: </span>{{c.data.cepIntegration.uf}}<br/>
      <span>DDD: </span>{{c.data.cepIntegration.ddd}}<br/>
    </div>
  </div>
</div>

CSS

.panel{
   width: 517px;
  .panel-heading{
    background-color: #C4C4C4;
    width: 517px;
    height: fit-content;
        max-height: 638px;
     
    h5{
        margin: 5px 20px;
      font-weight: bold;
     
     
    }
  }
}


.container-search{
   width: 100%;
   width: 517px;
   float: left;
   margin: 0px;
   padding: 20px;
   background-color: #f5f5f5;
   border-radius: 0px;
 

  .search-field{
    width: 100%;
    .cep{
      width: 60%
      margin: 10px;
      border-radius: px;
    }
   
    .button-search{
        width: 45%;
      height: 45px
      color: black;
      background-color: #d1ebf7;
      border-radius: 4px;
      border-color: lightblue;
      margin: 22px;
      margin-top: 2px;
           
    }
     img {
      margin-left: 10px;
     
    }
  }
 
  .info-cep{
    .info{
      display: grid;
      grid-template-columns: auto auto;
      margin: 10px;
      padding: 10px;
      align-items: baseline
      span{
        width: 70%;
        font-weight: bold;
        padding: 10px;
      }
    }
  }
  .empty-field{
    font-size: 16px;
    margin: 10px;
  }
}

Server Script

(function() {
  /* populate the 'data' object /
  / e.g., data.table = $sp.getValue('table'); */

    if(input){

        if(input.action == "getZipCode" ){

            data.cep = input.cep; // Var cep - Onde recebe o valor do input enviado
pelo Client no c.server.update

            data.cepIntegration = new ZipCodeDetails().searchForCEP(data.cep); //Chamada da
integraçao - Script Include
       
 //Quando o CEP for inválido o valor de retorno será undefined, nesse caso poderá ser
usado uma mensagem de aviso ao usuário tanto com gs.addErrorMessage("Insira a messagem de aviso aqui");
|| gs.addInfoMessage(Insira a messagem de aviso aqui");
            if(data.cepIntegration == undefined || data.cepIntegration.erro == true){

                gs.addErrorMessage('CEP inválido, por favor digite um CEP válido.');

            }
        }
    }
   
})();

Client Controller

function BottonLabel($scope,$rootScope,$timeout, $window, $location) {
  /* widget controller */
    var c = this;
    c.search = function(cep) {

        c.data.action = "getZipCode";
        c.cep = cep;
        c.data.cep = c.cep.replace('-', '');
        c.server.update();          

    };
}

Teste

CEP Válido



CEP Inválido



Adicionando campos ao formulário - Servicenow

 1 - Abra a lista da tabela criada recentemente All > nome da tabela e clique em "New". 2 - Clique no context menu > Configu...