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

31 de agosto de 2018

Este tutorial es la segunda 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.

Definiendo los detalles del pago

El segundo argumento obligatorio del constructor del objeto PaymentRequest es un objeto con los detalles del pago. Este objeto contiene obligatoriamente el total a pagar y, opcionalmente, un array con el detalle del pago (subtotal, impuestos, descuentos, etc.)

Total a pagar

El total a pagar se define con una etiqueta o título y una cantidad de dinero (que incluye la divisa). Por ejemplo:

const paymentDetails = {
  total: {
    label: 'Total',
    amount: {
      currency: 'USD',
      value: '0',
    },
  },
};

new PaymentRequest(supportedPaymentMethods, paymentDetails, options);

Esta información se muestra en la sección "Order Summary" de la pantalla que se muestra al usuario:

Ejemplo sencillo de cómo se muestra el total a pagar

El título o etiqueta es una cadena de texto elegida libremente, pero la divisa debe ser un código válido de acuerdo con el estándar ISO 4217. Este otro ejemplo modifica alguno de estos valores:

const paymentDetails = {
  total: {
    label: 'Purchase Amount',
    amount: {
      currency: 'GBP',
      value: '24.99',
    },
  },
};

Y así se mostraría este ejemplo al usuario:

Ejemplo sencillo de cómo se muestra el total a pagar

Detalles del pago

Esta opción se puede usar para detallar cómo se ha obtenido el total a pagar. Normalmente estos detalles incluyen el subtotal, los impuestos, los descuentos, los gastos de envío, etc.

Este objeto debe ser un array de elementos y cada uno de ellos debe usar el mismo formato que el total (título o etiqueta y cantidad con divisa).

const allDisplayItems = [
  {
    label: 'Subtotal',
    amount: {
      currency: 'USD',
      value: 10,
    },
  }, {
    label: 'Discount (10%)',
    amount: {
      currency: 'USD',
      value: -1,
    },
  }, {
    label: 'Tax',
    amount: {
      currency: 'USD',
      value: 0.68,
    },
  },
];

const paymentDetails = {
  total: {
    label: 'Total',
    amount: {
      currency: 'USD',
      value: 0,
    },
  },
  displayItems: allDisplayItems,
};

Y así se vería este ejemplo en el navegador:

Detalles del pago a realizar

Cosas que debes tener en cuenta:

  • El orden en el que defines los contenidos de displayItems es importante porque es el mismo orden en el que se muestran al usuario.
  • El objeto displayItems no está pensado para mostrar un listado largo con todos los objetos o servicios comprados. Utilízalo solamente para mostrar el resumen general del pedido (subtotal, impuestos, descuentos, etc.)
  • La API "Payment Request" no suma los contenidos del detalle del pago para comprobar que el total sea correcto. El navegador solamente muestra la información que le pasas.

Si algún detalle del pago no está definido todavía (por ejemplo, el coste de envío no se sabe porque el usuario todavía no ha indicado la dirección) utiliza el parámetro pending para indicar que está pendiente.

const transactionDisplayItems = [
  {
    label: 'Total cost of goods',
    amount: {
      currency: 'USD',
      value: 10,
    },
  }, {
    label: 'Tax',
    pending: true,
    amount: {
      currency: 'USD',
      value: 0.75,
    },
  },
];

Los gastos pendientes se muestran con un tipo de letra más pequeño y más claro:

Ejemplo de un detalle de pago marcado como pendiente

Posibles errores

Títulos demasiado largos

Actualmente los navegadores no recortan el título de total, por lo que debes tener cuidado con su longitud. Los títulos de los detalles de pago sí que se recortan automáticamente.

Ejemplo de títulos muy largos

Total no indicado

El parámetro total es obligatorio, por lo que si no lo indicas, verás el siguiente error:

TypeError: Failed to construct 'PaymentRequest': Must specify total

No incluir el título, cantidad o divisa

Si no incluyes alguna de estas propiedades en el total o en los detalles del pago, verás los siguientes errores:

// Si no indicas el título
'PaymentRequest': required member label is undefined.

// Si no indicas la cantidad
'PaymentRequest': required member amount is undefined.

// Si no indicas la divisa
'PaymentRequest': required member currency is undefined.

// Si no indicas el valor
'PaymentRequest': required member value is undefined.

Totales negativos (devoluciones)

La API "Payment Request" no soporta cantidades totales negativas (que normalmente se utilizan para hacer devoluciones). Si indicas un valor negativo, verás el siguiente error:

'PaymentRequest': Total amount value should be non-negative

Divisas no válidas

La divisa se debe indicar como un código válido de tres letras en mayúscula. Si no lo haces así, verás el siguiente error.

'PaymentRequest': '...' is not a valid ISO 4217 currency code,
should be 3 upper case letters [A-Z]

De hecho, puedes pasar cualquier valor de tres letras mayúsculas y se considerará una divisa válida. Esto se ha hecho así para soportar divisas definidas en el futuro, como por ejemlo las criptomonedas. Así que si aceptas pagos en Bitcoins, deberías usar XBT como código.

Cuando se utilizan divisas válidas, el navegador muestra su símbolo junto a la cantidad. Para el resto de divisas, solamente se muestra su código:

Comparativa de pago con dólares americanos y bitcoins

Múltiples divisas

Actualmente los navegadores no soportan los pagos en múltiples divisas, por lo que si intentas hacerlo, verás este error:

DOMException: Request cancelled

Formato de la cantidad a pagar

El parámetro value puede ser una cadena de texto además de un número. Si utilizas una cadena, solo puede contener números y un solo punto para indicar los decimales. Si no, verás el siguiente error:

'PaymentRequest': '...' is not a valid amount format

Por ejemplo, 1,000.00 no es válido por la coma que separa los miles, pero 1000.00 sí que es válido.

Escritura de derecha a izquierda

Si indicas los títulos en algún idioma que escribe de derecha a izquierda (árabe, hebreo, etc.) se mostrarán correctamente. El resto de contenidos de la página se mostrarán de acuerdo a las opciones del navegador y del sistema operativo.

Definiendo opciones adicionales

El tercer argumento opcional del constructor de PaymentRequest es un objeto que define qué información adicional quieres solicitar al usuario, tales como su nombre, email, teléfono, etc. Se recomienda pedir solo lo que realmente necesitas, ya que si no, se alarga el proceso de compra innecesariamente.

Para solicitar solamente el nombre, teléfono y email, define lo siguiente:

const options = {
  requestPayerName: true,
  requestPayerPhone: true,
  requestPayerEmail: true,
};

Por defecto todas estas opciones valen false. Si devuelves true para alguna de ellas, el navegador mostrará un paso adicional durante la compra:

Solicitud de información adicional durante el pago

Si el navegador ya dispone de la información solicitada, se muestra directamente y el usuario puede cambiarla si quiere:

Información extra rellenada automáticamente por el navegador

Cosas a tener en cuenta:

  • El valor de los parámetros requestPayerName, requestPayerPhone y requestPayerEmail debe ser booleano. Si pasas otro tipo de valor, se harán las conversiones automáticas de JavaScript (null, undefined y 0 se consideran false, mientras que los demás valores, incluyendo {} y [], se consideran true).