Payment Request API, el nuevo estándar para pagos en Internet (tercera parte)

3 de septiembre de 2018

Este tutorial es la tercera parte de la siguiente serie de tutoriales que explica el funcionamiento práctico de la nueva API llamada Payment Request para hacer pagos en Internet:

  • Primera parte: introducción general y cómo definir las formas de pago disponibles.
  • Segunda parte: cómo mostrar los detalles del pago y solicitar información al usuario.
  • Tercera parte: cómo completar (o cancelar) el proceso de pago.
  • Cuarta parte: cómo solicitar la dirección y forma de envío.

Respondiendo a PaymentRequest.show()

Después de llamar al método show(), el navegador muestra al usuario todos los detalles del pago para iniciar el proceso. Los usuarios tienen dos opciones: ignorar esa información y no completar o rellenar la información solicitada y pulsa el botón "Pagar".

Si el usuario rellena la información correctamente, la promesa devuelta por show() se resuelve,. Si no, la promesa se rechaza:

paymentRequest.show()
.then((paymentResponse) => {
  // el usuario ha rellenado la información solicitada y ha realizado
  // el pago. Obtener los detalles de `paymentResponse` para completar el pago
  return paymentResponse.complete();
})
.catch((err) => {
  // hay un error o el usuario ha rechazado el pago
});

Cuando el pago se completa, la promesa show() recibe un objeto de tipo PaymentResponse que contiene la información del usuario que debes enviar al sistema de procesamiento de pagos que utilices.

Propiedades de PaymentResponse

El objeto PaymentResponse contiene los siguientes parámetros:

Parámetro Explicación
methodName Método de pago seleccionado por el usuario (por ejemplo basic-card)
details Contiene los detalles del pago, que dependen de la forma de pago seleccionada. Se explica más adelante con detalle.
payerName Nombre del pagador, que será null a menos que hayas definido requestPayerName a true
payerPhone Teléfono del pagador, que será null a menos que hayas definido requestPayerPhone a true
payerEmail Email del pagador, que será null a menos que hayas definido requestPayerEmail a true
Shipping Info Información sobre la forma de envío. Se explica más adelante con detalle.

Para los pagos de tipo basic-card, los detalles están estandarizados y siempre son billingAddress, cardNumber, cardSecurityCode, cardholderName, expiryMonth y expiryYear. Cuando se utilizan servicios de terceros como Google Pay, los detalles serán los que defina cada servicio en su documentación.

Una vez obtenidos los detalles mediante el objeto PaymentResponse, ya puedes procesar el pago y completar la transacción llamando al método paymentResponse.complete().

Completando la transacción

Una vez que la promesa de show() se ha resuelto, el navegador muestra una imagen animada indicando que se está a la espera de completar el pago. Puedes dejar esta animación visible o puedes ocultarla y utilizar tu propio diseño para esta pantalla de espera:

Posibles alternativas después de que la promesa show() se ha resuelto

Si quieres ocultar la animación inmediatamente, llama al método PaymentResponse.complete().

paymentRequest.show()
.then((paymentResponse) => {
  // cerrar la pantalla de espera
  return paymentResponse.complete()
  .then(() => {
    // TODO: obtener detalles del pago mediante el objeto paymentResponse
    // TODO: procesa pago
  });
})
.catch((err) => {
  console.error('Payment Request API error: ', err);
});

Ejecutar el método complete() sin argumentos es equivalente a ejecutar paymentResponse.complete('unknown'). En otras palabras, al navegador le estás diciendo que no considere el pago ni como completado ni como erróneo, por lo que no se muestra ninguna pantalla de espera.

Si quieres mantener la pantalla de espera mientras se completa el pago, no ejecutes complete() todavía. Imaginemos que tienes un método llamado validatePaymentWithBackend() que comprueba el pago realizando llamadas a tu servidor y que devuelve una promesa que se resuelve como un valor booleano (true si el pago se ha completado y false en cualquier otro caso). En este caso, la pantalla de espera se mantendría y la llamada a complete() se haría cuando esta nueva promesa se resuelva:

paymentRequest.show()
.then((paymentResponse) => {
  return validatePaymentWithBackend(paymentResponse)
  .then((success) => {
    if (success) {
      return paymentResponse.complete('success');
    } else {
      return paymentResponse.complete('fail');
    }
  });
})
.catch((err) => {
  // hay un error o el usuario ha cancelado el pago
});

En este ejemplo se utilizan las cadenas success y fail para indicar al navegador el estado del pago. Estos valores son estándar y el navegador los usa para mostrar al usuario si el pago se ha completado con éxito o si ha fallado:

Ejemplo de intento de pago que ha resultado en un error

Cosas a tener en cuenta

Devolver un resultado propio

Si no devuelves alguno de los valores definidos en el estándar (unknown, success o fail) la promesa devuelta por complete() rechaza el pago y te devolverá un error como el siguiente:

Failed to execute 'complete' on 'PaymentResponse': The provided value '...' is
not a valid enum value of type PaymentComplete.

Completar los pagos rápido

Si no llamas al método complete() en un tiempo razonable, el navegador considera que la transacción ha caducado y cerrará la pantalla de pago. Además, se avisará al usuario de que ha habido un problema con el pago.

Cancelando la transacción

Utiliza el método abort() para cancelar la transacción actual (porque ha expirado la sesión, porque el producto que se quiere comprar acaba de agotarse, etc.)

paymentRequest.show()
.catch((err) => {
  console.error('PaymentRequest error: ', err);
});

setTimeout(() => {
  paymentRequest.abort()
  .then(() => {
    // La transacción se ha cancelado correctamente
    // TODO: mostrar un mensaje avisando al usuario
  })
  .catch((err) => {
    // No se puede cancelar la transacción
    console.log('abort() Error: ', err);
  });
}, 4000);

En el ejemplo anterior, si se deja la ventana del pago visible, la promesa show() se cancela con el siguiente error:

DOMException: The user aborted a request.

La promesa devuelta por abort() permite comprobar si la cancelación se ha completado correctamente o no. La cancelación de la transacción podría fallar por ejemplo si el usuario cierra la ventana del pago o si el pago se ha completado mientras se intentaba anular.