Programación Web. Integración con APIs

Sesión 7. Pago electrónico

En este tema vamos a tratar el pago electrónico por Internet, con la idea de integrar en nuestros proyectos web una forma real de realizar transacciones monetarias. Primero estudiaremos la historia de los pagos electrónicos, para después centrarnos en las formas de pago en la web. Por último veremos como desarrollar un sistema de pago completo para tiendas, usando las herramientas de testeo que nos ofrece Paypal. Integraremos las funcionalidades que ofrecen estas herramientas en nuestros códigos de PHP, Javascript y HTML.

¿Que es el pago electrónico?

El Pago Electrónico se entiende como cualquier operación de pago realizada con una tarjeta de banda magnética o con un microprocesador incorporado (por ejemplo con una tarjeta de crédito), en un grupo terminal de pago electrónico o terminal de punto de venta. En el caso concreto de Internet, se usara la identificación numérica de la tarjeta, así como otros datos (fecha de caducidad, digitos de control, etc.).

En los últimos cuarenta años, el pago electrónico ha pasado de ser una forma interna entre bancos para realizar transacciones a popularizarse y ser usado por cualquier cliente de banca. Podemos diferenciar tres etapas en la evolución de las transacciones electrónicas:

  • Desde finales de los 70 los bancos inician la informatización de todos sus datos. Posteriormente las transacciones entre bancos se automatizan.
  • A mediados de los 90 Internet se populariza a nivel global y nacen los primeros negocios electrónicos (ebay, amazon...). Se realizan las primeras ventas masivas y se mejora la seguridad en la red (nace el protocolo SSL).
  • A finales de los 90 nacen las primeras webs dedicadas a la intermediación en el pago online (paypal, moneybrokers,...).

Actualmente existen tres formas de pago electrónico aceptadas en Internet:

  • Pago con tarjeta de crédito.
  • Pago con dinero electrónico.
  • Pago con tarjetas prepago.

De estas formas de pago, el pago con tarjeta de crédito supone más del 90% de las transacciones a nivel mundial. Tanto el pago con dinero electrónico como con tarjetas prepago es minoritario y se encuentra en clara recesión.

Implementación del pago electrónico.

En la actualidad es muy común dotar a las aplicaciones web de la posibilidad de realizar pagos de manera telemática. La forma mas habitual es mediante una pasarela de pago (tpv) que permita el uso de tarjetas de crédito. También existen otras formas de realizar pagos en la web:

  • Por transferencia bancaria (se guardan los datos del pedido y se espera el ingreso)
  • Pago por sms (para pequeños pagos)
  • Pago contrareembolso (al llegar el paquete, el cliente pagará en metálico al repartidor)

En este tema solo vamos a estudiar como realizar la implementación de la solución de pago mediante tarjeta de crédito, ya que por un lado es la más compleja de desarrollar y además la más utilizada. Para realizar esta implementación vamos a necesitar:

  • Una base de datos donde guardar la siguiente información:
  • Información del cliente (nombre, dni, dirección fiscal).
  • Información del pedido
  • Líneas de pedido (productos)
  • Dirección de envío
  • Librerías y/o scripts que nos permitan la comunicación con la pasarela de pago del banco o entidad intermediaria (pj: Paypal).

Además de la parte referente al desarrollo de programación, debemos tener en cuenta los siguientes puntos antes de implementar nuestro sistema de pago:

  • Numero de ventas estimadas. Este punto determinará la potencia de nuestros servidores y la estructura de base de datos, no es lo mismo el desarrollo para una tienda como Amazon, que para una pequeña tienda de barrio.

  • Ámbito geográfico de los clientes (local, nacional, global). Este punto determinará las divisas a utilizar, transportes e impuestos.

  • Precio de los productos en venta y de los pedidos comunes. A la hora de realizar el diseño de la web y la forma de mostrar precios.

  • Si la venta es de productos físicos o servicios (no requieren envió). Si solo ofrecemos servicios o descargas no deberemos guardar direcciones físicas ni realizar envíos.

  • Cómo de críticos son los pagos y la concurrencia de la aceptación del pago con los resultados en nuestra web. Este punto será importante para la implementación de transacciones en nuestra base de datos, si tenemos productos con stock, deberemos de llevar en tiempo real su número para no permitir compras con stock cero.

Paypal, un ejemplo de integración.

En nuestro ejemplo de integración vamos a usar la plataforma Paypal. A continuación explicaremos que es Paypal y porque usarlo.

PayPal es una empresa estadounidense perteneciente al sector del comercio electrónico por Internet que permite la transferencia de dinero entre usuarios. PayPal también procesa peticiones de pago en comercio electrónico y otros servicios webs, por los que cobra un porcentaje. La mayor parte de su clientela proviene del sitio de subastas en línea eBay. De hecho, PayPal pertenecía a eBay hasta principios de 2015 ya que se utilizó para fomentar las ventas en el sitio de eBay.

Vamos a usar Paypal en nuestro ejemplo porque nos permite realizar pagos electrónicos mediante tarjeta de crédito sin necesidad de pedir una autorización de pago telemático a un banco. Entre las ventajas e inconvenientes de usar Paypal encontramos:

  • Utilizar paypal para las ventas por internet nos evita tener que conseguir la autorización del banco para realizar transacciones con tarjetas de terceros.

  • Paypal es conocido por la gran mayoría de usuarios de Internet, ofrece confianza. Ademas dispone de un seguro del 50% de la compra al cliente.

  • Dispone de herramientas sencillas para la integración de la web con su pasarela de pagos.

  • El mayor inconveniente de Paypal es su mayor recargo por las ventas (sobre un 5%, mientras que los bancos no suelen cobrar mas del 2%-3%)

Registrarnos como desarrolladores en Paypal

Para poder hacer uso de la pasarela de pago electrónico de Paypal en modo de pruebas necesitamos registrarnos como desarrolladores de paypal en su sistema de Sandbox, esto lo haremos en la url: http://developer.paypal.com o en sandbox.paypal.com.

Página PayPal

Pulsaremos sobre el botón sign up now para comenzar con el registro. Procederemos a rellenar los datos del registro y al terminarlo debemos realizar la activación desde el enlace que encontraremos en el correo electrónico de confirmación que nos enviarán.

El siguiente paso será entrar en el sistema con la nueva cuenta que hemos creado y crear dos cuentas de Paypal de prueba asociadas a nuestra cuenta de desarrollador. Lo haremos siguiendo el enlace New test account: “Preconfigured”. Crearemos una cuenta de vendedor y otra de comprador, esta última la crearemos con al menos 1.000€ de saldo. Además nos debemos asegurar de que ambas cuentas están localizadas en España para evitar bloqueos por pagos entre diferentes países y divisas. Tras hacer esto el resultado de nuestra página principal de la cuenta debería ser similar al siguiente:

PayPal Test Accounts

Una vez tenemos las dos cuentas, podemos acceder a ellas (sería como entrar en una cuenta real de Paypal de vendedor o comprador) seleccionando su opción y pulsado sobre el botón de la parte inferior “Enter Sandbox Test Site”.

Tipos de pago en Paypal

A la hora de desarrollar la comunicación de nuestro site con la pasarela de pago de Paypal, éste ofrece diferentes tipos de pago (formas de realizar la compra):

  • Botón “compra ahora” o “donar”, es la forma mas sencilla de integrar paypal en una web, pero muy limitada.
  • Compra con carrito de la compra alojado en paypal (es una solución intermedia en cuanto a complejidad y libertad).
  • Compra con carrito de terceros. En este caso Paypal únicamente recibirá la información estrictamente necesaria para el cobro.

En nuestro ejemplo usaremos la compra con carrito de la compra de terceros. Esta opción es la que mayor libertada nos va a dar, además de ser la opción más parecida (de hecho es básicamente igual) a la ofertada directamente por las entidades bancarias.

IPN: Notificación de pago instantanea

Paypal, al igual que la gran mayoría de las pasarelas de pago suministradas por los bancos, ofrece la posibilidad de comprobación instantánea de pago. Esta notificación permite conocer el momento exacto en el cual el pago se ha realizado. Además la notificación se hace directamente desde Paypal siendo la forma mas segura de comprobación de pago realizado. En el siguiente esquema se ven los pasos que se realizaran al hacer un pago con notificación instantánea:

Pago con notificación instantánea

Para hacer uso de la notificación de pago debemos configurar correctamente nuestra cuenta de Paypal, si miramos el esquema vemos como Paypal realiza la confirmación de la compra (la notificación instantánea) llamando al Servidor Web (donde tenemos alojados nuestros ficheros PHP).

Configuración notificaciones de pago con PayPal

Integrando Paypal en nuestro comercio electrónico

Para poder integrar Paypal con notificación de pago instantáneo en nuestra tienda virtual debemos crear varios scripts y realizar cambios en la base de datos (si fuera necesario). En el caso de la base de datos, necesitaremos tener estas cuatro tablas (o una estructura equivalente):

  • Clientes: donde guardaremos los datos de los clientes, así como la dirección de envió si fuera necesaria.
  • Productos: información sobre los productos en venta.
  • Pedido: en esta tabla se tendrá que hacer referencia al cliente que realiza el pedido y el estado del mismo (pagado o no).
  • LíneaPedido: tabla con relación mucho a muchos (N-N) entre pedido y productos. Tendrá un campo cantidad.

Una vez tenemos una base de datos que nos permita guardar los pedidos, debemos realizar los scripts de comunicación. Vamos a mostrar un ejemplo completo de una tienda virtual comentando los códigos necesarios (este ejemplo luego lo podremos integrar a nuestros proyectos).

A continuación se muestra el primer script que utilizaremos, consiste en un formulario de compra, lee de la base de datos los productos escogidos y calcula el precio total del pedido, inserta esta información en un pedido de la base de datos que se marca como no pagado (“pagado” a 0). Es una muestra de un posible checkout (paso en el cual ya hemos elegido los productos que deseamos comprar y estamos logueados en el sistema).

Compra.php (checkout)
$rootBdUser = "root";
$rootBdPass = "";
$nombreBd = "tienda";
$conn = mysql_connect("localhost",$rootBdUser,$rootBdPass);
mysql_select_db($nombreBd,$conn);

// id del cliente que realiza la compra
$usuarioLogueado = 1;
// array con articulo y cantidad
$articulos = array("1"=>1,"2"=>2);

//crear el pedido (que estara sin pagar)
$sql = "insert into tienda_pedido (total,fkUsuario,pagado)
   VALUES (0,".$usuarioLogueado.",0)";
mysql_query($sql);
$idPedido = mysql_insert_id();

//crear lineas de pedido
foreach ($articulos as $id => $cantidad)
{
   $sql = "insert into tienda_linea_pedido
      (fkPedido,fkProducto,cantidad) VALUES
      (".$idPedido.",".$id.",".$cantidad.")";
   mysql_query($sql);
}

//calcular el precio del pedido y registrarlo en la tabla de pedido
$sql = "select sum(p.precio * lp.cantidad)
   from tienda_linea_pedido lp
   inner join tienda_producto p
   on p.id = lp.fkProducto
   where lp.fkPedido = ".$idPedido;
$Rset = mysql_query($sql);
$row = mysql_fetch_array($Rset);
$total = $row[0];
mysql_free_result($Rset);
$sql = "update tienda_pedido
   set total = ".$total."
   where id = ".$idPedido;
mysql_query($sql);

?>

<html>
   <head><title>PAGO ONLINE</title></head>
   <body>
      <br>
      <span>El usuario con id:</span><?=$usuarioLogueado?><br>
      <span>Va a realizar la compra de:</span><br>
      <?
         foreach ($articulos as $id => $cantidad)
         {
            echo "Producto: ".$id."
               cantidad:".$cantidad."<br>";
         }
      ?>
      <span>El total de la compra con id
         <?=$idPedido?> es: <?=$total?></span><br>
      <br>
      <form action="enviarPaypal.php"
         method="POST">
         <input type="hidden"
            name="idPedido"
            value="<?=$idPedido?>">
         <input type="hidden"
            name="total"
            value="<?=$total?>">
         <input type="hidden"
            name="cliente"
            value="<?=$usuarioLogueado?>">
         <input type="submit"
            name="opcion"
            value="Terminar Compra">
      </form>
   </body>
</html>

La información del checkout (id del usuario, id del pedido y total de la compra) se enviará a Paypal mediante un formulario de tipo POST con una estructura especifica. En el fichero enviarPaypal.php se muestra como crearemos este formulario (que enviaremos a Paypal) a partir de la información que nos llega del checkout (compra.php).

EnviarPaypal.php (formulario de envío a Paypal):
<!-- Vamos a redirigir la pagina a la pasarela de
   pago de paypal con los valores que nos llegan del formulario -->
<body onLoad="document.formulario.submit()" >
   <div>Connect to Paypal...</div>
   <form  name="formulario"
      id="formulario"
      action="https://sandbox.paypal.com/cgi-bin/webscr"
      method="post">
      <!-- Identificar tu tienda (recuerda los datos
         puestos en la cuente creada como seller en
         developer.paypal.com) -->
      <input type="hidden"
         name="bn"
         value="Tienda de Prueba"><!-- el nombre da igual -->
      <input type="hidden"
         name="business"
         value="[email protected]">
         <!-- introducir el email de la cuenta de prueba -->
      <!-- Especificar el tipo de boton/formulario en paypal -->
      <input type="hidden"
         name="cmd"
         value="_xclick">
      <input type="hidden"
         name="no_note"
         value="1">
      <!-- Ponemos que no pregunten sobre el envio
         -nuestra web se hace cargo- -->
      <input type="hidden"
         name="no_shipping"
         value="1">
      <!-- El unico item es la compra realizada -nosotros con el id
         de la compra ya sacamos los producto- -->
      <input type="hidden"
         name="item_name"
         value="Compra desde Tienda de Prueba">
      <!-- Especificamos el id del pedido -->
      <input type="hidden"
         name="item_number"
         value="<?=$_POST["idPedido"]?>">
      <!-- Ponemos el total de la compra -->
      <input type="hidden"
         name="amount"
         value="<?=$_POST["total"]?>">
      <!-- Especificamos pago en euro -->
      <input type="hidden"
         name="currency_code"
         value="EUR">
      <input type="hidden"
         name="rm" value="2">
      <!-- Como dato extra, enviamos el codigo del cliente -->
      <input type="hidden"
         name="custom"
         value="<?=$_POST["cliente"]?>">
      <!-- Pagina de vuelta de la compra efectuada -->
      <input type="hidden"
         name="return"
         value="http://proyectos.proweb.ua.es/josh/clase/14/compraOk.php">
      <!-- Pagina de vuelta de la compra con error-->
      <input type="hidden"
         name="cancel_return"
         value="http://proyectos.proweb.ua.es/josh/clase/14/compraError.php">
   </form>
</body>

Una vez se envía el formulario de envioPaypal.php, el usuario es redirigido a Paypal donde realizará el pago. Una vez el usuario pague con la tarjeta de crédito, a los pocos segundos Paypal enviará la notificación de pago instantánea. Esa notificación la recogeremos en el fichero paypal.php. En este fichero comprobaremos que la llamada es realmente de Paypal (mediante un fragmento de código facilitado por Paypal). Después recogeremos las variables que nos envía Paypal, si el pago es correcto, haremos un update de base de datos para marcar nuestro pedido con pagado a 1, además guardaremos en un fichero de log (log.txt, aseguraros de tener permisos de escritura sobre el directorio para poder crear este fichero) que el pago ha sido realizado y la hora en la que ha ocurrido.

Paypal.php:
<?php

// Credenciales y conexion para la base de datos
$rootBdUser = "josh";
$rootBdPass = "projoshweb";
$nombreBd = "DBjosh";
$conn = mysql_connect("localhost",$rootBdUser,$rootBdPass);
mysql_select_db($nombreBd,$conn);

// CODIGO DE PAYPAL PARA COMPROBAR LA AUTENTICIDAD -------

// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';

foreach ($_POST as $key => $value) {
   $value = urlencode(stripslashes($value));
   $req .= "&$key=$value";
}

// post back to PayPal system to validate
$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('ssl://sandbox.paypal.com', 443, $errno, $errstr, 30);

// ------------------------------------------------------

// recogemos los datos da paypal
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$payment_status = $_POST['payment_status'];
$payment_amount = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
$custom = $_POST['custom'];


/*
 * Comprobamos si el pago se ha efectuado y si no ha habido error
 * Para hacer un seguimiento de la acciones guardamos las incidencias
 * en un fichero de texto log.txt
 */

if (!$fp) {
// Ha ocurrido un error

   $fh = fopen("log.txt", "a");
   fwrite($fh, "[ERROR][PAYPAL]["
      .date("d-m-Y H:i:s")."]\n");
   fclose($fh);

} else {
   fputs ($fp, $header . $req);
   while (!feof($fp)) {
      $res = fgets ($fp, 1024);
      if (strcmp ($res, "VERIFIED") == 0)
      {
         // Se ha verificado la compra

         // si el pago es correcto, ponemos en nuestra base de
         // datos el pedido como pagado.
         if($payment_status == "Completed")
         {
            // Ponemos el pedido de la base de datos como pagado
            $sql = "update tienda_pedido set pagado = 1
               where id = ".$item_number;
            mysql_query($sql);

            $fh = fopen("log.txt", "a");
            fwrite($fh, "[OK][PAYPAL]["
               .date("d-m-Y H:i:s")."] numVenta: "
               .$item_number." - idCliente: "
               .$custom." - total: "
               .$payment_amount." \n");
            fclose($fh);
            // Podemos aprovechar aqui para enviar un mail al usuario
         }
         else
         {
            // si el pago no esta completado, lo añadimos al log
            // y no hacemos nada
            $fh = fopen("log.txt", "a");
            fwrite($fh, "[OK][ERROR]["
               .date("d-m-Y H:i:s")."] numVenta: "
               .$item_number." - idCliente: "
               .$custom." - payStatus: "
               .$payment_status." \n");
            fclose($fh);
         }
      }
      else
         if (strcmp ($res, "INVALID") == 0)
         {
            // Si es invalido tambien lo grabamos como error
            $fh = fopen("log.txt", "a");
            fwrite($fh, "[OK][ERROR]["
               .date("d-m-Y H:i:s")."] numVenta: "
               .$item_number." - idCliente: "
               .$custom." - payStatus: "
               .$payment_status." \n");
            fclose($fh);
         }
   }
   fclose ($fp);
}
?>

Por último crearemos dos ficheros, compraOk.php y compraError.php que serán a los que se redirija al usuario desde Paypal al terminar la compra. Si todo ha ido correctamente será enviado a compraOk.php mientras que si ha habido algún problema será enviado a compraError.php. Esto ficheros se especifican en el formulario de envío a Paypal (verlo en el fichero enviarPaypal.php).

CompraOk.php:
<html>
   <head><title>PAGO REALIZADO</title></head>
   <body>
      <?
         // ES UN PAGO DE PAYPAL
         if(isset($_POST["receiver_email"]))
         {
            $cliente = $_POST["custom"];
            $idPedido = $_POST["item_number"];

            echo "<br> El pago del pedido :".$idPedido;
            echo "<br> por el cliente con id :".$cliente;

            // COMPROBAR QUE EL PAGO SE HA REALIZADO CORRECTAMENTE
            if($_POST["payment_status"] == "Completed")
               echo "<br> Se ha efectuado y comprobado correctamente";
            else
               echo "<br> Se ha efectuado pero no se ha podido comprobar";
         }
         else
         {
            echo "<br> Ocurrió un error con el pago";
         }
      ?>
   </body>
</html>
CompraError.php
<html>
   <head><title>PAGO NO REALIZADO</title></head>
   <body>
      <?
         // ES UN PAGO DE PAYPAL
         if(isset($_POST["receiver_email"]))
         {
            $cliente = $_POST["custom"];
            $idPedido = $_POST["item_number"];

            echo "<br> El pago del pedido :".$idPedido;
            echo "<br> por el cliente con id :".$cliente;
            echo "<br> NO SE HA REALIZADO ";
         }
         else
         {
            echo "<br> Ocurrio un error con el pago";
         }
      ?>
   </body>
</html>

Ejercicios Sesión 7

Integrar el ejemplo de pago electrónico por Paypal en el proyecto Uazon (Uazon).

Se pide modificar el proyecto Uazon para poder realizar pagos electrónicos por la pasarela de pagos de prueba de Paypal (sandbox.paypal.com). Se seguirán las indicaciones del ejemplo realizado en clase. Para poder hacer este ejercicio es necesario modificar la base de datos de Uazon, añadiendo la tabla linea_pedido y modificando la tabla de pedidos (tomar como muestra las tablas del ejemplo de clase). Por último, recordad que debéis registraros en el centro de desarrollo de Paypal (developer.paypal.com y para probar el correcto funcionamiento realizad los test directamente en vuestra carpeta web en el servidor (ej: proyectos.proweb.ua.es/josh/xxx).