No mostrar más este mensaje

ecommerce

Pago con Referencia 

 

El pago con Referencia permite al comercio realizar un pago utilizando una referencia asociada a los datos de tarjeta. Esta operativa permite que el comercio realice varios pagos asociados al mismo titular sin almacenar los datos de tarjeta y, por tanto, sin necesidad de cumplir PCI.

El comercio solicita un pago al SIS. Junto con los datos necesarios para el pago, se envía un nuevo parámetro para solicitar la generación de una “referencia” asociada a los datos de tarjeta. Esta petición se puede realizar por cualquiera de las actuales llamadas al SIS: realizarPago, entradaXMLentidad, operaciones o WebService (en los ejemplos veremos esta última).

El SIS procesa la solicitud de pago y almacena los datos de tarjeta (sólo Tarjeta y Caducidad, nunca CVV2) asociados a una referencia generada internamente. Sólo se generará la referencia si el pago es autorizado.

Para este primer pago, se podrá enviar una operación de importe 0 euros, que se llevará a cabo como cualquier otra operación de importe superior. El SIS devuelve la referencia y la fecha de caducidad (aunque el comercio no esté configurado para ello) junto con la respuesta del pago para que el comercio pueda utilizarla con posterioridad.

Una vez que el comercio ya dispone de una referencia, podrá utilizarla en los pagos posteriores en lugar de enviar la tarjeta y la caducidad.

Firma del comercio:

Se dotará al comercio de una clave, que se utilizará para firmar los datos aportados por el mismo, pudiendo verificarse no solo la identificación del comercio, sino que los datos no han sido alterados en ningún momento. Se utilizará como algoritmo de securización el Hash SHA-1, que garantiza los requisitos mínimos de seguridad en cuanto a la autenticación del origen. La clave se proporcionará para ser incluida en la web del comercio.

Este mismo algoritmo se utilizará para asegurar al comercio la autenticidad de los datos de la respuesta, en caso de que se proporcione URL de notificación por parte del comercio.

Más información en el apartado 2.3.4 y 2.3.5 de esta misma guía

A continuación veremos un ejemplo de llamada al WebService de TPV Virtual para la operativa Petición de Pago usando Pago con Referencia. Los pasos que realizaremos son:

  1. Calculamos la firma inicial (más información en el apartado 2.7 de esta guía)
  2. Creamos el XML a enviar
  3. Instanciamos un stub del Web Service (más información de la creación del WebService en el apartado 5 de esta guía)
  4. Añadimos la información (el XML creado anteriormente)
  5. Realizamos la petición (la petición la hacemos con importe 0 para que no genere ningún pago)
  6. Leemos la referencia que nos ha devuelto el WebService
  7. Calculamos la firma con la referencia recibida (más información en el apartado 2.8 de esta guía)
  8. Creamos el XML a enviar
  9. Usando el stub creado anteriormente añadimos la información (el XML creado en el paso anterior)
  10. Realizamos la petición

En el ejemplo se usan constantes para los datos de envío. En un escenario real no serán constantes sinó variables de la aplicación. Los datos propios del comercio (identificador, clave secreta, terminal, etc…) son ficticios. Es necesario cambiarlos por los correspondientes a cada comercio.

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

private static final Double IMPORTE         = Double.valueOf(1.45);
private static final String PEDIDO_INICIAL        = "123456";
private static final String PEDIDO            = "123457";
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 TERMINAL         = "2";
private static final String CLAVE_SECRETA         = "poiuytrewq9876543210";
private static final String FECHA            = "0101"private static final String FECHA            = "1412";
private static final String IDENTIFIER        = "REQUIRED";
private static final String URL            = "https://pruebaCom.jsp";
private static final String VERSION            = "0.1";    

Declaramos constantes con los nombres de los tags XML:

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_MERCHANTSIGNATURE    = "DS_MERCHANT_MERCHANTSIGNATURE";
private static final String    XML_DS_MERCHANT_TERMINAL            = "DS_MERCHANT_TERMINAL";
private static final String    XML_DS_MERCHANT_MERCHANTURL        = "DS_MERCHANT_MERCHANTURL";
private static final String    XML_DS_MERCHANT_TRANSACTIONTYPE        = "DS_MERCHANT_TRANSACTIONTYPE";
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_IDENTIFIER        = "DS_MERCHANT_IDENTIFIER";

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 de la primera petición
    String firmaInicial = FirmaUtils.getFirmaWebServicePagoReferenciaNueva((double)0, PEDIDO_INICIALCOMERCIOMONEDATARJETAURLCVV2TIPO_TRANSACCION,    CLAVE_SECRETA);
    // Creamos el XML de la primera petición
    Document xmlDocumentInicial = createXMLInicial(firmaInicial);
    // Pasamos el objeto XML a String
    String xmlDatosEntradaInicial = documentToString(xmlDocumentInicial);
    // Eliminamos todo lo que vaya antes del tag XML_DATOS_ENTRADA
    String datosEntradaInicial = xmlDatosEntradaInicial.substring(xmlDatosEntradaInicial.indexOf(XML_DATOSENTRADA) - 1);
    System.out.println(datosEntradaInicial);
    // Creamos el stub del WebService
    SerClsWSEntradaServiceStub entradaServiceStub = new SerClsWSEntradaServiceStub();
    // Creamos un objeto TrataPeticion al que le añadimos los datos de
    // entrada
    TrataPeticion trataPeticionInicial = new TrataPeticion();
    trataPeticionInicial.setDatoEntrada(datosEntradaInicial);
    // Llamamos al WebService y obtenemos la respuesta del mismo
    TrataPeticionResponse trataPeticionResponseInicial = entradaServiceStub.trataPeticion(trataPeticionInicial);
    // Leemos el mensaje de retorno
    String trataPeticionReturnInicial = trataPeticionResponseInicial.getTrataPeticionReturn();
        
    System.out.println(trataPeticionReturnInicial);
    // Obtenemos el identificador que nos ha llegado en la respuesta
    String identifier = getIdentifier(trataPeticionReturnInicial);
    System.out.println(identifier);
    // Creamos la firma
    String firma = FirmaUtils.getFirmaWebServicePagoReferencia(IMPORTEPEDIDOCOMERCIOMONEDATIPO_TRANSACCIONURL, identifier, nullnull,CLAVE_SECRETA);
    // Creamos el XML
    Document xmlDocument = createXML(firma, identifier);
    // Pasamos el objeto XML a String
    String xmlDatosEntrada = documentToString(xmlDocument);
    // Eliminamos todo lo que vaya antes del tag XML_DATOS_ENTRADA
    String datosEntrada = xmlDatosEntrada.substring(xmlDatosEntrada.indexOf(XML_DATOSENTRADA) - 1);
    System.out.println(datosEntrada);
    // Creamos un objeto TrataPeticion al que le añadimos los datos de
    // entrada
    TrataPeticion trataPeticion = new TrataPeticion();
    trataPeticion.setDatoEntrada(datosEntrada);
    // Llamamos al WebService y obtenemos la respuesta del mismo
    TrataPeticionResponse trataPeticionResponse = entradaServiceStub.trataPeticion(trataPeticion);
    // Leemos el mensaje de retorno
    String trataPeticionReturn = trataPeticionResponse.getTrataPeticionReturn();
    System.out.println(trataPeticionReturn);
}

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

// Crea un objeto Document (XML) con los datos a enviar
private static Document createXMLInicial(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_MERCHANT_AMOUNT, 0);
        addElemento(document, raiz, XML_DS_MERCHANT_ORDERPEDIDO_INICIAL);
        addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTCODECOMERCIO);
        addElemento(document, raiz, XML_DS_MERCHANT_CURRENCYMONEDA);
        addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTURLURL);
        addElemento(document, raiz, XML_DS_MERCHANT_PANTARJETA);
        addElemento(document, raiz, XML_DS_MERCHANT_CVV2CVV2);
        addElemento(document, raiz, XML_DS_MERCHANT_TRANSACTIONTYPETIPO_TRANSACCION);
        addElemento(document, raiz, XML_DS_MERCHANT_TERMINALTERMINAL);
        addElemento(document, raiz, XML_DS_MERCHANT_EXPIRYDATEFECHA);
        addElemento(document, raiz, XML_DS_MERCHANT_IDENTIFIERIDENTIFIER);
        addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTSIGNATURE, firma);
        return document;
    }
// Crea un objeto Document (XML) con los datos a enviar
private static Document createXML(String firma, String identifier)throws ParserConfigurationException {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    DOMImplementation implementation = builder.getDOMImplementation();
    Document document = implementation.createDocument(null, XML_DATOSENTRADA, null);
    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_ORDERPEDIDO);
    addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTCODECOMERCIO);
    addElemento(document, raiz, XML_DS_MERCHANT_CURRENCYMONEDA);
    addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTURLURL);
    addElemento(document, raiz, XML_DS_MERCHANT_TRANSACTIONTYPETIPO_TRANSACCION);
    addElemento(document, raiz, XML_DS_MERCHANT_TERMINALTERMINAL);
    addElemento(document, raiz, XML_DS_MERCHANT_IDENTIFIER, identifier);
    addElemento(document, raiz, XML_DS_MERCHANT_MERCHANTSIGNATURE, firma);
    return document;
}
// 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();
}
// 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);
    }
}
// Obtiene el valor del campo identifier    
private static String getIdentifier(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);
    return getChildValue(elementOperacion, "Ds_Merchant_Identifier");
}
// Obtiene el valor del hijo de un elemento    
private static String getChildValue(Element element, String childName) {
    NodeList nlsNombre = element.getElementsByTagName(childName);
    Element eleNombre = (Element) nlsNombre.item(0);
    return eleNombre.getFirstChild().getNodeValue();
}

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

<DATOSENTRADA>
    <DS_MERCHANT_AMOUNT>0</DS_MERCHANT_AMOUNT>
    <DS_MERCHANT_ORDER>94867191194</DS_MERCHANT_ORDER>
    <DS_MERCHANT_MERCHANTCODE>329393581</DS_MERCHANT_MERCHANTCODE>
    <DS_MERCHANT_CURRENCY>978</DS_MERCHANT_CURRENCY>
    <DS_MERCHANT_MERCHANTURL>https://pruebaCom.jsp</DS_MERCHANT_MERCHANTURL>
    <DS_MERCHANT_PAN>4548812049400004</DS_MERCHANT_PAN>
    <DS_MERCHANT_CVV2>123</DS_MERCHANT_CVV2>
    <DS_MERCHANT_TRANSACTIONTYPE>A</DS_MERCHANT_TRANSACTIONTYPE>
    <DS_MERCHANT_TERMINAL>2</DS_MERCHANT_TERMINAL>
    <DS_MERCHANT_EXPIRYDATE>1412</DS_MERCHANT_EXPIRYDATE>
    <DS_MERCHANT_IDENTIFIER>REQUIRED</DS_MERCHANT_IDENTIFIER>
    <DS_MERCHANT_MERCHANTSIGNATURE>7dbc8daeb5cfcef1a663e3f2fe9e70f762240f0c</DS_MERCHANT_MERCHANTSIGNATURE>
</DATOSENTRADA>

Y obtendremos esta respuesta:

<RETORNOXML>
    <CODIGO>0</CODIGO>
    <OPERACION>
        <Ds_Amount>0</Ds_Amount>
        <Ds_Currency>978</Ds_Currency>
        <Ds_Order>94867191194</Ds_Order>
        <Ds_Signature>8D630259BC35AE5F60FC4E7FA2FDBD32847E692B</Ds_Signature>
        <Ds_MerchantCode>329393581</Ds_MerchantCode>
        <Ds_Terminal>2</Ds_Terminal>
        <Ds_Response>0001</Ds_Response>
        <Ds_AuthorisationCode>000000</Ds_AuthorisationCode>
        <Ds_TransactionType>A</Ds_TransactionType>
        <Ds_SecurePayment>0</Ds_SecurePayment>
        <Ds_Language>1</Ds_Language>
        <Ds_CardNumber>454881******0004</Ds_CardNumber>
        <Ds_ExpiryDate>1412</Ds_ExpiryDate>
        <Ds_Merchant_Identifier>7d2076b9fd95f81342bb8e921e66ab61dcb1a6e3</Ds_Merchant_Identifier>
        <Ds_MerchantData></Ds_MerchantData>
        <Ds_Card_Country>724</Ds_Card_Country>
    </OPERACION>
</RETORNOXML>

Con el identificador obtenido haremos la petición:

<DATOSENTRADA>
    <DS_Version>0.1</DS_Version>
    <DS_MERCHANT_AMOUNT>145</DS_MERCHANT_AMOUNT>
    <DS_MERCHANT_ORDER>48173990167</DS_MERCHANT_ORDER>
    <DS_MERCHANT_MERCHANTCODE>329393581</DS_MERCHANT_MERCHANTCODE>
    <DS_MERCHANT_CURRENCY>978</DS_MERCHANT_CURRENCY>
    <DS_MERCHANT_MERCHANTURL>https://pruebaCom.jsp</DS_MERCHANT_MERCHANTURL>
    <DS_MERCHANT_TRANSACTIONTYPE>A</DS_MERCHANT_TRANSACTIONTYPE>
    <DS_MERCHANT_TERMINAL>2</DS_MERCHANT_TERMINAL>
    <DS_MERCHANT_IDENTIFIER>7d2076b9fd95f81342bb8e921e66ab61dcb1a6e3</DS_MERCHANT_IDENTIFIER>
    <DS_MERCHANT_MERCHANTSIGNATURE>46c181da1e81e364f5102b543c8475cc06b3c5d9</DS_MERCHANT_MERCHANTSIGNATURE>
</DATOSENTRADA>

Y obtendremos esta respuesta:

<RETORNOXML>
    <CODIGO>0</CODIGO>
    <Ds_Version>0.1</Ds_Version>
    <OPERACION>
        <Ds_Amount>145</Ds_Amount>
        <Ds_Currency>978</Ds_Currency>
        <Ds_Order>48173990167</Ds_Order>
        <Ds_Signature>9A7C29627B59506E7F42E1709B3707392263A253</Ds_Signature>
        <Ds_MerchantCode>329393581</Ds_MerchantCode>
        <Ds_Terminal>2</Ds_Terminal>
        <Ds_Response>0000</Ds_Response>
        <Ds_AuthorisationCode>990243</Ds_AuthorisationCode>
        <Ds_TransactionType>A</Ds_TransactionType>
        <Ds_SecurePayment>0</Ds_SecurePayment>
        <Ds_Language>1</Ds_Language>
        <Ds_CardNumber>454881******0004</Ds_CardNumber>
        <Ds_Merchant_Identifier>7d2076b9fd95f81342bb8e921e66ab61dcb1a6e3</Ds_Merchant_Identifier>
        <Ds_MerchantData></Ds_MerchantData>
        <Ds_Card_Country>724</Ds_Card_Country>
    </OPERACION>
</RETORNOXML>

Podríamos seguir haciendo peticiones consecutivas con otros importes con la misma referencia y los pagos se realizarian sobre la misma tarjeta.

En los ficheros anexos a esta guía se puede encontrar este ejemplo