No mostrar más este mensaje

ecommerce

XML Directo

 

Existe la posibilidad de enviar la transacción mediante XML permitiendo automatizar el envío de transacciones, por ejemplo un grupo de devoluciones. 

La comunicación se realizará mediante un envío del documento XML a la dirección indicada del SIS. El sistema de REDSYS interpretará el documento XML y realizará las validaciones pertinentes, para a continuación procesar la operación. Dependiendo del resultado de la oración, se monta un documento XML de respuesta con el resultado de la misma.

El documento XML se transmitirá mediante un envío con POST a las direcciones:

Pruebas: https://sis-t.redsys.es:25443/sis/operaciones
Real: https://sis.redsys.es/sis/operaciones

El envío se realizará simulando la petición realizada por un formulario con un único input llamado “entrada”. El valor de “entrada” será el documento XML, el cual debe estar en formato x-www-form-urlencoded. Se definen dos tipos de mensaje:

  1. DATOSENTRADA: Mensaje de solicitud enviado.
  2. RETORNOXML: Respuesta del SIS a la petición.

Las peticiones al SIS mediante XML, se realizan mediante una conexión host to host (comercio -> SIS). El comercio envía la petición por XML y el retorno también va vía XML y no existe navegador del titular.

En esta entrada el comercio si envía la tarjeta y el comercio es quien muestra el recibo de compra al titular. El titular en ningún momento está en contacto con el SIS. Por este motivo por esta entrada no se pueden realizar pagos que requieran autenticación del titular, ya que no tenemos el control del navegador del titular en ningún momento y por tanto no se puede ceder este control al emisor para que efectúe la autenticación de acuerdo al protocolo 3D Secure.

Este tipo de entrada al SIS, tiende a desaparecer, recomendándose a los nuevos comercios la entrada por WebService, que mantiene todas las funcionalidades de la entrada por XML, pero añade la facilidad de que el comercio opere en multidivisa (operativa DCC).

A través de la entrada /operaciones, no es posible ofrecer la operativa DCC dado que el comercio en ningún momento nos cede la sesión del navegador del titular y por tanto no podemos mostrarle la pantalla de selección de moneda de DCC ni el recibo de compra de DCC.

Ejemplo de código:

Declaramos las constantes que contienen la información del pago:

private static final Double     IMPORTE            = Double.valueOf(1.45);
private static final String     PEDIDO          = "123456";
private static final String     COMERCIO         = "99999999";
private static final String     MONEDA             = "978";
private static final String     TARJETA         = "1234567890123456";
private static final String     CVV2             = "123";
private static final String     TIPO_TRANSACCION     = "A";
private static final String     CLAVE_SECRETA         = "poiuytrewq9876543210";
private static final String     VERSION            = "0.1";
private static final Integer     TERMINAL         = 2;
private static final String     URL             = "https://prueba.com";
private static final String     DESCRIPCION        = "Alfombrilla+para+raton";
private static final String     NOMBRE_COMERCIO         = "Comercio de Pruebas";
private static final Integer     FECHA             = 1212;
private static final String     IP             = "127.0.0.1";

Declaramos constantes con los nombres de los tags XML correspondientes a:

<!ELEMENT DATOSENTRADA 
(DS_Version, 
DS_MERCHANT_AMOUNT, 
DS_MERCHANT_CURRENCY, 
DS_MERCHANT_ORDER, 
DS_MERCHANT_MERCHANTCODE, 
DS_MERCHANT_MERCHANTURL, 
DS_MERCHANT_MERCHANTNAME ?, 
DS_MERCHANT_CONSUMERLANGUAGE ?, 
DS_MERCHANT_MERCHANTSIGNATURE, 
DS_MERCHANT_TERMINAL, 
DS_MERCHANT_TRANSACTIONTYPE, 
DS_MERCHANT_MERCHANTDATA ?, 
DS_MERCHANT_PAN?, 
DS_MERCHANT_EXPIRYDATE ?, 
DS_MERCHANT_CVV2 ?)> 
<!ELEMENT DS_Version (#PCDATA)> 
<!ELEMENT DS_MERCHANT_AMOUNT (#PCDATA)> 
<!ELEMENT DS_MERCHANT_CURRENCY (#PCDATA)> 
<!ELEMENT DS_MERCHANT_ORDER (#PCDATA)> 
<!ELEMENT DS_MERCHANT_MERCHANTCODE (#PCDATA)> 
<!ELEMENT DS_MERCHANT_MERCHANTURL (#PCDATA)> 
<!ELEMENT DS_MERCHANT_MERCHANTNAME (#PCDATA)> 
<!ELEMENT DS_MERCHANT_CONSUMERLANGUAGE (#PCDATA)> 
<!ELEMENT DS_MERCHANT_MERCHANTSIGNATURE (#PCDATA)> 
<!ELEMENT DS_MERCHANT_TERMINAL (#PCDATA)> 
<!ELEMENT DS_MERCHANT_TRANSACTIONTYPE (#PCDATA)> 
<!ELEMENT DS_MERCHANT_MERCHANTDATA (#PCDATA)> 
<!ELEMENT DS_MERCHANT_PAN (#PCDATA)> 
<!ELEMENT DS_MERCHANT_EXPIRYDATE (#PCDATA)> 
<!ELEMENT DS_MERCHANT_CVV2 (#PCDATA)>
private static final String    XML_DATOSENTRADA                = "DATOSENTRADA";
private static final String    XML_DS_Version                = "DS_Version";
private static final String    XML_DS_MERCHANT_AMOUNT            = "DS_MERCHANT_AMOUNT";
private static final String    XML_DS_MERCHANT_CURRENCY            = "DS_MERCHANT_CURRENCY";
private static final String    XML_DS_MERCHANT_ORDER            = "DS_MERCHANT_ORDER";
private static final String    XML_DS_MERCHANT_MERCHANTCODE        = "DS_MERCHANT_MERCHANTCODE";
private static final String    XML_DS_MERCHANT_MERCHANTURL        = "DS_MERCHANT_MERCHANTURL";
private static final String    XML_DS_MERCHANT_MERCHANTNAME        = "DS_MERCHANT_MERCHANTNAME";
private static final String    XML_DS_MERCHANT_MERCHANTSIGNATURE    = "DS_MERCHANT_MERCHANTSIGNATURE";
private static final String    XML_DS_MERCHANT_TERMINAL            = "DS_MERCHANT_TERMINAL";
private static final String    XML_DS_MERCHANT_TRANSACTIONTYPE        = "DS_MERCHANT_TRANSACTIONTYPE";
private static final String    XML_DS_MERCHANT_MERCHANTDATA        = "DS_MERCHANT_MERCHANTDATA";
private static final String    XML_DS_MERCHANT_PAN            = "DS_MERCHANT_PAN";
private static final String    XML_DS_MERCHANT_EXPIRYDATE        = "DS_MERCHANT_EXPIRYDATE";
private static final String    XML_DS_MERCHANT_CVV2            = "DS_MERCHANT_CVV2";
private static final String    XML_DS_MERCHANT_CLIENTIP            = "DS_MERCHANT_CLIENTIP";

A continuamos se detalle un método main de ejemplo:

public static void main(String[] args) throws     NoSuchAlgorithmException, 
                                                ParserConfigurationException, 
                                                IOException, 
                                                TransformerException,
                                                XPathExpressionException, 
                                                SAXException {
    // Creamos la firma
    String firma = FirmaUtils.getFirmaHostToHostIMPORTE, 
                                              PEDIDO, 
                                              COMERCIO, 
                                              MONEDA, 
                                              TARJETA, 
                                              CVV2, 
                                              TIPO_TRANSACCION, 
                                              CLAVE_SECRETA);
    // Creamos el XML que enviaremos
    Document xmlDocument = createXML(firma);
    // Pasamos el objeto XML a String
    String xmlDatosEntrada = documentToString(xmlDocument);
    // Creamos un envío HTTP Post
    HttpPost httpPost = new HttpPost(URL_DESTINO_PRUEBAS);
    // Añadimos el XML a enviar
    httpPost.addXML(PARAMETRO_XML, xmlDatosEntrada);
    // Hacemos la llamada y nos guardamos la respuesta
    String respuesta = httpPost.call();
    // Parseamos el XML de respuesta y luego guardamos en un mapa
    Map<String, String> responseMap = parseXML(respuesta);
    // Mostramos el contenido del mapa
    for (Entry<String, String> entry : responseMap.entrySet()) {
        System.out.println(entry.getKey() + ": " + entry.getValue());
    }
}

Los métodos mostrados a continuación son usados por el main descrito anteriormente:

// Transforma un objeto del tipo Document a un String
private static String documentToString(Document document) throws TransformerException {
    DOMSource domSource = new DOMSource(document);
    StringWriter writer = new StringWriter();
    StreamResult result = new StreamResult(writer);
    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer transformer = tf.newTransformer();
    transformer.transform(domSource, result);
    return writer.toString();
}
// Crea un objeto Document (XML) con los datos a enviar
private static Document createXML(String firma) throws ParserConfigurationException {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    DOMImplementation implementation = builder.getDOMImplementation();
    Document document = implementation.createDocument(nullXML_DATOSENTRADAnull);
    document.setXmlVersion("1.0");
    Element raiz = document.getDocumentElement();
    addElemento(document, raiz, XML_DS_VersionVERSION);
    addElemento(document, raiz, XML_DS_MERCHANT_AMOUNT, (int) (IMPORTE * 100));
    addElemento(document, raiz, XML_DS_MERCHANT_CURRENCYMONEDA);
    addElemento(document, raiz, XML_DS_MERCHANT_ORDERPEDIDO);
    addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTCODECOMERCIO);
    addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTURLURL);
    addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTNAMENOMBRE_COMERCIO);
    addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTSIGNATURE, firma);
    addElemento(document, raiz, XML_DS_MERCHANT_TERMINALTERMINAL);
    addElemento(document, raiz, XML_DS_MERCHANT_TRANSACTIONTYPETIPO_TRANSACCION);
    addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTDATADESCRIPCION);
    addElemento(document, raiz, XML_DS_MERCHANT_PANTARJETA);
    addElemento(document, raiz, XML_DS_MERCHANT_EXPIRYDATEFECHA);
    addElemento(document, raiz, XML_DS_MERCHANT_CVV2CVV2);
    addElemento(document, raiz, XML_DS_MERCHANT_CLIENTIPIP);
    return document;
}
// Añade un nuevo elemento al objeto Document    
private static void addElemento(Document document, Element raiz, String nombreElemento, Object valorElemento){
    if (valorElemento != null) {
        // Creamos un nuevo elemento
        Element hijo = document.createElement(nombreElemento);
        // Ingresamos la info
        Text hijoValor = document.createTextNode(valorElemento.toString());
        // Añadimos el valor al elemento
        hijo.appendChild(hijoValor);
        // Añadimos el elemento a la raiz
        raiz.appendChild(hijo);
    }
}
// Transforma un xml en un mapa de claves valor para cada tag
private static Map parseXML(String xml) throws ParserConfigurationException, 
                                                               SAXException, 
                                                               IOException, 
                                                               XPathExpressionException {
    DOMParser parser = new DOMParser();
    parser.parse(new InputSource(new StringReader(xml)));
    Document doc = parser.getDocument();
    NodeList nodeList = doc.getElementsByTagName("OPERACION");
    Element elementOperacion = (Element) nodeList.item(0);
    String Ds_Amount = getChildValue(elementOperacion, "Ds_Amount");
    String Ds_Currency = getChildValue(elementOperacion, "Ds_Currency");
    String Ds_Order = getChildValue(elementOperacion, "Ds_Order");
    String Ds_Signature = getChildValue(elementOperacion, "Ds_Signature");
    String Ds_MerchantCode = getChildValue(elementOperacion, "Ds_MerchantCode");
    String Ds_Terminal = getChildValue(elementOperacion, "Ds_Terminal");
    String Ds_Response = getChildValue(elementOperacion, "Ds_Response");
    String Ds_AuthorisationCode = getChildValue(elementOperacion, "Ds_AuthorisationCode");
    String Ds_TransactionType = getChildValue(elementOperacion, "Ds_TransactionType");
    String Ds_SecurePayment = getChildValue(elementOperacion, "Ds_SecurePayment");
    String Ds_Language = getChildValue(elementOperacion, "Ds_Language");
    String Ds_MerchantData = getChildValue(elementOperacion, "Ds_MerchantData");
    String Ds_Card_Country = getChildValue(elementOperacion, "Ds_Card_Country");
    Map responseMap = new HashMap();
    responseMap.put("Ds_Amount", Ds_Amount);
    responseMap.put("Ds_Currency", Ds_Currency);
    responseMap.put("Ds_Order", Ds_Order);
    responseMap.put("Ds_Signature", Ds_Signature);
    responseMap.put("Ds_MerchantCode", Ds_MerchantCode);
    responseMap.put("Ds_Terminal", Ds_Terminal);
    responseMap.put("Ds_Response", Ds_Response);
    responseMap.put("Ds_AuthorisationCode", Ds_AuthorisationCode);
    responseMap.put("Ds_TransactionType", Ds_TransactionType);
    responseMap.put("Ds_SecurePayment", Ds_SecurePayment);
    responseMap.put("Ds_Language", Ds_Language);
    responseMap.put("Ds_MerchantData", Ds_MerchantData);
    responseMap.put("Ds_Card_Country", Ds_Card_Country);
    return responseMap;
}
// Obtiene el valor de un hijo del elemento
private static String getChildValue(Element element, String childName) {
    NodeList nlsNombre = element.getElementsByTagName(childName);
    Element eleNombre = (Element) nlsNombre.item(0);
    return eleNombre.getFirstChild().getNodeValue();
}

Además se usa esta clase de apoyo que permite realizar la conexión HTTP enviando los datos por POST:

package es.lacaixa.redsys.xml.conexiondirecta;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
public class HttpPost {
    private URL            url;
    private StringBuilder        data;
    private static final String    ENCODE    = "UTF-8";
    // Necesario en test ya que el certificado de seguridad recibido es para un
    // dominio diferente.
    // El certificado está creado para el entorno de producción
    static {
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                // ip address of the service URL(like.23.28.244.244)
                return hostname.equals("sis-t.redsys.es");
            }
        });
    }
    public HttpPost(String url) throws MalformedURLException {
        this.url = new URL(url);
        data = new StringBuilder();
    }
    public void addXML(String nombreParametro, String valorParametro) throws UnsupportedEncodingException {
        // Codificamos cada uno de los valores
        if (data.length() > 0) {
            data.append("&");
        }
        data.append(URLEncoder.encode(nombreParametro,ENCODE)+"="+URLEncoder.encode(valorParametro,ENCODE));
    }
    public String call() throws IOException {
        StringBuilder respuesta = new StringBuilder();
        // Abrimos la conexión
        URLConnection conn = url.openConnection();
        // Especificamos que vamos a escribir
        conn.setDoOutput(true);
        // Obtenemos el flujo de escritura
        OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
        // Escribimos
        wr.write(data.toString());
        // Cerramos la conexión
        wr.close();
        // Obtenemos el flujo de lectura
        BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String linea;
        // Procesamos la salida
        while ((linea = rd.readLine()) != null) {
            respuesta.append(linea);
        }
        return respuesta.toString();
    }
}

Si ejecutamos este programa estaremos enviando esta petición (los datos son ficticios, esto solo es una simulación de ejemplo):

<?xml version=version encoding=encoding standalone=standalone?>
<DATOSENTRADA>
    <DS_Version>0.1</DS_Version>
    <DS_MERCHANT_AMOUNT>145</DS_MERCHANT_AMOUNT>
    <DS_MERCHANT_CURRENCY>978</DS_MERCHANT_CURRENCY>
    <DS_MERCHANT_ORDER>123456</DS_MERCHANT_ORDER>
    <DS_MERCHANT_MERCHANTCODE>99999999</DS_MERCHANT_MERCHANTCODE>
    <DS_MERCHANT_MERCHANTURL>https://pruebaCom.jsp</DS_MERCHANT_MERCHANTURL>
    <DS_MERCHANT_MERCHANTNAME>Comercio de Pruebas</DS_MERCHANT_MERCHANTNAME>
    <DS_MERCHANT_MERCHANTSIGNATURE>a6cc3997ac0cbac43cf93790e122c79720155bd8</DS_MERCHANT_MERCHANTSIGNATURE>
    <DS_MERCHANT_TERMINAL>2</DS_MERCHANT_TERMINAL>
    <DS_MERCHANT_TRANSACTIONTYPE>A</DS_MERCHANT_TRANSACTIONTYPE>
    <DS_MERCHANT_MERCHANTDATA>Alfombrilla+para+raton</DS_MERCHANT_MERCHANTDATA>
    <DS_MERCHANT_PAN>1234567890123456</DS_MERCHANT_PAN>
    <DS_MERCHANT_EXPIRYDATE>1212</DS_MERCHANT_EXPIRYDATE>
    <DS_MERCHANT_CVV2>123</DS_MERCHANT_CVV2>
    <DS_MERCHANT_CLIENTIP>127.0.0.1</DS_MERCHANT_CLIENTIP>
</DATOSENTRADA>

Y obtendremos esta respuesta:

<?xml version=version encoding=encoding ?>
<RETORNOXML>
    <CODIGO>0</CODIGO>
    <Ds_Version>0.1</Ds_Version>
    <OPERACION>
        <Ds_Amount>145</Ds_Amount>
        <Ds_Currency>978</Ds_Currency>
        <Ds_Order>123456</Ds_Order>
        <Ds_Signature>a6cc3997ac0cbac43cf93790e122c79720155bd8</Ds_Signature>
        <Ds_MerchantCode>99999999</Ds_MerchantCode>
        <Ds_Terminal>2</Ds_Terminal>
        <Ds_Response>0000</Ds_Response>
        <Ds_AuthorisationCode>832220</Ds_AuthorisationCode>
        <Ds_TransactionType>A</Ds_TransactionType>
        <Ds_SecurePayment>0</Ds_SecurePayment>
        <Ds_Language>1</Ds_Language>
        <Ds_MerchantData>Alfombrilla+para+raton</Ds_MerchantData>
        <Ds_Card_Country>724</Ds_Card_Country>
    </OPERACION>
</RETORNOXML>