No mostrar más este mensaje

ecommerce

Notificación HTTP

 

Esta operativa complementa el envío por POST visto en el apartado 3.3. Una vez realizado el envío por POST se puede recibir una notificación, transparente al usuario, informando los datos de la transacción realizada.

El envío a realizar es el mismo que el descrito en el apartado 3.3 a excepción de 2 particularidades:

  • El cálculo de la firma se hará usando el SHA1CompletoAmpliado y pasándole la URL de notificación (más información en el apartado 2.4.2)
  • Se debe incluir en el formulario a enviar un parámetro nuevo indicando la URL de notificación (Ds_Merchant_MerchantURL)

Así pues, el ejemplo JSP quedaría así:

Indicamos que es una página JSP

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"  pageEncoding="ISO-8859-1"%>

Importamos la clase FirmaUtils que usaremos para el cálculo de la firma

<%@ page import="es.lacaixa.redsys.FirmaUtils" %>

Declaramos las variables a usar. En un entorno real algunos de estos datos no serán fijos y los recuperaremos de la request

<%! 
    double    IMPORTE                    = (double)1.45;
    String    PEDIDO                    = "123456";
    String    COMERCIO                = "99999999";
    String    MONEDA                    = "978";
    String    TIPO_TRANSACCION        = "0";
    String    TERMINAL                = "2";
    String    CLAVE_SECRETA            = "poiuytrewq9876543210";
    String    FECHA                    = "1212"
    String    URL_OK                    = "http://prueba.com/OK.html";
    String    URL_KO                    = "http://prueba.com/KO.html";
    String    URL_NOTIFICACION        = "http://prueba.com/apl/RedsysSamples/RespuestaPasarelaServlet";    
    String    URL_ACTION                = "https://sis-t.redsys.es:25443/sis/realizarPago";
%>

Calculamos la firma del comercio usando la clase importada previamente

<%! 
    String FIRMA = FirmaUtils.getFirmaSHA1CompletoAmpliada( Double.valueOf(IMPORTE), 
                                                            PEDIDO, 
                                                            COMERCIO, 
                                                            MONEDA, 
                                                            CLAVE_SECRETA, 
                                                            TIPO_TRANSACCION, 
                                                            URL_NOTIFICACION);
%>

Creamos el código HTML con el form correspondiente. El form se ha de enviar por POST y los nombres de los campos han de ser los indicados en la tabla anterior. Cualquier diferencia en el nombre de un campo será crítica para el buen funcionamiento de la pasarela.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Ejemplo petici&oacute;n POST con Notificaci&oacute;n HTTP</title>    
</head>
    
    <body>

        <h1>Ejemplo petici&oacute;n POST con Notificaci&oacute;n HTTP</h1>

        <form id="peticionPostForm" action="
<%= URL_ACTION %>" method="post">

            <input type="hidden" name="Ds_Merchant_Amount"         value="
<%= (int)(IMPORTE*100)%>"/>
            <input type="hidden" name="Ds_Merchant_Order"         value="
<%= PEDIDO %>"/>
            <input type="hidden" name="Ds_Merchant_MerchantCode"     value="
<%= COMERCIO %>"/>
            <input type="hidden" name="Ds_Merchant_Currency"     value="
<%= MONEDA %>"/>
            <input type="hidden" name="Ds_Merchant_TransactionType"     value="
<%= TIPO_TRANSACCION %>"/>
            <input type="hidden" name="Ds_Merchant_MerchantURL"     value="
<%= URL_NOTIFICACION %>"/>
            <input type="hidden" name="Ds_Merchant_UrlOK"         value="
<%= URL_OK %>"/>
            <input type="hidden" name="Ds_Merchant_UrlKO"         value="
<%= URL_KO %>"/>
            <input type="hidden" name="Ds_Merchant_MerchantSignature" value="
<%= FIRMA %>"/>
            <input type="hidden" name="Ds_Merchant_Terminal"     value="
<%= TERMINAL %>"/>

            <input type="submit" value="Realizar Pago"/>
        </form>

    </body>
</html>

La respuesta http es un proceso independiente de la conexión con el navegador del cliente y no tiene ningún reflejo en pantalla del mismo. Evidentemente, en el lado del comercio, deberá haber un proceso que recoja esta respuesta http.

El protocolo utilizado en las respuestas puede ser http o https, el formato de este mensaje es un formulario HTML, enviado con el método POST, y cuyos campos son los siguientes (en los campos Ds_Currency; Ds_Terminal; Ds_ConsumerLanguage la longitud se considera máxima por lo que no es imprescindible el relleno con ceros a la izquierda; la firma será generada con los campos exactamente como se envíen):

DATO NOMBRE DEL DATO LONG/TIPO COMENTARIOS
Fecha Ds_Date dd/mm/yyyy Fecha de la transacción
Hora Ds_Hour HH:mm Hora de la transacción
Importe Ds_Amount 12 / Núm. Mismo valor que en la petición.
Moneda Ds_Currency 4 / Núm. Mismo valor que en la petición. 4 se considera su longitud máxima.
Número de pedido Ds_Order 12 / A-N. Mismo valor que en la petición.
Identificación de comercio: código FUC Ds_MerchantCode 9 / N. Mismo valor que en la petición.
Terminal Ds_Terminal 3 / Núm. Número de terminal que le asignará su banco. 3 se considera su longitud máxima.
Firma para el comercio Ds_Signature 40 / A-N Ver a pie de página las instrucciones para su cálculo.
Código de respuesta Ds_Response 4 / Núm. Ver tabla siguiente
Datos del comercio Ds_MerchantData 1024 / A-N Información opcional enviada por el comercio en el formulario de pago.
Pago Seguro Ds_SecurePayment 1 / Núm. 0 – Si el pago NO es seguro
1 – Si el pago es seguro
Tipo de operación Ds_TransactionType 1 / A-N Tipo de operación que se envió en el formulario de pago
País del titular Ds_Card_Country 3/Núm País de emisión de la tarjeta con la que se ha intentado realizar el pago.
Código de autorización Ds_AuthorisationCode 6/ A-N Código alfanumérico de autorización asignado a la aprobación de la transacción por la institución autorizadora.
Idioma del titular Ds_ConsumerLanguage 3 / Núm El valor 0, indicará que no se ha determinado el idioma del cliente. (opcional). 3 se considera su longitud máxima.

La conexión utilizada para comunicar la confirmación “on-line” entre el TPV Virtual y el comercio puede ser SSL. Opcionalmente el comercio puede activar un filtro para limitar la recepción de la confirmación “on-line” solo desde el TPV Virtual para evitar comunicaciones fraudulentas.

El TPV Virtual por defecto puede comunicar a los puertos 80, 443, 8080 y 8081 del comercio. Otros puertos deberán ser consultados.

Una vez que el comercio recibe el formulario, el código de respuesta (ds_response) tendrá los siguientes valores posibles:

CÓDIGO SIGNIFICADO
0000 a 0099 Transacción autorizada para pagos y preautorizaciones
0900 Transacción autorizada para devoluciones y confirmaciones
101 Tarjeta caducada
102 Tarjeta en excepción transitoria o bajo sospecha de fraude
104 Operación no permitida para esa tarjeta o terminal
116 Disponible insuficiente
118 Tarjeta no registrada
180 Tarjeta ajena al servicio
184 Error en la autenticación del titular
190 Denegación sin especificar Motivo
191 Fecha de caducidad errónea
202 Tarjeta en excepción transitoria o bajo sospecha de fraude con retirada de tarjeta
912/9912 Emisor no disponible
Cualquier otro valor Transacción denegada

Nota: solo en el caso de las preautenticaciones (preautorizaciones separadas), se devuelve un 0 si está autorizada y el titular se autentica y, un 1 si está autorizada y el titular no se autentica.

El TPV Virtual efectúa el envío de las notificaciones on-line para las operaciones de compra autorizadas y denegadas por la entidad emisora de la tarjeta, así como en aquellas situaciones en las que el proceso de compra ha sido interrumpido al haberse producido uno de los siguientes errores:

SIS0051 -> Pedido repetido. Se envía notificación con código 913.
SIS0078 -> Método de pago no disponible para su tarjeta. Se envía notificación con código 118
SIS0093 -> Tarjeta no válida. Se envía notificación con código 180.
SIS0094 -> Error en la llamada al MPI sin controlar. Se envía notificación con código 184

No se envía notificación en aquellos casos en los que la operación no termine, por ejemplo por que el usuario no indica la tarjeta o cierra el navegador antes de que finalice la autenticación.

Para recibir la notificación HTTP montaremos un Servlet que se encargará de leer los parámetros enviados por la pasarela de pago. Este Servlet no implementa ninguna lógica de negocio, simplemente vuelca el contenido en el log del servidor. En un entorno real esos datos se explotarán de la manera más conveniente en cada caso.


package es.lacaixa.redsys.servlet;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;

import org.xml.sax.SAXException;

public class RespuestaPasarelaServlet extends HttpServlet {

    private static final long    serialVersionUID    = -8991452242470541541L;

    public RespuestaPasarelaServlet() {
        super();
    }

    /*
     * En el método doGet redirigimos al doPost. En principio no debería
     * entrarnos ninguna petición por aquí pero lo dejamos así por si acaso
     * algún día cambian la operativa
     */

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws     ServletException,
                                                                                                   IOException {
        doPost(request, response);
    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws     ServletException,
                                                                                               IOException {

        System.out.println("Request (redsys): ");

        try {

            // Leemos los parámetros de la response
            Map<String, String> responseMap = readResponse(request);

            // Y los imprimimos en la consola del servidor
            for (Entry<String, String> entry : responseMap.entrySet()) {
                System.out.println(entry.getKey() + ": " + entry.getValue());
            }
        } catch (XPathExpressionException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        }
    }

    // Lee de la request los parámetros recibidos y los guarda en un mapa para su posterior explotación
    private static Map<String, String> readResponse(HttpServletRequest request) throws 
                                                        ParserConfigurationException,
                                                        SAXException,
                                                        IOException,
                                                        XPathExpressionException {


        String Ds_Date = request.getParameter("Ds_Date");
        String Ds_Hour = request.getParameter("Ds_Hour");
        String Ds_Amount = request.getParameter("Ds_Amount");
        String Ds_Currency = request.getParameter("Ds_Currency");
        String Ds_Order = request.getParameter("Ds_Order");
        String Ds_MerchantCode = request.getParameter("Ds_MerchantCode");
        String Ds_Terminal = request.getParameter("Ds_Terminal");
        String Ds_Signature = request.getParameter("Ds_Signature");
        String Ds_Response = request.getParameter("Ds_Response");
        String Ds_MerchantData = request.getParameter("Ds_MerchantData");
        String Ds_SecurePayment = request.getParameter("Ds_SecurePayment");
        String Ds_TransactionType = request.getParameter("Ds_TransactionType");
        String Ds_Card_Country = request.getParameter("Ds_Card_Country");
        String Ds_AuthorisationCode = request.getParameter("Ds_AuthorisationCode");
        String Ds_ConsumerLanguage = request.getParameter("Ds_ConsumerLanguage");

        Map<String, String> responseMap = new HashMap<String, String>();

        responseMap.put("Ds_Date", Ds_Date);
        responseMap.put("Ds_Hour", Ds_Hour);
        responseMap.put("Ds_Amount", Ds_Amount);
        responseMap.put("Ds_Currency", Ds_Currency);
        responseMap.put("Ds_Order", Ds_Order);
        responseMap.put("Ds_MerchantCode", Ds_MerchantCode);
        responseMap.put("Ds_Terminal", Ds_Terminal);
        responseMap.put("Ds_Signature", Ds_Signature);
        responseMap.put("Ds_Response", Ds_Response);
        responseMap.put("Ds_MerchantData", Ds_MerchantData);
        responseMap.put("Ds_SecurePayment", Ds_SecurePayment);
        responseMap.put("Ds_TransactionType", Ds_TransactionType);
        responseMap.put("Ds_Card_Country", Ds_Card_Country);
        responseMap.put("Ds_AuthorisationCode", Ds_AuthorisationCode);
        responseMap.put("Ds_ConsumerLanguage", Ds_ConsumerLanguage);

        return responseMap;
    }
}

En el fichero web.xml añadiremos la configuración de este servlet:

  
  <servlet>
    <description></description>
    <display-name>RespuestaPasarelaServlet</display-name>
    <servlet-name>RespuestaPasarelaServlet</servlet-name>
    <servlet-class>es.lacaixa.redsys.servlet.RespuestaPasarelaServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>RespuestaPasarelaServlet</servlet-name>
    <url-pattern>/RespuestaPasarelaServlet</url-pattern>
  </servlet-mapping>

Para poder usar la notificación sobre este servlet necesitaremos instalarlo bajo algún dominio público. Es decir, no podemos probarlo en local ni en una red privada. Esto es porqué la pasarela no hace la petición a través del navegador como en el caso de las URL’s de OK y KO. En este caso la pasarela lanza una petición directamente desde su servidor al nuestro. Si nuestro servidor no es visible para la pasarela nunca nos llegará la modificación.

Esto solo afecta a la notificación, con lo que podríamos tener nuestra aplicación en local realizando pruebas y el servlet instalado en algún entorno de pruebas (siempre que sea visible para el exterior). De esta manera la notificación la recibiríamos en el entorno de pruebas pero el resto de proceso lo llevaríamos a cabo desde nuestro entorno local.

Para probarlo, entramos al navegador (el host y context-root variarán en función de cada desarrollo):

3_4_a

Cuando realicemos el submit del formulario este nos enviará a la pasarela de pago. En ese punto el control lo tiene la pasarela y estamos fuera de nuestra aplicación.

3_4_b

Una vez rellenados los datos confirmamos la compra, esto nos dirigirá una página de confirmación:

3_4_c

Cuando le demos a continuar el navegador nos redirigirá a la URL de OK que hayamos enviado en el formulario:

3_4_d

Si hay algún problema durante el proceso nos redigirá a la URL de KO.
En los logs del servidor donde tenemos instalado el Servlet deberíamos ver las siguientes trazas correspondientes a la notificación:

3_4_e