Pagos con tarjeta

Cargo con tarjeta tokenizada

A todos nos gusta recibir pagos, es por ello empezaremos con un guía para ver la forma de hacerlo.

Esta guía hace uso de la librería de Openpay.js, para enviar la información de la tarjeta directamente a Openpay. Usando esta librería aparte de ser la forma más sencilla de guardar una tarjeta permite minimizar el alcance de una certificación PCI Compliance.

Flujo para realizar cargos a tarjeta

Flujo para realizar cargos a tarjeta

Pasos:

  1. Implementación del sistema antifraude generando un “device_session_id”
  2. Tokenización de la tarjeta de crédito o débito usando la librería Openpay.js
  3. Toda la información de la compra se envía a tu servidor
  4. Desde tu servidor se crea el cargo en Openpay
  5. Openpay envía la instrucción de cargo al banco emisor y regresa la respuesta

Creación del formulario

Para pedirle al usuario la información de la tarjeta y poder realizar los pasos 1 y 2 es necesario tener un formulario indicándole al cliente las tarjetas soportadas y que el pago será vía Openpay.

Ejemplo de cobro con tarjeta

Código del formulario.

Nota: El HTML completo del formulario lo puedes descargar aquí

<form action="#" method="POST" id="payment-form">
    <input type="hidden" name="token_id" id="token_id">
    <input type="hidden" name="use_card_points" id="use_card_points" value="false">
    <div class="pymnt-itm card active">
        <h2>Tarjeta de crédito o débito</h2>
        <div class="pymnt-cntnt">
            <div class="card-expl">
                <div class="credit"><h4>Tarjetas de crédito</h4></div>
                <div class="debit"><h4>Tarjetas de débito</h4></div>
            </div>
            <div class="sctn-row">
                <div class="sctn-col l">
                    <label>Nombre del titular</label><input type="text" placeholder="Como aparece en la tarjeta" autocomplete="off" data-openpay-card="holder_name">
                </div>
                <div class="sctn-col">
                    <label>Número de tarjeta</label><input type="text" autocomplete="off" data-openpay-card="card_number"></div>
                </div>
                <div class="sctn-row">
                    <div class="sctn-col l">
                        <label>Fecha de expiración</label>
                        <div class="sctn-col half l"><input type="text" placeholder="Mes" data-openpay-card="expiration_month"></div>
                        <div class="sctn-col half l"><input type="text" placeholder="Año" data-openpay-card="expiration_year"></div>
                    </div>
                    <div class="sctn-col cvv"><label>Código de seguridad</label>
                        <div class="sctn-col half l"><input type="text" placeholder="3 dígitos" autocomplete="off" data-openpay-card="cvv2"></div>
                    </div>
                </div>
                <div class="openpay"><div class="logo">Transacciones realizadas vía:</div>
                <div class="shield">Tus pagos se realizan de forma segura con encriptación de 256 bits</div>
            </div>
            <div class="sctn-row">
                    <a class="button rght" id="pay-button">Pagar</a>
            </div>
        </div>
    </div>
</form>

Es muy importante que los campos en donde se va a introducir la información de la tarjeta tenga el atributo data_openpay_card ​ya que esto permitirá a la librería de Openpay encontrar la información.

Observa que para los datos de la tarjeta no se está ocupando el atributo name esto para que al momento de enviar el formulario a tu servidor los datos de la tarjeta no viajen en la petición ya que sólo los vamos a ocupar para crear el token.

En el formulario de ejemplo anterior no se incluyen los campos “amount” y “description” pero deberan incluirse al hacer el submit al servidor.

Sistema antifraude (Paso 1)

Con el siguiente código se cargan las librerías necesarios para la generación del id de dispositivo:

<head>
  <script type="text/javascript"
        src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  <script type="text/javascript"
        src="https://js.openpay.mx/openpay.v1.min.js"></script>
<script type='text/javascript'
  src="https://js.openpay.mx/openpay-data.v1.min.js"></script>
</head>

Con el siguiente código se inicializa el valor para el device_session_id:

<script type="text/javascript">
 $(document).ready(function() {
  OpenPay.setId('mzdtln0bmtms6o3kck8f');
  OpenPay.setApiKey('pk_f0660ad5a39f4912872e24a7a660370c');
  var deviceSessionId = OpenPay.deviceData.setup("payment-form", "deviceIdHiddenFieldName");
  });
</script>

El parámetro payment-form, recibe el id del formulario que contiene la información del cargo que se enviara a tu servidor. Indica a la librería que en ese formulario es donde se va a agregar un campo oculto con el valor del device_session_id.

El parámetro deviceIdHiddenFieldName, recibe el nombre del campo oculto donde se asignara el device_session_id. Este dato es importante si piensas recuperar el valor del hidden y enviar mediante un submit.

Tokenización y envío de datos (Paso 2 y 3)

Una vez que tenemos nuestro formulario creado, vamos a programar que en el botón de enviar se cree un token utilizando la librería Openpay.js.

Primero agregamos al head el archivo de Openpay.js y de JQuery:

<head>
  <script type="text/javascript"
        src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  <script type="text/javascript"
        src="https://js.openpay.mx/openpay.v1.min.js"></script>
</head>

​Luego asignamos a la librería de Openpay nuestro merchant-id y nuestra llave pública (public-key):

<script type="text/javascript">
     $(document).ready(function() {
            OpenPay.setId('mzdtln0bmtms6o3kck8f');
            OpenPay.setApiKey('pk_f0660ad5a39f4912872e24a7a660370c');
            OpenPay.setSandboxMode(true);
    });
</script>

Y por último atrapamos el evento de clic del botón “Pagar” para que en lugar de que haga el submit del formulario realice la función “tokenize” de la tarjeta:

$('#pay-button').on('click', function(event) {
       event.preventDefault();
       $("#pay-button").prop( "disabled", true);
       OpenPay.token.extractFormAndCreate('payment-form', success_callbak, error_callbak);              
});

Como puedes ver estamos pasando como parámetro el nombre del formulario creado, esto para que la librería obtengan los datos de la tarjeta y haga la petición a Openpay.

Si todo sale bien se llamará el método success_callback en el cual asignaremos el valor id del token creado al campo token_id y enviaremos los datos al servidor:

var success_callbak = function(response) {
              var token_id = response.data.id;
              $('#token_id').val(token_id);
              $('#payment-form').submit();
};

Si existe un problema en la llamada mostramos el error en un alert:

var error_callbak = function(response) {
     var desc = response.data.description != undefined ?
        response.data.description : response.message;
     alert("ERROR [" + response.status + "] " + desc);
     $("#pay-button").prop("disabled", false);
};

Para mayor referencia del uso de la librería consulta la página de Openpay.js

Uso de puntos de tarjeta (Opcional)

Opcionalmente, podemos aceptar pagos mediante puntos, si la tarjeta lo acepta.

Para esto crearemos un cuadro de diálogo, con el cual el usuario podrá aceptar pagar con puntos. En este caso, utilizaremos un cuadro de diálogo usando la librería de Bootstrap:

<div class="modal fade" role="dialog" id="card-points-dialog">
  <div class="modal-dialog modal-sm">
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title">Pagar con Puntos</h4>
      </div>
      <div class="modal-body">
        <p>¿Desea usar los puntos de su tarjeta para realizar este pago?</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal" id="points-no-button">No</button>
        <button type="button" class="btn btn-primary" data-dismiss="modal" id="points-yes-button">Si</button>
      </div>
    </div>
  </div>
</div>

Ya con el código HTML del cuadro de diálogo, modificaremos la función success_callback que definimos previamente, para mostrar el diálogo si detectamos que la tarjeta permite el uso de puntos:

var success_callbak = function(response) {
              var token_id = response.data.id;
              $('#token_id').val(token_id);
              if (response.data.card.points_card) {
                  // Si la tarjeta permite usar puntos, mostrar el cuadro de diálogo
                  $("#card-points-dialog").modal("show");
              } else {
                  // De otra forma, realizar el pago inmediatamente
                  $('#payment-form').submit();
              }
};

Ahora utilizaremos los eventos de los botones de este diálogo para cambiar el valor del campo oculto use_card_points del formulario, y después solicitar el pago en el servidor:

$("#points-yes-button").on('click', function(){
              $('#use_card_points').val('true');
              $('#payment-form').submit();
});
$("#points-no-button").on('click', function(){
        $('#use_card_points').val('false');
        $('#payment-form').submit();
        });

Notas:

  • Si el cargo se realiza con puntos, es posible que la respuesta regrese un mensaje para el cliente. En ese caso, es requerido mostrárselo en su ticket de compra. Ver la definición de API para más detalles.

Crear cargo (Paso 4 y 5)

Ahora sólo resta hacer el cargo desde tu servidor, para esto crearemos una instancia de Openpay con el merchant-id y el private-key y luego con los valores del formulario haremos el cargo:


$openpay = Openpay::getInstance('mzdtln0bmtms6o3kck8f',
  'sk_e568c42a6c384b7ab02cd47d2e407cab');

$customer = array(
     'name' => $_POST["name"],
     'last_name' => $_POST["last_name"],
     'phone_number' => $_POST["phone_number"],
     'email' => $_POST["email"],);

$chargeData = array(
    'method' => 'card',
    'source_id' => $_POST["token_id"],
    'amount' => $_POST["amount"], // formato númerico con hasta dos dígitos decimales. 
    'description' => $_POST["description"],
    'use_card_points' => $_POST["use_card_points"], // Opcional, si estamos usando puntos
    'device_session_id' => $_POST["deviceIdHiddenFieldName"],
    'customer' => $customer
    );

$charge = $openpay->charges->create($chargeData);

$openpay = Openpay::getInstance('mzdtln0bmtms6o3kck8f',
  'sk_e568c42a6c384b7ab02cd47d2e407cab');

$customer = array(
     'name' => $_POST["name"],
     'last_name' => $_POST["last_name"],
     'phone_number' => $_POST["phone_number"],
     'email' => $_POST["email"],);

$chargeData = array(
    'method' => 'card',
    'source_id' => $_POST["token_id"],
    'amount' => $_POST["amount"], // formato númerico con hasta dos dígitos decimales. 
    'description' => $_POST["description"],
    'use_card_points' => $_POST["use_card_points"], // Opcional, si estamos usando puntos
    'device_session_id' => $_POST["deviceIdHiddenFieldName"],
    'customer' => $customer
    );

$charge = $openpay->charges->create($chargeData);

¡¡Listo!! Ya tenemos un cargo creado con tarjeta.

Si existiera un error recibiriamos una excepción la cual debemos capturar y manejar, para mas información consulta la seccion de errores


Notas:

  • Los campos amount, description, etc.. que no están en el formulario de ejemplo, son datos propios de tu aplicación que deben haberse obtenido antes del formulario de pago.
  • En el campo amount, puede ser utilizado un String con formato punto decimal.
  • Si deseas ver como realizar el procedimiento en otro lenguaje consulta nuestra sección de integración.
  • El código HTML completo se encuentra aquí. (La página no funciona completamente, deberás descargarla y realizar la implementación del POST en tu servidor).
  • Asegúrate que tu integración cumple con los requisitos de compatibilidad de versiones más detalles
  • Puedes simular diferentes resultados usando las tarjetas de Pruebas
  • Implementa las Notificaciones para conocer el estado de los pagos en tiempo real