Por que eu devo ler este artigo: Este artigo é útil por apresentar conceitos de comunicação do nosso aplicativo com uma segunda API de pagamentos muito famosa no mercado: o MercadoPago. Essa solução é mais flexível que a primeira (PayPal) no que se refere ao parcelamento dos pagamentos, bem como solicitação de outras ações básicas, como recibos, fluxos de estorno, etc. Por ser uma empresa latina, o MercadoPago se aplica melhor às regras locais do nosso país, além de oferecer uma vasta documentação sobre como implementar seus recursos. Neste artigo, o leitor aprenderá a conectar nosso app com tal API, vendo dicas de como analisar melhor seus dados de retorno.

Na última parte do artigo vimos como efetuar a implementação do checkout via carrinho de compras em integração com a API do PayPal para Cordova que a empresa disponibilizou como forma de facilitar a comunicação no universo JavaScript com as engines SDKs dos sistemas operacionais mobile iOS e Android. Com base nisso, já conseguimos efetuar todo o fluxo de compra simplificado, inclusive a coleta de dados do usuário, já que o próprio PayPal se encarrega de tal tarefa, dado que é preciso estar logado para finalizar o pagamento. Também vimos como finalizar o fluxo limpando todos os dados do carrinho do usuário e o redirecionando para uma tela de sucesso.

Todavia, ainda precisamos disponibilizar ao usuário uma forma de parcelar suas compras caso o mesmo deseje, com a respectiva atualização dos valores de juros e provisionamentos. Infelizmente, o PayPal tem algumas limitações em relação à nova API, inclusive para os SDKs mobile no que se refere a parcelamento. O leitor terá a opção de implementar tal fluxo quando estiver inserido no modelo de Express Checkout, isto é, quando seu site gera um botão que redireciona o usuário para o site do PayPal com os dados da compra e parcelamentos inclusos. Vejamos na Figura 1 o fluxo básico definido pelo PayPal para esse tipo de implementação. Observe que o usuário tem, de igual forma, as opções de efetuar o pagamento com suas credenciais do PayPal (nesse caso, para pagamentos com cartão de crédito os valores serão considerados caso o usuário não tenha saldo na conta do PayPal) ou informando manualmente dos dados pessoais e do cartão de crédito.

Fluxo de parcelamento junto ao PayPal
Figura 1. Fluxo de parcelamento junto ao PayPal.

De toda forma, o fluxo inicia do seu website, é processado no ambiente do PayPal e, no final, pode ser finalizado redirecionando para o seu website novamente. Porém, essa é de longe a melhor forma de implementarmos já que estamos usando componentes embutidos no aplicativo mobile na forma de plugins. Você até pode seguir com o mesmo fluxo através da sua página HTML no projeto PhoneGap, mas isso definitivamente não é indicado. Na seção Links você pode encontrar a URL da documentação do PayPal que ensina todos os passos para proceder dessa forma.

No nosso caso, como precisamos de um ambiente seguro e que nos disponibilize mais opções para o mercado brasileiro (lembre-se que as opções do PayPal para o mercado nacional são limitadas, por exemplo: pagamentos com cartão de crédito só são permitidos em moeda americana), analisaremos uma segunda API de pagamentos muito famosa do mercado: o MercadoPago.

Integrando a API do MercadoPago

O MercadoPago é o sistema de pagamentos seguros online mais famoso da América. Seu módulo para desenvolvedores (vide URL na seção Links) atinge vários mercados e plataformas, contemplando desde SDKs clientes para tecnologias como Android, iOS e JavaScript (que é o nosso caso), até para servidores atendendo linguagens de programação diversas: PHP, Java, .Net, Node.js, ASP.NET, Ruby e Phyton. É possível ainda efetuar testes facilmente com o ambiente de Sandbox, muito semelhante ao que trabalhamos com o do PayPal.

A solução conta ainda com módulos e plugins facilmente integráveis a diversas plataformas de e-commerce online, como Magento, OpenCart, WordPress, etc. Ou, se você preferir, pode também criar os famosos botões de redirecionamento que levam o usuário à finalização da compra no próprio site do MercadoPago, uma opção mais simples e que se abstém da necessidade de conhecimentos técnicos mais avançados. Finalmente, a empresa ainda conta com opções para pagamentos físicos para os casos em que o usuário deseje portar uma maquininha de cartões (solução parecida com a da Cielo ou PagSeguro, por exemplo) através do MercadoPago Point.

Para a nossa solução, faremos uso de dois SDKs da plataforma: o SDK JavaScript nos será útil para coletar as informações pessoais e do cartão de crédito do usuário para gerar um token de autenticação que, por sua vez, será enviado ao segundo SDK, baseado em Java e que estará hospedado no nosso servidor (via Web Service), pois será nesse momento em que o pagamento de fato será gerado e enviado aos servidores do MercadoPago.

A primeira coisa que temos de ter em mente quando implementamos a coleta de dados sensíveis do usuário, cuja confidencialidade deve ser mantida acima de tudo, é que não podemos hospedá-los em nossas aplicações ou enviá-los ao nosso serviço via HTTP, visto que nosso ambiente não foi homologado nem atende aos critérios estabelecidos pelas normas de segurança da indústria. Essas mesmas normas são definidas pela PCI DSS (Payment Card Industry Data Security Standard), um padrão de segurança internacional que especifica exigências mínimas a serem atendidas pelas empresas que façam uso do consumo financeiro gerado por bandeiras famosas, como Visa, MasterCard, American Express, Discover, etc. Marcas privadas e específicas de certos países não estão inclusas no padrão. Os serviços que consumiremos do MercadoPago já implementam as mesmas via SDKs, nos facilitando todo esse trabalho.

Na Listagem 1, o leitor encontra um exemplo de formulário que o MercadoPago disponibiliza em sua documentação como sugestão de dados sensíveis que precisarão ser coletados no momento da criação de um pagamento. Veja que se trata de um formulário convencional sem nenhum estilo associado, apenas a estrutura baseada em campos de input, seus tipos e valores de placeholder (esse, inclusive, pode ser usado para dar dicas ao usuário de que dados ele pode inserir). Cada campo recebe um id de mesmo valor que o atributo data-checkout, que, por sua vez, será usado pela API JavaScript do MercadoPago para validar as informações fornecidas pelo usuário. Em resumo, os campos que precisamos solicitar são: e-mail, dados do cartão de crédito (como número, cvv, data de expiração e titular do cartão de crédito), tipo do documento e número do documento do mesmo. Algumas dessas informações variam de acordo com o país onde se deseja efetuar a venda, logo leia bem a documentação caso deseje liberar pagamentos internacionais no seu app.


<form action="" method="post" id="pay" name="pay" >
  <fieldset>
   <ul>
    <li>
     <label for="email">Email</label>
     <input id="email" name="email" value="test_user_19653727@testuser.com" 
     type="email" placeholder="your email"/>
    </li>
    <li>
     <label for="cardNumber">Credit card number:</label>
     <input type="text" id="cardNumber" data-checkout="cardNumber" 
     placeholder="4509 9535 6623 3704" />
    </li>
    <li>
     <label for="securityCode">Security code:</label>
     <input type="text" id="securityCode" data-checkout="securityCode" 
     placeholder="123" />
    </li>
    <li>
     <label for="cardExpirationMonth">Expiration month:</label>
     <input type="text" id="cardExpirationMonth" 
     data-checkout="cardExpirationMonth" placeholder="12" />
    </li>
    <li>
     <label for="cardExpirationYear">Expiration year:</label>
     <input type="text" id="cardExpirationYear" 
     data-checkout="cardExpirationYear" placeholder="2015" />
    </li>
    <li>
     <label for="cardholderName">Card holder name:</label>
     <input type="text" id="cardholderName" data-checkout="cardholderName" 
     placeholder="APRO" />
    </li>
    <li>
     <label for="docType">Document type:</label>
     <select id="docType" data-checkout="docType"></select>
    </li>
    <li>
     <label for="docNumber">Document number:</label>
     <input type="text" id="docNumber" data-checkout="docNumber" 
     placeholder="12345678" />
    </li>
   </ul>
   <input type="submit" value="Pay!" />
  </fieldset>
</form>
Listagem 1. Código HTML sugerido pelo MercadoPago para coletar dados do usuário

O MercadoPago disponibiliza dois tipos de pagamentos básicos:

  • Checkout básico: permite criar um pagamento específico através da geração de um botão para que o usuário seja redirecionado para o site do MercadoPago, finalizando a compra lá e voltando para o seu site via URL de callback;
  • Checkout transparente: o usuário não tem contato algum com o site do MercadoPago e toda a comunicação é efetuada através das APIs da plataforma, com chamadas seguras via Rest e recebimentos das respostas também por funções de callback.

Faremos uso do checkout transparente, pois, apesar de mais complexo, atende melhor às nossas exigências, afinal não queremos que o usuário saiba qual a plataforma de pagamentos que estamos usando por detrás.

Coletando os dados de pagamento

Mas antes de partirmos para a implementação do código do MercadoPago, voltemos nossa atenção à criação da página que usaremos no app para coletar os referidos dados. No arquivo index.html do projeto, adicione uma nova page tal como demonstrado na Listagem 2. Em si, a listagem é relativamente simples: apenas exibe cada um dos campos usando o estilo de formulários do Framework7. Na linha 2, por exemplo, podemos ver a mesma declaração de formulário que herdamos do exemplo fornecido pelo MercadoPago, estrutura essa que se repete na declaração individual de cada um dos inputs. O que muda, no todo, é a organização da estrutura para impor o design do Framework7.

Nas linhas 5 e 6 vemos dois campos de input do tipo hidden para salvar informações (valor e descrição da compra) que precisaremos enviar para o nosso serviço que, de fato, processará o pagamento, o qual será criado mais adiante.

Em relação aos campos do formulário, o Framework7 trabalha com um ícone atrelado ao campo de texto. O ícone deve ser declarado sob a forma de elemento <i> tal como estávamos fazendo para os ListViews. O modelo que implementamos na listagem faz uso do Material Design do Google, que define que as labels dos campos de formulário devem aparecer dentro dos mesmos, e assim que o usuário clicar em um dado campo, as mesmas devem flutuar logo acima dele. Dessa forma, o placeholder que configuramos em todos os inputs não surtirá efeito, porém você verá mais adiante uma forma de remover esse efeito.

Perceba que mantivemos todas as configurações dos inputs tal qual nos fora recomendado pelo MercadoPago, exceto pelos tipos dos mesmos (atributo type), os quais alteramos para que cada um equivalha ao tipo de dado que ali será digitado (ex: number, email, text, etc.).


<div class="page-content form-mp">
  <form method="post" id="pay" name="pay">
    <div class="content-block-title">Efetuar Pagamento com 
    MercadoPago!</div>
    <div class="list-block inputs-list">
     <input type="hidden" value="23.00" name="valor" />
     <input type="hidden" value="teste" name="descricao" /> 
     <input type="hidden" value="1" name="parcelas" />
     <ul>
       <li>
        <div class="item-content">
         <div class="item-media"><i class="zmdi zmdi-email">
         </i></div>
         <div class="item-inner">
          <div class="item-title floating-label">E-mail</div>
          <div class="item-input item-input-field">
            <input id="email" name="email" data-checkout="email" 
            type="email" placeholder="Digite seu email" />
          </div>
         </div>
        </div>
       </li>
       <li>
        <div class="item-content">
         <div class="item-media bandeira"><i class="zmdi zmdi-card">
         </i></div>
         <div class="item-inner">
          <div class="item-title floating-label">Número do Cartão</div>
          <div class="item-input item-input-field">
            <input type="number" id="cardNumber" data-checkout="cardNumber" 
            placeholder="4509 9535 6623 3704" />
          </div>
         </div>
        </div>
       </li>
       <li>
        <div class="item-content">
         <div class="item-media"><i class="zmdi zmdi-shield-security">
         </i></div>
         <div class="item-inner">
            <div class="item-title floating-label">CVV</div>
            <div class="item-input item-input-field">
              <input type="number" id="securityCode" data-checkout="securityCode" 
              placeholder="123" maxlength="3"/>
            </div>
         </div>
        </div>
       </li>
       <li>
        <div class="item-content">
         <div class="item-media"><i class="zmdi zmdi-calendar">
         </i></div>
         <div class="item-inner">
            <div class="item-title floating-label">Mês Vencimento</div>
            <div class="item-input item-input-field">
              <input type="number" id="cardExpirationMonth" 
              data-checkout="cardExpirationMonth" placeholder="12" />
            </div>
         </div>
        </div>
       </li>
       <li>
        <div class="item-content">
         <div class="item-media"><i class="zmdi zmdi-calendar">
         </i></div>
         <div class="item-inner">
          <div class="item-title floating-label"
          >Ano Vencimento</div>
          <div class="item-input item-input-field">
            <input type="number" id="cardExpirationYear" 
            data-checkout="cardExpirationYear" placeholder="2016" />
          </div>
         </div>
        </div>
       </li>
       <li>
          <div class="item-content">
           <div class="item-media">
           <i class="zmdi zmdi-folder-person"></i></div>
           <div class="item-inner">
              <div class="item-title floating-label"
              >Nome do Titular</div>
              <div class="item-input item-input-field">
                <input type="text" id="cardholderName" 
                data-checkout="cardholderName" placeholder="JULIO SAMPAIO" />
              </div>
           </div>
          </div>
       </li>
       <li>
        <div class="item-content">
         <div class="item-media"><i 
         class="zmdi zmdi-accounts-list-alt"></i></div>
         <div class="item-inner">
           <div class="item-title floating-label">Tipo do Documento</div>
           <div class="item-input item-input-field">
              <select id="docType" data-checkout="docType"></select>
           </div>
         </div>
        </div>
       </li>
       <li>
        <div class="item-content">
         <div class="item-media"><i class="zmdi 
         zmdi-card-membership"></i></div>
         <div class="item-inner">
          <div class="item-title floating-label">Número do Documento</div>
          <div class="item-input item-input-field">
            <input type="number" id="docNumber" 
            data-checkout="docNumber" placeholder="41763266702" />
          </div>
         </div>
        </div>
       </li>
     </ul>
    </div>
  </form>
</div>
Listagem 2. Page com o formulário de coleta dos dados sensíveis do usuário

Como a estrutura básica do nosso exemplo de formulário foi extraída da página inicial de exemplos do Framework7, para que o suporte ao Material Design funcione precisamos importar dois novos arquivos: o kitchen-sink.css na tag <head>, que se encontra disponível na pasta www/css do download de código fonte deste artigo e que fora importado diretamente da página de exemplos do Framework7 com classes CSS auxiliares para impor estilos extras na HTML (procure importá-lo logo após o CSS do Framework7):


<link rel="stylesheet" href="css/kitchen-sink.css">

E o segundo é o kitchen-sink.js, disponível na pasta www/js do mesmo download, que deve ser posicionado na parte inferior da página logo após o import dos js do Framework7:


<script type="text/javascript" src="js/kitchen-sink.js"></script>

Para deixar a tela pronta com o respectivo botão de envio das informações, podemos incluir o seguinte trecho de código após o fechamento da tag <ul>, na linha 96 da listagem anterior:


<div class="content-block">
       <input type="submit" class="button button-raised button-fill 
       color-indigo" value="Efetuar Pagamento" />
</div>

Para finalizar, inclua também o código CSS representado na Listagem 3, que se encarregará de sobrescrever algumas propriedades padrão do estilo do Framework7. Tais propriedades incluem a cor e tamanho da fonte dos ícones que deverão aparecer em tamanho maior nessa página, além do peso da fonte (de negrito para normal) e do espaçamento interno do título da página. Independente da regra, é importante declará-las como regras filhas do formulário, já que se aplicarão somente ao mesmo e não desalinharão o restante do estilo. O resultado da página pode ser visualizado na Figura 2.


<style>
   .form-mp .zmdi {
          font-size: 24px;
          color: #757575;
   }
   .form-mp .floating-label, .form-mp .item-input, 
   .form-mp .item-title {
          font-weight: normal;
   }
   .form-mp .content-block-title {
          height: 41px;
          padding-top: 26px;
   }
</style>
Listagem 3. Código CSS para ajustar ícones e fonte na página
Página de solicitação dos dados de pagamento
Figura 2. Página de solicitação dos dados de pagamento.

Caso deseje exibir seus próprios placeholder’s, deixando as labels de cada campo fixas na tela, basta remover todas as classes CSS floating-label do código, assim nossa mesma implementação ficará igual à Figura 3.

Página de pagamento com sugestão de dados via placeholder
Figura 3. Página de pagamento com sugestão de dados via placeholder.
Nota: É importante que o leitor implemente algumas regras básicas de validação nos campos via JavaScript, como campos obrigatórios (todos são), tamanho máximo dos valores, etc.

Pickers na página de pagamento

Na mesma tela, devemos adicionar alguma lógica de preenchimento para os campos que representam uma combobox. Por exemplo, os campos de Mês e Ano de expiração do cartão de crédito precisam disponibilizar alguns valores para o usuário selecionar, ou você pode disponibilizar os campos no tipo texto para digitação livre pelo mesmo usuário. Em todo caso, façamos o código que carrega uma lista de opções via componente Picker do Framework7. Na Listagem 4 você encontra o código que deve ser inserido numa tag <script> ao final das demais importações de arquivos js da index.html.

Veja que, como se trata de dois componentes distintos, precisamos criar um componente individual para cada um, logo isso resultará em dois vetores: meses e anos. O processo de preenchimento dos meses pode ser feito via for que vai de 1 até 12. Já em relação aos anos, precisamos estipular uma margem mínima a partir do ano corrente e iterar sobre a mesma. Vamos considerar um intervalo de 20 anos, o suficiente para esse tipo de implementação. Na linha 7 criamos um objeto do tipo Date no JavaScript para que possamos recuperar a informação do ano corrente via função getFullYear(), daí é só somar com o valor 20 e iterar no loop preenchendo o vetor no final. Por fim, basta referenciar os recém-criados vetores às propriedades cols > values de cada Picker. Lembre-se de configurar corretamente os seletores na propriedade input referentes aos valores dos campos que o MercadoPago sugeriu, sem alterar tais valores.

Com isso, nossos pickers resultarão em algo semelhante ao que temos na Figura 4.


<script>
   var meses = new Array();
   var anos = new Array();
   for (i = 1; i <= 12; i++) {
          meses.push(i);
   }
   var date = new Date();
   for (i = date.getFullYear(); i < date.getFullYear() + 20; i++) {
          anos.push(i);
   }
   var pickerMeses = myApp.picker({
          input: '#cardExpirationMonth',
          toolbarCloseText: 'Selecione...',
          cols: [
                 {
                       textAlign: 'center',
                       values: meses
                 }
          ]
   });
   var pickerAno = myApp.picker({
          input: '#cardExpirationYear',
          toolbarCloseText: 'Selecione...',
          cols: [
                 {
                       textAlign: 'center',
                       values: anos
                 }
          ]
   });
</script>
Listagem 4. Código JavaScript para carregar pickers de data de vencimento do cartão
Tela de checkout MP com pickers de data de vencimento
Figura 4. Tela de checkout MP com pickers de data de vencimento.

MercadoPago: SDK JavaScript

O próximo passo para trabalhar com a API é efetuar a importação do arquivo JavaScript da mesma. Portanto, na página index.html inclua o seguinte trecho de import após a importação do index.js:


<script src="https://secure.mlstatic.com/sdk/javascript/v1/mercadopago.js">
</script>

Após isso, obviamente, é preciso que você esteja logado na sua conta do MercadoPago, logo, se ainda não criou uma, efetue os passos clicando no botão “Cadastre-se” do topo da página oficial (vide seção Links). Uma vez logado, acesse a página de obtenção das credenciais da sua conta via link disponibilizado na seção Links, tal como vemos na Figura 5. Veja que a mesma apresenta dois modos: o modo sandbox, que usaremos sempre quando estivermos em desenvolvimento da aplicação; e o modo produção, cujas credenciais você usará quando for migrar seu aplicativo para o ambiente de produção. Observe que o próprio MercadoPago disponibiliza um link “O que eu preciso para ir a produção” que você deve ler quando for efetuar tal processo.

Há ainda uma segunda aba na página com as credenciais que você pode usar se estiver usando o modelo de checkout básico que vimos.

Página de credenciais do MercadoPago
Figura 5. Página de credenciais do MercadoPago.

Uma vez com as credenciais em mãos, podemos nos voltar para o código JavaScript de acesso à API. Para isso, vamos criar um novo arquivo na pasta /js do projeto de nome mp.js, que conterá apenas os códigos referentes ao acesso ao MercadoPago. E a primeira linha de código do mesmo será a inicialização da API:


Mercadopago.setPublishableKey("SUA_PUBLIC_KEY_AQUI");

Isso será o suficiente para carregar os objetos e funções importantes da API na nossa página. Nela, temos um outro campo que precisa ter seus valores carregados através do SDK do MercadoPago: trata-se do campo docType. Dependendo do país onde esteja executando o código, o MercadoPago exige que informações referentes à identificação do comprador sejam informadas. No caso do Brasil, o CPF do usuário é solicitado para garantir uma maior segurança. Porém, deixaremos a cargo do próprio MercadoPago a tarefa de nos informar que documento é esse, deixando a lógica adaptada o suficiente para futuras possibilidades em outros países. Portanto, insira mais uma linha de código no arquivo:


Mercadopago.getIdentificationTypes();

Isso é tudo que precisaremos fazer para ter o campo de “Tipo de Documento” carregado na página, isso porque a API do MercadoPago efetua uma consulta via Ajax em seus servidores e retorna a lista compatível com o país de execução do aplicativo, preenchendo automaticamente o campo em questão, desde que o mesmo, obviamente, esteja com o mesmo id que a plataforma sugeriu inicialmente. Veja na Figura 6 um exemplo de como o campo fica quando a página for recarregada.

Campo Tipo do Documento preenchido automaticamente
Figura 6. Campo Tipo do Documento preenchido automaticamente.

Note que o mesmo apresenta o texto sobrescrito ao valor do placeholder e isso é um problema. Uma solução bem simples é criar um elemento <option> vazio dentro do <select> apenas para que o Framework7 entenda que tem conteúdo a ser carregado ali imediatamente após a renderização da página como um todo e o Ajax do MercadoPago, por sua vez, se encarregará de popular o campo corretamente (Figura 7).

Campo Tipo do Documento previamente selecionado
Figura 7. Campo Tipo do Documento previamente selecionado.

Buscando dados da bandeira

O próximo passo é verificar quais são o tipo e a bandeira do cartão que o usuário usará no aplicativo para processar o pagamento, pois precisaremos desses dados para exibir a bandeira do cartão do usuário na página assim que o usuário terminar de digitá-lo, bem como na validação dos dados enviados. Acrescente, portanto, o código da Listagem 5 ao final do arquivo mp.js. Vejamos alguns detalhes sobre as funções da mesma:

  • Função addEvent(): função utilitária que usaremos para adicionar um determinado evento (focus, blur, mousein/out, etc.) enviado por parâmetro a elementos HTML específicos, configurando também uma função de callback para processar o retorno no fim;
  • Função getBin(): essa função se encarrega de recuperar a informação dos seis primeiros dígitos (o suficiente para identificar o tipo do cartão) do número do cartão no respectivo campo, removendo também caracteres especiais, como pontos e hifens, que o usuário venha eventualmente a digitar;
  • Função guessingPayment(): recupera o número do cartão digitado via função getBin() (linha 17) e verifica se o tipo do evento que a disparou foi o keyup. Caso positivo analisa se o tamanho do texto é maior que 6 (isso porque executaremos essa função sempre que o usuário soltar a tecla – onkeyup – e na API do MercadoPago são necessários apenas os 6 primeiros dígitos de um cartão para identificar seu tipo/bandeira) chamando o método de recuperação do pagamento como consequência (getPaymentMethodInfo); caso contrário (evento onchange) executamos a mesma validação porém somente após o tempo de 100 milissegundos, dando uma lacuna suficiente para o usuário terminar de informar o valor (para os casos em que o usuário colar o texto no campo, por exemplo);
  • Função setPaymentMethodInfo(): logo no início da função usamos a função de log() do Console para analisar a resposta (response) que a API nos dará quando digitarmos um cartão de teste no campo. Caso a resposta HTTP retorne com sucesso (Status 200, na linha 38) procedemos da seguinte maneira:

    • o Buscamos o elemento de formulário para inserir um campo escondido referente ao id do método de pagamento. Esse campo deverá ser criado como um elemento do tipo input hidden na própria página via JavaScript com suas propriedades name, type e value devidamente informadas (linhas 49 a 52). Note que essa inclusão deve ocorrer apenas se o mesmo elemento já não existir no formulário, por isso realizamos o teste da linha 48, caso contrário teríamos muitas repetições desse campo no mesmo;
    • o Caso o elemento já exista no formulário, apenas modificamos seu valor pelo possível novo id do tipo de pagamento (linha 56);
    • o Buscamos o elemento de classe CSS bandeira (linha 41) para que possamos modificar o ícone padrão de cartão de crédito com a imagem da bandeira do cartão informado pelo usuário, dando um efeito interessante ao app, além de assegurar ao usuário que nosso sistema identifica suas informações correta e dinamicamente. Após isso, criamos um novo elemento de imagem e definimos seu atributo src apontando para a respectiva URL retornada pelo serviço do MercadoPago, via propriedade thumbnail do objeto de response (linha 44). Assim, basta adicionarmos o mesmo ao objeto de bandeira e a implementação estará finalizada.

Por fim, adicionamos dois novos ouvintes da função de guessingPaymentMethod ao final do código para os eventos de keyup e change, conforme descrevemos antes.


function addEvent(el, eventName, handler) {
 if (el.addEventListener) {
        el.addEventListener(eventName, handler);
 } else {
        el.attachEvent('on' + eventName, function() {
               handler.call(el);
        });
 }
};

function getBin() {
 var ccNumber = document.querySelector('input[data-checkout="cardNumber"]');
 return ccNumber.value.replace(/[ .-]/g, '').slice(0, 6);
};

function guessingPaymentMethod(event) {
 var bin = getBin();

 if (event.type == "keyup") {
        if (bin.length >= 6) {
               Mercadopago.getPaymentMethod({
                     "bin": bin
               }, setPaymentMethodInfo);
        }
 } else {
        setTimeout(function() {
               if (bin.length >= 6) {
                     Mercadopago.getPaymentMethod({
                            "bin": bin
                     }, setPaymentMethodInfo);
               }
        }, 100);
 }
};

function setPaymentMethodInfo(status, response) {
 console.log(JSON.stringify(response));
 if (status == 200) {
        // faça algo ex: mostre a logo do método de pagamento
        var form = document.querySelector('#pay');
        var bandeira = document.querySelector('.bandeira');
        
        var bandeiraImg = document.createElement('img');
        bandeiraImg.setAttribute('src', response[0].thumbnail);

        $(bandeira).html(bandeiraImg);

        if (document.querySelector("input[name=paymentMethodId]") == null) {
               var paymentMethod = document.createElement('input');
               paymentMethod.setAttribute('name', "paymentMethodId");
               paymentMethod.setAttribute('type', "hidden");
               paymentMethod.setAttribute('value', response[0].id);
               
               form.appendChild(paymentMethod);
        } else {
               document.querySelector("input[name=paymentMethodId]")
               .value = response[0].id;
        }
 }
};

addEvent(document.querySelector('input[data-checkout="cardNumber"]'), 
'keyup', guessingPaymentMethod);
addEvent(document.querySelector('input[data-checkout="cardNumber"]'), 
'change', guessingPaymentMethod);
Listagem 5. Identificando método e informações de pagamento

Esse código não trará grandes mudanças à aplicação no momento, exceto pela mudança do ícone da bandeira do cartão que poderemos verificar informando um cartão qualquer no campo referido. O MercadoPago disponibiliza uma página com vários cartões de crédito para testes em sua documentação, desde brasileiros até internacionais, de diversas marcas distintas. Na seção Links você encontra a URL com tais dados de teste. Na mesma página, no link “mais cartões de teste” você encontrará uma listagem de cartões nacionais para testes com marcas como HiperCard, Elo, Diners, bem como marcas exclusivas de outros países, como Naranja (Argentina), Tarjeta MercadoPago (México), etc.

Agora efetue um teste, copie um dos valores disponíveis na página e veja o comportamento do campo, tal como vemos na Figura 8. O leitor pode ainda implementar regras de validação próprias para os dados do cartão, como tamanho mínimo/máximo, tipo de dado digitado ou até mesmo a inclusão de uma máscara no campo para formatar o valor à medida que o usuário o digita.

Exemplo de cartão com identificação automática de bandeira
Figura 8. Exemplo de cartão com identificação automática de bandeira.

Em relação aos dados do cartão estamos apenas fazendo uso dos valores de id (tipo de pagamento) e thumbnail (imagem da bandeira), mas existem outras informações que vêm junto da resposta HTTP ao serviço do MercadoPago. Veja na Listagem 6 o código JSON retornado pelo serviço em função da nossa chamada com os dados do cartão em destaque. Entre as opções mais importantes, destacam-se:

  • name: descrição da bandeira;
  • status: define se o cartão está ativo ou não;
  • secure_thumbnail: URL da imagem da bandeira em ambiente seguro – HTTPS;
  • deferred_capture: suporte a estornos;
  • settings: configurações importantes do cartão, como o número mínimo de dígitos para identificar o bin, o tamanho do número do cartão e as configurações do código de segurança;
  • additional_info_needed: informações sobre os dados necessários para concluir a compra naquele cartão especificamente;
  • min_allowed_ammount, max_allowed_ammount: valores mínimo/máximo permitidos para efetuar operações neste cartão;

[
  {
    "id": "visa",
    "name": "Visa",
    "payment_type_id": "credit_card",
    "status": "active",
    "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/visa.gif",
    "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/visa.gif",
    "deferred_capture": "supported",
    "settings": [
        {
            "bin": {
                "pattern": "^(4)",
                "exclusion_pattern": null,
                "installments_pattern": "^(4)"
            },
            "card_number": {
                "length": 16,
                "validation": "standard"
            },
            "security_code": {
                "mode": "mandatory",
                "length": 3,
                "card_location": "back"
            }
        }
    ],
    "additional_info_needed": [
        "cardholder_name",
        "cardholder_identification_type",
        "cardholder_identification_number"
    ],
    "min_allowed_amount": 0.5,
    "max_allowed_amount": 50000,
    "accreditation_time": 2880
  }
]
Listagem 6. JSON retornado pelo serviço de tipo de pagamento do MercadoPago

Enviando os dados ao MercadoPago

O próximo passo consiste em capturar o evento de submit do nosso formulário, definindo todas as informações de que precisamos para enviar ao nosso Web Service, que é quem de fato irá processar o pagamento no final. Lembre-se de que precisamos enviar ao servidor apenas os dados criptografados retornados pela API JavaScript do MercadoPago no cliente, assim evitamos qualquer falha de segurança no processo como um todo. Portanto, nada de enviar os dados do cartão ou do usuário e muito menos salvá-los em nossa base de dados, ok?

Para isso, faremos uso da função createToken() da classe MercadoPago no JavaScript, tal como definido na Listagem 7. Trata-se de uma função relativamente simples que trata apenas da associação do evento de submit do formulário (de id pay) à função doPay (linha 2) que de fato lidará com o fluxo de pagamento. Essa função, por sua vez, previne o click duplo no botão via função preventDefault() do JavaScript (na linha 5) e, em seguida, chama a função createToken() passando o seletor do formulário e a função de callback que receberá os dados retornados pelo serviço e os tratará: sdkResponseHandler.


doSubmit = false;
addEvent(document.querySelector('#pay'), 'submit', doPay);

function doPay(event) {
   event.preventDefault();
   if (!doSubmit) {
          var $form = document.querySelector('#pay');

          Mercadopago.createToken($form, sdkResponseHandler); 
          // A função "sdkResponseHandler" foi definida abaixo

          return false;
   }
};
Listagem 7. Código para criar token único para cartão do usuário

A Listagem 8 traz o código da função sdkResponseHandler(), que lidará com o processamento da resposta à geração do token de pagamento pela API do MercadoPago. Veja que ela recebe como primeiro parâmetro a variável status, que identifica o status HTTP da resposta à requisição. Mais uma vez testamos se está ok (200 ou 201): em caso positivo, criamos um novo elemento de input hidden definindo como valor o id da resposta (o token em si) e adicionando-o ao formulário; caso contrário enviamos o response para a função tratarErrosTokenCartao() (linha 3), que se encarregará de verificar o que houve de errado e informar ao usuário.

Nesse momento definimos o valor da variável doSubmit para true, isso porque após essa execução não devemos reenviar os dados ao servidor, apenas quando o resultado retornar de lá.

Na linha 15 o leitor pode observar uma função nova: formToJSON(). Trata-se de uma função do Framework7 muito útil que mapeia o formulário enviado como parâmetro e retorna todos os seus campos e respectivos valores organizados no formato JSON. Isso será muito útil para enviarmos os mesmos via função postJSON (Ajax) para o nosso Web Service, sem que precisemos mapear cada um manualmente. Na linha 16 vemos que o valor retornado por essa função para o objeto pagamento foi acrescido da propriedade payer e seu respectivo atributo email, isso para adequar o modelo de dados do nosso cliente-servidor ao do MercadoPago, já que tal valor pertence ao objeto composto payer na sua API. Na linha 22 efetuamos a chamada explicitamente, recebendo como resultado um booleano informando se o processo aconteceu com sucesso.

Veja que, nessa execução toda, temos uma inspeção a fazer (via console.log): o JSON gerado pelo Framework7 com os dados do formulário tal como temos exibido na Listagem 9.


function sdkResponseHandler(status, response) {
 if (status != 200 && status != 201) {
        tratarErrosTokenCartao(response);
 } else {
    var form = document.querySelector('#pay');

    var card = document.createElement('input');
    card.setAttribute('name', "token");
    card.setAttribute('type', "hidden");
    card.setAttribute('value', response.id);
    
    form.appendChild(card);
    doSubmit = true;

    var pagamento = myApp.formToJSON('#pay');
    pagamento.payer = {
           "email": pagamento.email
    };

    console.log(JSON.stringify(pagamento));

    $.postJSON(WS_HOME_WEB + 'rest/mp/pay', pagamento, function(resultado) {
           myApp.alert(resultado ? ‘Pagamento efetuado com sucesso’ : ‘Erro’);
    });
 }
};
Listagem 8. Código que processa a resposta à geração do token de pagamento

  "valor": "23.00",
  "descricao": "teste",
  "email": "julio@gmail.com",
  "paymentMethodId": "visa",
  "token": "91000f1707afb99a2bbbaa8f8d54a5e7",
  "payer": {
      "email": "julio@gmail.com"
  }
}
Listagem 9. JSON criado pelo Framework7 com dados do formulário

Para finalizar a implementação dessa parte cliente, vejamos na Listagem 10 o código de validação dos dados do formulário. Passamos o objeto response para a função que se encarrega de iterar sobre o vetor cause que contém a lista de erros que o serviço do MercadoPago retorna. Cada um dos códigos representa um possível erro que está representado pelas respectivas mensagens de validação dentro da estrutura do switch/case. No final adicionamos a mensagem a uma notificação do Framework7. Os casos em que tivermos dois códigos declarados um após o outro (linhas 14 a 16, por exemplo), são possíveis graças ao recurso de múltiplo case do JavaScript, assim evitamos a repetição de mensagens.


function tratarErrosTokenCartao(response) {
 var msg = "Campos inválidos: <br>";
 $(response.cause).each(function() {
    switch (this.code) {
    case "205":
       msg += "Digite o seu número de cartão!<br>";
       break;
    case "208":
       msg += "Escolha um mês!<br>";
       break;
    case "209":
       msg += "Escolha um ano!<br>";
       break;
    case "212":
    case "213":
    case "214":
       msg += "Insira seu documento!<br>";
       break;
    case "220":
       msg += "Digite o seu banco emissor!<br>";
       break;
    case "221":
       msg += "Insira o nome e sobrenome!<br>";
       break;
    case "224":
       msg += "Digite o código de segurança!<br>";
       break;
    case "316":
       msg += "Insira um nome válido!<br>";
       break;
    case "322":
    case "323":
    case "324":
       msg += "Número de documento inválido!<br>";
       break;
    case "325":
    case "326":
       msg += "Data de vencimento inválida!<br>";
       break;
    case "E301":
       msg += "Há algo errado com este número. Volte a digitá-lo!<br>";
       break;
    case "E302":
       msg += "Código de Segurança inválido!<br>";
       break;
    default:
       // Caso não seja nenhum dos códigos anteriores
       msg += "Favor revisar novamente os dados!<br>";
       break;
    }
 });
 myApp.addNotification({
        message: msg,
        button: {
               text: 'OK'
        }
 });
}
Listagem 10. Função para validar os dados dos campos do formulário

Finalizando o back-end

Voltando nossa atenção agora para o back-end da aplicação, precisamos criar a estrutura no serviço para receber os dados via Ajax. Para isso, a primeira coisa que temos de criar são as classes de entidades que representarão os dados do formulário, entre outras informações. Veja na Listagem 11 o código para criar as duas entidades: Pagamento e Pagador. Note que as mesmas apresentam agora algumas anotações novas: @JsonRootName, que faz parte da API Restful do Jackson e serve para definir o nome raiz do nosso objeto; @JsonProperty mapeia o nome desse elemento a nível de JSON, nos possibilitando dar qualquer outro nome de negócio às variáveis no Java. Cada um desses valores representa já a forma como devemos enviar os dados para o serviço do MercadoPago.


@JsonRootName("payment")
public class Pagamento {

   @JsonProperty("token")
   private String token;

   @JsonProperty("transaction_amount")
   private BigDecimal valor;

   @JsonProperty("payment_method_id")
   private String paymentMethodId;

   @JsonProperty("description")
   private String descricao;

@JsonProperty("installments")
private int parcelas;

   @JsonProperty("payer")
   private Pagador payer;
   
   // getters e setters
   
}

@XmlRootElement
public class Pagador {

   private String email;
   
   // getters e setters
   
}
Listagem 11. Classes de entidade Pagamento e Pagador

Após isso, crie uma nova classe de nome MercadoPagoService no pacote de serviços e adicione o código da Listagem 12. Veja que ela apenas simula o recebimento dos dados vindos do cliente JavaScript, pois precisamos antes testar o seu funcionamento. Para transformar o objeto de Pagamento recebido por parâmetro em JSON fazemos uso da classe ObjectMapper (classe que encapsula os objetos JSON e os converte de String para objeto Java e vice-versa) que retorna um ObjectWriter (classe que escreve os valores em JSON após as conversões). No final imprimimos o valor no Console para analisar se tudo veio corretamente.


@Path("mp")
public class MercadoPagoService {

  @POST
  @Consumes(MediaType.APPLICATION_JSON + ";charset=utf-8")
  @Produces(MediaType.TEXT_PLAIN)
  @Path("/pay")
  public boolean gerarPagamento(Pagamento pagamento) {
    try {
           ObjectWriter ow = new ObjectMapper().writer()
           .withDefaultPrettyPrinter();
           String json = ow.writeValueAsString(pagamento);
           System.out.println(json);
           
           return true;
    } catch (Exception e) {
           e.printStackTrace();
           return false;
    }
  }
}
Listagem 12. Classe de serviço para o MercadoPago

Agora com o método de serviço pronto, podemos focar na API do MercadoPago para Java. O primeiro passo é adicionar as dependências no pom.xml, logo abra o arquivo e adicione as instruções exibidas na Listagem 13. A primeira instrução diz ao Maven para considerar o repositório informado na tag <url> como um local válido a se buscar libs, isso porque, por padrão, o Maven busca bibliotecas apenas no seu repositório oficial; caso precisemos referenciar libs hospedadas em outros sites (como o GitHub no caso do MercadoPago) é necessário informar a URL dos mesmos na referida tag. A segunda representa a instrução de download das libs do MercadoPago em si.


// Adicione após a tag <packaging>
  <repositories>
         <repository>
               <id>mercadopago</id>
               <url>https://github.com/mercadopago/sdk-java/raw/master/releases</url>
         </repository>
  </repositories>
   
  // Adicione dentro da tag <dependencies>
  <dependency>
         <groupId>com.mercadopago</groupId>
         <artifactId>sdk</artifactId>
         <version>0.3.4</version>
  </dependency>
Listagem 13. Instruções para adicionar as libs do MercadoPago no projeto Java

Agora, nosso código pode evoluir para o demonstrado na Listagem 14. Observe que na linha 11 instanciamos um objeto MP e passamos para ele o valor do nosso token de acesso. Esse mesmo valor está na página de credenciais da sua aplicação no site de desenvolvedores. Após isso, o resto é muito simples: basta chamar o método post() da API passando a URL que se deseja processar (no caso um pagamento) e o JSON já formatado. Para checar se o pagamento ocorreu com sucesso, basta verificar se o código do status veio como 200 ou 201.


@POST
@Consumes(MediaType.APPLICATION_JSON + ";charset=utf-8")
@Produces(MediaType.TEXT_PLAIN)
@Path("/pay")
public boolean gerarPagamento(Pagamento pagamento) {
   boolean retorno = false;
   try {
      ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
      String jsonPagamento = ow.writeValueAsString(pagamento);

      MP mp = new MP("SEU_ACCESS_TOKEN_AQUI");

      JSONObject payment = mp.post("/v1/payments", jsonPagamento);
      
      if (payment.getInt("status") == 200 || payment.getInt("status") == 201) {
             retorno = true;
      }
   } catch (Exception e) {
      e.printStackTrace();
   }
   return retorno;
}
Listagem 14. Código da função com chamada ao serviço do MercadoPago

Para efetuar pagamentos parcelados, basta setar o atributo parcelas do objeto Pagamento com o valor selecionado pelo usuário no picker de parcelamento que criamos antes, isso será o suficiente para que o MercadoPago aplique as taxas de custeio em cima do valor total e credite tais dados do usuário final.

A API do MercadoPago apresenta muitas outras opções para otimizar o seu desenvolvimento, portanto não esqueça de sempre ler atentamente a documentação oficial dessas plataformas. Você pode implementar recursos como o salvamento e recuperação automática dos cartões do seu cliente, via API do MercadoPago para evitar ter de salvar tais dados no seu próprio aplicativo, assim como comunicar os recebimentos por e-mail, bem como gerenciar seus ganhos via painel do Sandbox. Mas lembre-se: é importante checar antes no site da companhia os custos de cada operação que a empresa certamente te cobrará, cada uma tem suas próprias taxas. Bons estudos!