martes, 29 de marzo de 2011

Uso de las librerías PayPal (segunda parte)

El objetivo de este documento es explicar el uso de las librerías de la API de PayPal para realizar lo que se llama un sistema de pago ExpressCheckout, el proceso de pago más simple de PayPal.

FLUJO DEL SISTEMA DE PAGO EXPRESSCHECKOUT

Las siguientes ilustraciones explican claramente la diferencia entre los procesos de un sistema de pago habitual y el sistema ExpressCheckout.

Flujo habitual de un sistema de pago





Flujo con ExpressCheckout














Como hemos podido observar, en el flujo de sistema ExpressCheckout el comprador:
  1. Selecciona ‘Express Checkout’ pulsando el botón de PayPal en la web del vendedor.
  2. Inicia sesión en PayPal.
  3. Revisa la transacción en PayPal.
  4. Confirma la orden y paga desde la web del vendedor.
  5. Recibe una orden de confirmación en la web del vendedor.


POSIBILIDADES DE INTEGRACIÓN

Hay dos formas de llevar a cabo este método de pago usando la API de PayPal:

  • A través de NVP (nombre par-valor).
  • A través de SOAP usando los servicios correspondientes

PayPal recomienda el uso del primer método, por lo cual nos vamos a centrar en él.


USANDO LA API DE PAYPAL CON NVP

Como hemos visto en el documento anterior, PayPal ofrece la posibilidad de generar automáticamente el código que necesitamos, con tan solo indicarle una serie de parámetros.

Aunque también es posible escribir por nosotros el código tras leer toda la API y los ejemplos correspondientes, a fin de simplificar este documento, vamos a examinar el código y las librerías generadas por el asistente de PayPal.

NOTA: Recomiendo encarecidamente revisar el código generado por el asistente para Java, puesto que está “cargadito de errores”. Pasé varios días revisando y depurando dicho código. No sucede lo mismo con el código generado en JSP, que aparenta estar bien.

Al final de este blog figura todo el código fuente. Ya sé que el diseño de las páginas es horrible, pero he querido volcarme en la programación y conseguir un código fuente sencillo y fácil de entender. Dedicando un rato se puede conseguir un diseño mucho mejor. Os puedo asegurar que he pasado mucho más tiempo depurando el código erróneo generado por el asistente de PayPal que el que vosotros pasaréis mejorando el diseño gráfico de las páginas.

Bueno, empezamos. Para poder realizar el pago ExpressCheckout usaremos básicamente tres métodos de la API de PayPal:

  • SetExpressCheckout: Configura la transacción, redirige al comprador hacia la web de PayPal para que revise los datos de la transacción, y vuelve a redirigir al comprador a la página web del vendedor para que confirme la compra.
  • GetExpressCheckout: Obtiene de PayPal información acerca del comprador, incluyendo datos de envío.
  • DoExpressCheckoutPayment: Completa la transacción.


I. Pasos previos

1. Seguir los pasos del procedimiento de generación anterior para obtener un usuario, clave y firma.

2. Creamos una página web en la que incluimos el enlace al botón de PayPal del paso 2 del asistente de integración.





3. Cuando el usuario pulsa dicho botón, solo verá que se le redirige a la página web de PayPal para que confirme el pago. Pero, ¿cómo se consigue esto? El botón del asistente dirige hacia 'expresscheckout.java', que es un Servlet en cuyo método principal 'processRequest()' hemos copiado el código generado automáticamente por PayPal.









II. SetExpressCheckout


















Para llamar a SetExpressCheckout hay que proceder así en el código de ‘expresscheckout.java’:

1. Crear un objeto de tipo paypalfunctions.

2. Utilizar dicho objeto para realizar la siguiente llamada:

public HashMap CallShortcutExpressCheckout (paymentAmount, returnURL, cancelURL);

o String paymentAmount: total de la transacción. Formato: ha de contener un punto y dos dígitos decimales. Opcionalmente se admite separador de miles.

o String returnURL: Página web a la que será redirigido el comprador una vez que éste haya entrado en PayPal y aprobado el pago.

o String cancelURL: Página web a la que será redirigido el comprador si éste no aprueba el pago.

Este método se encargará de invocar internamente a SetExpressCheckout. Para ello, tendrá en cuenta un par de variables más que hemos de haber definido previamente:

o String currencyCodeType: Código de la moneda que se está usando. Habitualmente, “EUR” o “USD”.

o String paymentType: Especifica el tipo de pago. Puede ser “Sale”, “Authorization” u “Order”. En nuestro caso, será “Order”.

3. Recoger el resultado en un Hashmap.

a. Si el resultado ha sido satisfactorio (el hashmap contiene la clave “ACK” con el valor “Success”), entonces leemos del hashmap el valor String correspondiente la clave “TOKEN”.

b. Utilizar el objeto de tipo paypalfunctions para invocar a RedirectURL(HttpServletResponse response, String token).

Como vemos, para invocar a dicho método hemos de utilizar como parámetros el response actual y el valor del token que hemos obtenido previamente.

Una vez hecho esto, el navegador dirigirá al comprador automáticamente a la página web de PayPal para que indique los datos del pago.


III. En la web de PayPal

















Ahora tenemos al comprador confirmando en la web de PayPal los detalles de la orden (dirección de envío, teléfono, email, etc). Una vez que confirme dichos datos, el navegador se redireccionará a la página web indicada previamente en la cadena returnUrl, y PayPal habrá colocado como parámetro de respuesta un token (una cadena identificativa de PayPal).


IV. GetExpressCheckout

















Nos situamos ahora en la página web indicada por returnUrl. Nuevamente, se trata de un Servlet en cuyo método principal ‘processRequest()’ hemos colocado el código necesario para poder realizar la llamada a GeteExpressCheckout y obtener la información del comprador necesaria para terminar el proceso de compra.

1. Leemos el token devuelto por la página web de PayPal

String token= request.getParameter("token");

2. Si el valor del token es distinto de null, creamos un objeto de tipo paypalfunctions y lo utilizamos para invocar el método GetShippingDetails incluyendo el token como parámetro.

public HashMap GetShippingDetails(String token)

Este método se encargará de invocar internamente a GetExpressCheckoutDetails.

3. Recogemos en un HashMap el resultado de invocar al método. Allí podemos obtener toda la información que necesitamos acerca del comprador a medida que invocamos al método get() del HashMap con la clave apropiada (ejemplo: String payerId = nvp.get("PAYERID").toString();

o EMAIL: Dirección de correo electrónico del comprador.

o PAYERID: Número de identificación de la cuenta del cliente de PayPal.

o PAYERSTATUS: Estado del comprador.

o SALUTATION: Saludo del comprador.

o FIRSTNAME: Nombre del comprador.

o MIDDLENAME: Segundo nombre del comprador.

o LASTNAME: Apellidos del comprador.

o SUFFIX: Sufijo del comprador.

oCOUNTRYCODE: Código del país de residencia en formato ISO standard 3166 de dos caracteres.

o BUSINESS: Nombre de la empresa del comprador.

o SHIPTONAME: Nombre y apellidos del destinatario del envío.

o SHIPTOSTREET: Dirección del envío (principal).

o SHIPTOSTREET2: Dirección del envío (alternativa).

o SHIPTOCITY: Ciudad a la que se envía.

o SHIPTOSTATE: Estado (para otros países) o provincia (España) del envío.

o SHIPTOCOUNTRYCODE: Código del país al que se envía.

o SHIPTOZIP: Código postal.

o ADDRESSSTATUS: Estado de la dirección en la base de datos de PayPal.

o INVNUM: Su propio número de factura o de seguimiento, según lo establecido en el elemento del mismo nombre en la solicitud de 'SetExpressCheckout'.

o PHONENUM: Número de teléfono de contacto del comprador. Nota: PayPal devuelve un número de teléfono de contacto sólo si la configuración del perfil de cuenta del vendedor requiere que el comprador lo introduzca.

4. Ahora tan solo nos queda presentar estos datos en pantalla junto a un botón de confirmación que redirija al cliente a una nueva página en la que se presente el resultado del pago.

Nota importante: Algunos de estos campos son retornados como null, por lo que aconsejo el uso del operador ternario a fin de poder presentarlos en pantalla sin errores.

Ejemplo:

String invoiceNumber=(nvp.get("INVNUM")==null)?"": nvp.get("INVNUM").toString();


V. DoExpressCheckoutPayment

















Si el cliente ha confirmado la compra, lo redirigimos a la página final en la que presentamos los datos del pago. Nuevamente, estamos en un Servlet en cuyo método principal processRequest() colocamos el código para efectuar las siguientes acciones:

1. Leo las variables de serverName, payerId, finalPaymentAmount y token (estas tres últimas son variables de sesión asignadas en la página anterior).

o String serverName = request.getServerName();

o String payerId = (String) session.getAttribute("payerId");

o String finalPaymentAmount = (String) session.getAttribute("Payment_Amount");

o String token = (String) session.getAttribute("token");

2. Creo un objeto de tipo paypalfunctions y lo utilizo para invocar el método

public HashMap ConfirmPayment(String token, String payerID, String finalPaymentAmount, String serverName);

Al invocarlo, hemos usado como parámetros las variables leídas anteriormente. Este método se encarga internamente de llamar a DoExpressCheckoutPayment.

3. Recojo el resultado en un HashMap. Si el resultado ha tenido éxito, (el hashmap contiene la

clave “ACK” con el valor “Success”), entonces leemos del hashmap el resto de valores que recogen el resultado final de la operación. Las claves para acceder a dichos valores son las siguientes cadenas:

o TRANSACTIONID: Identificador único de la transacción del pago. Nota: Si el atributo ‘PaymentAction’ de la solicitud fue ‘Autorization’ u ‘Order’, este valor es su AuthorizationID para su uso con las APIs de autorización y captura.

o TRANSACTIONTYPE: Tipo de transacción. Los valores posibles son: ‘cart’ y ‘express-checkout’.

o PAYMENTTYPE: Indica si el pago es inmediato o demorado. Los valores posibles son: ‘none’, ‘echeck’, ‘instant’.

o ORDERTIME: Hora y fecha de pago.

o AMT: El importe final del cargo, incluidos los gastos de envío y los impuestos indicados en su perfil de vendedor.

o CURRENCYCODE: Código del tipo de moneda en formato de tres caracteres indicado en el listado de monedas de PayPal (por defecto: USD).

o FEEAMT: Tasa que cobra PayPal por la operación.

o SETTLEAMT: Cantidad depositada en su cuenta PayPal después de la conversión de moneda.

o TAXAMT: Impuesto cobrado por la transacción.

o EXCHANGERATE: Tipo de cambio si se produjo una conversión de moneda. Es relevante sólo si se está facturando en su moneda no primaria. Si el cliente opta por pagar con una moneda distinta de la moneda no primaria, la conversión se produce en la cuenta del cliente.

o PAYMENTSTATUS: Estado del pago:

- completed (completado): El pago se ha completado, y los fondos se han añadido con éxito a su cuenta.

- pending (pendiente): El pago está en espera. Consultar el elemento ‘PendingReason’ para más información.

o PENDINGREASON: Indica la razón por la que el pago está pendiente:

- none: No hay ninguna razón.

- address (dirección): El pago está pendiente debido a que el comprador no ha incluido una dirección de envío confirmada, y las preferencias de recepción de pago del vendedor están configuradas de tal manera que el vendedor puede aceptar o rechazar manualmente cada uno de los pagos. Para cambiar las preferencias del vendedor hay que acudir a la sección de preferencias del perfil.

- echeck (cheque electrónico): El pago está pendiente porque fue realizado mediante un cheque electrónico que aún no ha sido aprobado

- intl (internacional): El pago está pendiente porque el vendedor tiene una cuenta fuera de Estados Unidos y no posee un mecanismo de retirada. Debe aceptar o rechazar el pago manualmente desde la web de PayPal (‘Account Overview’).

- multi-currency (multi-moneda): El vendedor no tiene saldo en la moneda enviada, y no tiene configurada las preferencias de recepción de pago para convertir y aceptar este pago automaticamente. Debe aceptar o rechazar el pago de manera manual.

- verify (verificar): El pago está pendiente, porque su cuenta (vendedor) aún no está verificada. Debe verificar su cuenta antes de poder aceptar este pago.

- other (otros): El pago está pendiente, por causas distintas de las enumeradas anteriormente. Para obtener más información, contacte con el servicio de atención al cliente de PayPal.

o REASONCODE: Razón para la revocación, si el elemento ‘TransactionType’ es ‘reversal’ (revocación):

- none (ninguno): no hay código.

- chargeback (cargo): Ha tenido lugar una revocación de esta operación debido a una devolución del cargo por parte del comprador.

- guarantee (garantía): Ha tenido lugar una revocación de esta operación debido a que el comprador ha invocado la devolución en tiempo de garantía ofrecida por el vendedor.

- buyer-complaint (queja del comprador): Ha tenido lugar una revocación de esta operación debido a una queja del comprador con respecto a la transacción.

- refund (devolución): Ha tenido lugar una revocación de esta operación debido a que el vendedor ha reembolsado su dinero al cliente.

- other (otros): Ha tenido lugar una revocación de esta operación debido a razones no indicadas anteriormente.

Nota importante: Algunos de estos campos son retornados como null, por lo que aconsejo el uso del operador ternario a fin de poder presentarlos en pantalla sin errores.

Ejemplo:

String invoiceNumber = (nvp.get("TRANSACTIONID")==null)? "": nvp.get("TRANSACTIONID").toString();


No hay comentarios:

Publicar un comentario