Integración BankStore JET-IFRAME

El sistema JET-IFRAME de PAYCOMET permite integrar de manera sencilla y segura la pasarela de pagos mantiendo sus 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.

  1. Introducción
  2. Configuración de producto
  3. Formulario
  4. Devolución de la llamada
  5. Ejemplos de uso

Introducción

La integración JET-IFRAME forma parte de la solución BankStore 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.

¿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 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 recibirá la variable "paytpvToken", necesaria junto con otros parámentros que veremos más adelante para comenzar a operar.

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ú Mis productos -> Configurar producto

Tras pulsar en el botón “Editar” del producto elegido, aparecerá un panel con la información básica del producto bajo el apartado “Configuración técnica del producto”. En concreto los datos necesarios durante el proceso de integración son:

  • JET ID

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="">


Debe incluirse "https://secure.paytpv.com/gateway/paycomet.jetiframe.js" al final del documento


    <script src="https://secure.paytpv.com/gateway/paycomet.jetiframe.js"></script>

El botón para enviar debe ser INPUT, no BUTTON


    <input type="submit">Pagar 2,02 € con paycomet

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">
					<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%">
										<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>
									</select>
									<span style="width:10%; text-align: center"> / </span>
									<select class="form-control" style="width:45%">
										<option>YY</option>
										<option>2018</option>
										<option>2019</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="apiID" value="qJQ9s6KX7M41LyCDxFn2fwprBN3gWRZb">
					<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>
									</select>
									<span style="width:10%; text-align: center"> / </span>
									<select class="form-control" style="width:45%" data-paycomet="dateYear">
										<option>YY</option>
										<option value="18">2018</option>
										<option value="19">2019</option>
										<option value="20">2020</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://secure.paytpv.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="apiID" value="your-jet-id">
  • 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
     id="paycomet-pan"
    con el tamaño inline donde se ubicará el iframe.
      <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 :
     xpaycomet-style="width:419px; height:21px; font-size:12px; padding-left:7px;"
  • En el input de la PAN se añade un atributo:x
     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:
     data-paycomet="dateMonth"
    y
     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
     id="paycomet-cvc2"
    con el tamaño inline donde se ubicará el iframe.
    <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:
     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
     <script src="https://secure.paytpv.com/gateway/paycomet.jetiframe.js?lang=es"></script>/pre>. Se puede pasar el parámetro "lang" con el idioma en el que se deseen las notificaciones.	

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 "add_user_token" a través de los web services de PayComet (consultar la API de Bankstore XML )

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.

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 : https://github.com/PayTpv/PAYTPV-XML-Bankstore/blob/master/class/Paytpv_bankstore.php como se muestra en el siguiente ejemplo:Con web services:

<?php
/**
 * PAYCOMET JET IFRAME callback
 * Tracking ID: SSX-7MS-JX3J
 *
 * @author PAYCOMET 
 * @copyright Copyright (c) 2016, PAYCOMET 
 * @version 1.0 2016-05-01
 */


if (isset($_POST["paytpvToken"])) {
    date_default_timezone_set("Europe/Madrid");

    $token = $_POST["paytpvToken"];

    if ($token && strlen($token) == 64) {

        $endPoint       = "https://secure.paytpv.com/gateway/xml_bankstore.php?wsdl";
        $merchantCode   = "** yourmerchantcode";
        $terminal       = "** terminalnumber";
        $password       = "** yourpassword";
        $jetID          = "** yourJETID";
        $productDescription         = "XML_BANKSTORE TEST productDescription";
        $owner                      = "XML_BANKSTORE TEST owner";

        $signature
            = sha1(
                $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
                );
            echo " Proceso correcto. Se ha obtenido el token";
            var_dump($addUserTokenResponse);

$order = "MERCHANTORDER-" . date("Y/m/d h:I:s");
            $signature 
                = sha1(
                    $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
                return true;
            } else {
                //KO
                var_dump($executePurchaseResponse["DS_ERROR_ID"]);
                return false;
            }
        
        var_dump($executePurchaseResponse);
        } 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>
	<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>
	<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.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 / 20 <br/>
								</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="apiID" value="qJQ9s6KX7M41LyCDxFn2fwprBN3gWRZb">
							<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>
											</select>
											<span style="width:10%; text-align: center"> / </span>
											<select class="form-control" style="width:45%" data-paycomet="dateYear">
												<option>YY</option>
												<option value="18">2018</option>
												<option value="19">2019</option>
												<option value="20">2020</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="cvv" 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://secure.paytpv.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/Paytpv_bankstore.php");
       date_default_timezone_set("Europe/Madrid");

       $token = $_POST["paytpvToken"];

       if ($token && strlen($token) == 64) {

        $endPoint       = "https://secure.paytpv.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 Paytpv_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;

?>