Integración BankStore JET-IFRAME
El sistema JET-IFRAME de PAYCOMET permite integrar de manera sencilla y segura la pasarela de pagos mantiendo tus formularios de pago.
Gracias a sus sistemas de iframes los datos sensibles nunca pasan por el sistema del cliente. La integración de este sistema no requiere añadir medidas de seguridad complementarias.
Introducción
La integración JET-IFRAME forma parte de la solución de captura de datos de tarjeta y realiza las tokenizaciones previas a poder ejecutar operaciones de cobro. Es independiente del interfaz de usuario y especialmente recomendada para integraciones para dispositivos móviles.
¡Recuerda!
El entorno sólo trabajará sobre protocolo seguro SSL.
¿Cómo funciona?
Mediante javascript se cargan dos iframes dentro del formulario como campos para recoger los valores de la PAN y el CVV, y se les aplican los estilos y placeholder definidos en dichos DIV. Cuando el formulario se envía, JET-IFRAME inicia un proceso en el que los iframes recogen y mandan la información necesaria a PAYCOMET para que devuelva un token temporal y se inserte en el formulario original del cliente en un campo oculto. Una vez finalizado este proceso el envío del formulario continúa de manera habitual. El cliente recibirá en su servidor a través del post de su formulario los campos del mismo, excepto la PAN y el CVC2, que nunca serán accesibles. Además el cliente recibirá la variable "paytpvToken", necesaria junto con otros parámentros que veremos más adelante para comenzar a operar.
¡Recuerda!
Esta integración no es compatible con Internet Explorer 11, ni versiones anteriores.
Configuración de producto
Para poder utilizar el servicio BankStore JET-IFRAME en tu comercio deberás estar en posesión de los parámetros de configuración necesarios. Éstos pueden obtenerse a través del panel de control de cliente (nueva versión)
Una vez dentro de la plataforma, puedes revisar la configuración del producto mediante el menú Terminales->"Nombre de terminal"->Datos de terminal.
Tras acceder, encontraras el JET ID en la sección "Credenciales de integración".
Si tu JET ID aún no ha sido generado, puedes hacer click en el enlace Generar JET ID dentro de tu panel de control.
En ese momento se generará tu JET ID. Con este identificador podrás realizar las llamadas que explicamos en los siguientes apartados.
Integración
Instrucciones para la integración
Todos estos campos son obligatorios: cardHolderName, dateMonth, dateYear. Debe mantenerse el atributo data-paycomet con sus correspondientes valores. No deberá aparece el atributo name en estos campos
<input type="text" data-paycomet="cardHolderName"/> <input type="text" data-paycomet="dateMonth"/> <input type="text" data-paycomet="dateYear"/>
En el lugar del formulario donde se introducirán la tarjeta y el código CVC2 debe haber sendos DIV sobre el INPUT.
<div id="paycomet-pan" data-paycomet="paNumber" style="estilo para número de tarjeta"></div> <input type="text" id="old-pan-input"/> <div id="paycomet-cvc2" data-paycomet="cvc2" style="estilo para codigo CVC2"></div> <input type="text" id="old-CVC2-input"/>
Los div con id "paycomet-pan" y "paycomet-cvc2" son obligatorios.
Los id indicados de los div "paycomet-pan" y "paycomet-cvc2" deben mantenerse.
El estilo que se defina in-line en los div será el que tengan los input. Dicho de otra manera, para definir los estilos de estos campos se debe poner en el atributo style de cada DIV. Sólo se tomarán los estilos in-line, el resto serán ignorados.
Por defecto el campo de la PAN tiene una máscara que muestra el tipo de tarjeta en un icono a la izquierda, dentro del INPUT y un TICK al final que indica si el formato es correcto. Si no se desea incorporar este diseño sólo hay que introducir un campo hidden en el formulario de la siguiente manera:
<input type="hidden" data-paycomet="no-mask" value="">
De incluirse como parámetro oculto el jetID del cliente de la siguiente manera:
<input type="hidden" data-paycomet="jetID" value="[customer-jetID]"></input>
Debe incluirse "https://api.paycomet.com/gateway/paycomet.jetiframe.js" al final del documento
<script src="https://api.paycomet.com/gateway/paycomet.jetiframe.js"></script>
Esta integración debe estar aislada de cualquier otro javascript, por tanto no deben incluirse scripts que interactuen con el formulario de pago.
Formulario de pago
A continuacion un ejemplo de como adaptar tu formulario de pago para poder utilizar la solución JET-IFRAME.
Formulario del comercio antes de la integración:
<div class="container"> <div class="row"> <aside class="col-sm-6"> <article class="card"> <div class="card-body p-5"> <p> <img src="http://bootstrap-ecommerce.com/main/images/icons/pay-visa.png"> <img src="http://bootstrap-ecommerce.com/main/images/icons/pay-mastercard.png"> <img src="http://bootstrap-ecommerce.com/main/images/icons/pay-american-ex.png"> </p> <p class="alert alert-success">Some text success or error</p> <form role="form" action="index.php"> <input type="hidden" name="amount" value="1234"> <div class="form-group"> <label for="username">Full name (on the card)</label> <div class="input-group"> <div class="input-group-prepend"> <span class="input-group-text"><i class="fa fa-user"></i></span> </div> <input type="text" class="form-control" name="username" placeholder="" required=""> </div> <!-- input-group.// --> </div> <!-- form-group.// --> <div class="form-group"> <label for="cardNumber">Card number</label> <div class="input-group"> <div class="input-group-prepend"> <span class="input-group-text"><i class="fa fa-credit-card"></i></span> </div> <input type="text" class="form-control" name="cardNumber" placeholder=""> </div> <!-- input-group.// --> </div> <!-- form-group.// --> <div class="row"> <div class="col-sm-8"> <div class="form-group"> <label><span class="hidden-xs">Expiration</span> </label> <div class="form-inline"> <select class="form-control" style="width:45%" data-paycomet="dateMonth"> <option>MM</option> <option value="01">01 - January</option> <option value="02">02 - February</option> <option value="03">03 - March</option> <option value="04">04 - April</option> <option value="05">05 - May</option> <option value="06">06 - June</option> <option value="07">07 - July</option> <option value="08">08 - August</option> <option value="09">09 - September</option> <option value="10">10 - October</option> <option value="11">11 - November</option> <option value="12">12 - December</option> </select> <span style="width:10%; text-align: center"> / </span> <select class="form-control" style="width:45%" data-paycomet="dateYear"> <option>YY</option> <option value="20">2020</option> <option value="21">2021</option> <option value="22">2022</option> <option value="23">2023</option> <option value="24">2024</option> <option value="25">2025</option> <option value="26">2026</option> <option value="27">2027</option> <option value="28">2028</option> <option value="29">2029</option> <option value="30">2030</option> </select> </div> </div> </div> <div class="col-sm-4"> <div class="form-group"> <label data-toggle="tooltip" title="" data-original-title="3 digits code on back side of the card">CVV <i class="fa fa-question-circle"></i></label> <input class="form-control" required="" type="text"> </div> <!-- form-group.// --> </div> </div> <!-- row.// --> <button class="subscribe btn btn-primary btn-block" type="button"> Confirm </button> </form> </div> <!-- card-body.// --> </article> <!-- card.// --> </aside> </div> </div>
Formulario del comercio tras la integración:
<div class="container"> <div class="row"> <aside class="col-sm-6"> <article class="card"> <div class="card-body p-5"> <p> <img src="http://bootstrap-ecommerce.com/main/images/icons/pay-visa.png"> <img src="http://bootstrap-ecommerce.com/main/images/icons/pay-mastercard.png"> <img src="http://bootstrap-ecommerce.com/main/images/icons/pay-american-ex.png"> </p> <p class="alert alert-success">Some text success or error</p> <form role="form" id="paycometPaymentForm" action="index.php" method="POST"> <input type="hidden" name="amount" value="1234"> <input type="hidden" data-paycomet="jetID" value="[customer-jetID]"> <div class="form-group"> <label for="username">Full name (on the card)</label> <div class="input-group"> <div class="input-group-prepend"> <span class="input-group-text"><i class="fa fa-user"></i></span> </div> <input type="text" class="form-control" name="username" data-paycomet="cardHolderName" placeholder="" required=""> </div> <!-- input-group.// --> </div> <!-- form-group.// --> <div class="form-group"> <label for="cardNumber">Card number</label> <div class="input-group"> <div class="input-group-prepend"> <span class="input-group-text"><i class="fa fa-credit-card"></i></span> </div> <div id="paycomet-pan" style="padding:0px; height:36px;"></div> <input paycomet-style="width: 100%; height: 21px; font-size:14px; padding-left:7px; padding-top:8px; border:0px;" paycomet-name="pan" paycomet-placeholder="Introduce tu tarjeta..."> </div> <!-- input-group.// --> </div> <!-- form-group.// --> <div class="row"> <div class="col-sm-8"> <div class="form-group"> <label><span class="hidden-xs">Expiration</span> </label> <div class="form-inline"> <select class="form-control" style="width:45%" data-paycomet="dateMonth"> <option>MM</option> <option value="01">01 - January</option> <option value="02">02 - February</option> <option value="03">03 - March</option> <option value="04">04 - April</option> <option value="05">05 - May</option> <option value="06">06 - June</option> <option value="07">07 - July</option> <option value="08">08 - August</option> <option value="09">09 - September</option> <option value="10">10 - October</option> <option value="11">11 - November</option> <option value="12">12 - December</option> </select> <span style="width:10%; text-align: center"> / </span> <select class="form-control" style="width:45%" data-paycomet="dateYear"> <option>YY</option> <option value="20">2020</option> <option value="21">2021</option> <option value="22">2022</option> <option value="23">2023</option> <option value="24">2024</option> <option value="25">2025</option> <option value="26">2026</option> <option value="27">2027</option> <option value="28">2028</option> <option value="29">2029</option> <option value="30">2030</option> </select> </div> </div> </div> <div class="col-sm-4"> <div class="form-group"> <label data-toggle="tooltip" title="" data-original-title="3 digits code on back side of the card">CVV <i class="fa fa-question-circle"></i></label> <div id="paycomet-cvc2" style="height: 36px; padding:0px;"></div> <input paycomet-name="cvc2" paycomet-style="border:0px; width: 100%; height: 21px; font-size:12px; padding-left:7px; padding-tap:8px;" paycomet-placeholder="CVV2" class="form-control" required="" type="text"> </div> <!-- form-group.// --> </div> </div> <!-- row.// --> <button class="subscribe btn btn-primary btn-block" type="submit"> Confirm </button> </form> <div id="paymentErrorMsg"> </div> </div> <!-- card-body.// --> </article> <!-- card.// --> </aside> </div> </div> <script src="https://api.paycomet.com/gateway/paycomet.jetiframe.js?lang=es"></script>
¿Qué ha cambiado?
- El method ha de ser
POST
- Se incluye el campo oculto
<input type="hidden" data-paycomet="jetID" value="[customer-jetID]">
- El campo del nombre del titular de la tarjeta pasa tener el atributo:
data-paycomet="cardHoldername"
- Sobre el campo de la pan se incluye un div con
con el tamaño inline donde se ubicará el iframe.id="paycomet-pan"
<div id="paycomet-pan" style="width:433px; height:29px;"></div>
- En el input de la PAN se añade un atributo para establecer el estilo del futuro INPUT:
paycomet-style="width:419px; height:21px; font-size:12px; padding-left:7px;"
- En el input de la PAN se añade un atributo placeholder para establecer el placeholder del futuro INPUT:
paycomet-placeholder="Introduce tu tarjeta..."
- En el input de la PAN se añade un atributo:
paycomet-name="pan"
- En el input de la PAN se borran el resto de atributos que no sean los dos anteriores.
- En los selectores de mes y año se añaden sendos atributos:
ydata-paycomet="dateMonth"
data-paycomet="dateYear"
- En los selectores de mes y año se ajustan los valores para que tengan el formato aceptado por paycomet: mm y yy
- Sobre el campo del cvc2 se incluye un div con
con el tamaño inline donde se ubicará el iframe.id="paycomet-cvc2"
<div id="paycomet-cvc2" style="width: 134px; height: 29px;"></div>
- En el input del cvc2 se añade un atributo con los estilos que tendrá ese campo:
paycomet-style="width: 120px; height: 21px; font-size:12px; padding-left:7px;"
- En el input del cvc2 se añade un atributo con el placeholder que tendrá ese campo:
paycomet-placeholder="CVV2"
- En el input del cvc2 se añade un atributo:
paycomet-name="cvc2"
- En el input del cvc2 se borran el resto de atributos que no sean los dos anteriores.
- Se añade un nuevo div para alojar los mensajes de error. el usuario puede añadir estilos libremente en css o inline para el contenido de este div :
<div id="paymentErrorMsg"></div>
- Se añade el script que hará funcionar todo el sistema
. Se puede pasar el parámetro "lang" con el idioma en el que se deseen las notificaciones.<script src="https://api.paycomet.com/gateway/paycomet.jetiframe.js?lang=es"></script>
Devolución de la llamada
Tras el envio del formulario, la llamada a la función de callback o el action definido en el formulario, recibirá el token temporal con el que debe realizar una llamada a:
- Si usas una integración XML se debe usar add_user_token.
- Si usas una integración REST hay que hacer una llamada a /v1/cards indicando sólo el terminal y jetToken.
En el siguiente ejemplo podemos ver como utilizar este token temporal en php para crear uno permanente y poder comenzar a operar con el usuario
Ejemplos de uso
A continuación mostraremos un ejemplo funcional de código donde se recibe el action del formulario anterior donde se realizan las operaciones básicas para realizar un pago (con la integración XML).
En este caso, tras añadir dinámicamente el token al formulario, lo hemos recibido como la variable paytpvToken. Con este token (recordemos que sólo es válido durante cinco minutos) podremos crear la firma necesaria para utilizar la API SOAP que proporciona PAYCOMET. Con el cliente SOAP ya creado, podremos realizar una seria de operaciones. Lo primero será registrar al usuario y si es la primera vez que usa la plataforma se guardará para futuras compras.
Al invocar a "add_user_token" nos devolverá un token que servirá para indicar a PAYCOMET futuras operaciones sobre el mismo sin necesidad de que vuelva a introducir la tarjeta ni de que el vendendor almacene dato alguno del ciente. El token puede ser guardado y relacionado con cualquier identificador de usuario que tenga el sistema del vendendor (cookies, usuarios registrados...) sin incurrir en prácticas no seguras.
Una vez registrado el usuario podemos proceder a realizar la operación de cobro (o cualquiera de todas las previstas en la API de PAYCOMET). Es recomendable conocer y utilizar la API en PHP de PAYCOMET como se muestra en el siguiente ejemplo:
Con integración XML:
<?php
/**
* PAYCOMET JET IFRAME callback
* Tracking ID: SSX-7MS-JX3J
*
* @author PAYCOMET
* @copyright Copyright (c) 2019, PAYCOMET
* @version 1.1 2019-11-07
*/
$jetID = "** yourJETID";
$merchantCode = "** yourmerchantcode";
$terminal = "** terminalnumber";
$password = "** yourpassword";
if (isset($_POST["paytpvToken"])) {
date_default_timezone_set("Europe/Madrid");
$token = $_POST["paytpvToken"];
if ($token && strlen($token) == 64) {
$endPoint = "https://api.paycomet.com/gateway/xml-bankstore?wsdl";
$productDescription = "XML_BANKSTORE TEST productDescription";
$owner = "XML_BANKSTORE TEST owner";
$signature
= hash("sha512",
$merchantCode
.$token
.$jetID
.$terminal
.$password
);
$ip = $_SERVER["REMOTE_ADDR"];
try {
$context = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
));
$clientSOAP = new SoapClient($endPoint, array('stream_context' => $context));
$addUserTokenResponse
= $clientSOAP->add_user_token(
$merchantCode,
$terminal,
$token,
$jetID,
$signature,
$ip
);
if ($addUserTokenResponse["DS_ERROR_ID"] == "0") {
// OK
echo " Proceso correcto. Se ha obtenido el token";
var_dump($addUserTokenResponse);
$order = "MERCHANTORDER-" . date("Y/m/d h:I:s");
$signature
= hash("sha512",
$merchantCode
.$addUserTokenResponse["DS_IDUSER"]
.$addUserTokenResponse["DS_TOKEN_USER"]
.$terminal
.$_POST["amount"]
.$order
.$password
);
$productDescription = "XML_BANKSTORE TEST productDescription";
$owner = "XML_BANKSTORE TEST owner";
$executePurchaseResponse
= $clientSOAP->execute_purchase(
$merchantCode,
$terminal,
$addUserTokenResponse["DS_IDUSER"],
$addUserTokenResponse["DS_TOKEN_USER"],
$_POST["amount"],
$order,
"EUR",
$signature,
$ip,
$productDescription,
$owner
);
if ($executePurchaseResponse["DS_RESPONSE"] == "1") {
// OK
var_dump("COMPRA CORRECTA
");
return true;
} else {
//KO
var_dump("Error al obtener el ejecutar la compra");
var_dump($executePurchaseResponse["DS_ERROR_ID"]);
return false;
}
var_dump($executePurchaseResponse);
} else {
var_dump("Error al obtener el token");
var_dump($addUserTokenResponse["DS_ERROR_ID"]);
return false;
}
} catch(SoapFault $e){
var_dump($e);
}
} else {
var_dump("Error, no se ha obtenido token");
return false;
}
return false;
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
</head>
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/all.css">
<div class="container">
<div class="row">
<aside class="col-sm-6">
<p><h1>JET-IFRAME </h1> </p>
<article class="card">
<div class="card-body p-5">
<p>
<h3> Datos de prueba </h3>
Tarjeta : 4539 2320 7664 8253 <br/>
CVC: 123 <br/>
Caducidad: 05 / 25 <br/>
</p>
<p class="alert alert-success">Some text success or error</p>
<form role="form" id="paycometPaymentForm" method="POST">
<input type="hidden" name="amount" value="1234">
<input type="hidden" data-paycomet="jetID" value="<?php echo $jetID; ?>">
<div class="form-group">
<label for="username">Full name (on the card)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-user"></i></span>
</div>
<input type="text" class="form-control" name="username" data-paycomet="cardHolderName" placeholder="" required="">
</div> <!-- input-group.// -->
</div> <!-- form-group.// -->
<div class="form-group">
<label for="cardNumber">Card number</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-credit-card"></i></span>
</div>
<div id="paycomet-pan" style="padding:0px; height:36px;"></div>
<input paycomet-style="width: 100%; height: 21px; font-size:14px; padding-left:7px; padding-top:8px; border:0px;" paycomet-name="pan">
</div> <!-- input-group.// -->
</div> <!-- form-group.// -->
<div class="row">
<div class="col-sm-8">
<div class="form-group">
<label><span class="hidden-xs">Expiration</span> </label>
<div class="form-inline">
<select class="form-control" style="width:45%" data-paycomet="dateMonth">
<option>MM</option>
<option value="01">01 - January</option>
<option value="02">02 - February</option>
<option value="03">03 - March</option>
<option value="04">04 - April</option>
<option value="05">05 - May</option>
<option value="06">06 - June</option>
<option value="07">07 - July</option>
<option value="08">08 - August</option>
<option value="09">09 - September</option>
<option value="10">10 - October</option>
<option value="11">11 - November</option>
<option value="12">12 - December</option>
</select>
<span style="width:10%; text-align: center"> / </span>
<select class="form-control" style="width:45%" data-paycomet="dateYear">
<option>YY</option>
<option value="20">2020</option>
<option value="21">2021</option>
<option value="22">2022</option>
<option value="23">2023</option>
<option value="24">2024</option>
<option value="25">2025</option>
<option value="26">2026</option>
<option value="27">2027</option>
<option value="28">2028</option>
<option value="29">2029</option>
<option value="30">2030</option>
</select>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="form-group">
<label data-toggle="tooltip" title=""
data-original-title="3 digits code on back side of the card">CVV <i
class="fa fa-question-circle"></i></label>
<div id="paycomet-cvc2" style="height: 36px; padding:0px;"></div>
<input paycomet-name="cvc2" paycomet-style="border:0px; width: 100%; height: 21px; font-size:12px; padding-left:7px; padding-tap:8px;" class="form-control" required="" type="text">
</div> <!-- form-group.// -->
</div>
</div> <!-- row.// -->
<button class="subscribe btn btn-primary btn-block" type="submit"> Confirm </button>
</form>
<div id="paymentErrorMsg">
</div>
</div> <!-- card-body.// -->
</article> <!-- card.// -->
</aside>
</div>
</div>
<script src="https://api.paycomet.com/gateway/paycomet.jetiframe.js?lang=es"></script>
</body>
</html>
Con la API de PHP:
<?php
/**
* PAYCOMET JET callback
* Tracking ID: SSX-7MS-JX3J
*
* @author PAYCOMET
* @copyright Copyright (c) 2019, PAYCOMET
* @version 1.0 2016-05-01
*/
include("class/paycomet_bankstore.php");
date_default_timezone_set("Europe/Madrid");
$token = $_POST["paytpvToken"];
if ($token && strlen($token) == 64) {
$endPoint = "https://api.paycomet.com/gateway/xml-bankstore?wsdl";
$merchantCode = "** yourmerchantcode";
$terminal = "** terminalnumber";
$password = "** yourpassword";
$jetID = "** yourJETID";
$signature = sha1($merchantCode.$token.$jetID.$terminal.$password);
$ip = $_SERVER["REMOTE_ADDR"];
$paycomet
= new Paycomet_Bankstore($merchantCode, $terminal, $password, $jetID);
$resp = $paycomet->AddUserToken($token);
$idUser = $resp->DS_IDUSER;
$tokenUser = $resp->DS_TOKEN_USER;
$purchaseResult
= $paycomet->ExecutePurchase(
$resp->DS_IDUSER,
$resp->DS_TOKEN_USER,
$_POST["amount"],
"REFERENCIAPEDIDO",
"EUR"
);
if ($purchaseResult->DS_RESPONSE == "1") {
return true;
} else {
var_dump($purchaseResult->DS_ERROR_ID);
return false;
}
} else {
var_dump("Error, no se ha obtenido token");
return false;
}
return false;
Handler
JET-IFRAME no permite realizar acciones entre el envío y la generación de tokens. Sin embargo, puedes usar este método para manejar el formulario con el token.
En el siguiente ejemplo se añade una llamada a la función customFunction()
en el action
del formulario para después realiza operaciones desde allí.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
</head>
<body>
<form role="form" id="paycometPaymentForm" action="javascript:customFunction();" method="POST">
<!------ Formulario ---------->
</form>
<script>
function customFunction(){
myForm = document.getElementById("paycometPaymentForm");
console.log(myForm);
}
</script>
</body>
</html>