Esta es una traducción que desde EGA Futura ofrecemos como cortesía a toda la Ohana y comunidad de programadores , consultores , administradores y arquitectos de Salesforce para toda Iberoamérica .

El enlace a la publicación original, lo encontrarás al final de este artículo.

Uno de los aspectos más importantes de cualquier proyecto de comercio electrónico es la experiencia de pago. B2B Commerce on Lightning Experience, construido sobre la plataforma Salesforce, proporciona un rico conjunto de funciones con múltiples opciones para integrar pagos en el proceso de compra. En esta publicación de blog, nos centraremos en cómo crear e integrar una solución de pago personalizada para su tienda B2B utilizando Apex, Lightning Web Components y Flow.

Entender el flujo de pago

Es posible que tenga experiencia de primera mano con un flujo de pago. Cuando visita una tienda en línea y hace clic en "Pagar", a menudo se lo dirigirá al proveedor de servicios de pago del proveedor. Una vez que haya pagado, será redirigido a la tienda del proveedor. Esto es lo que crearemos para el comercio B2B en Lightning Experience.

El primer paso es integrarse con el proveedor de servicios de pago de su elección, que ofrece una página de pago externa y alojada (HPP) donde el comprador será redirigido para ingresar sus detalles de pago. En un nivel alto, el flujo de pago funciona así:

  1. Cree una redirección a la página de pago alojada.
  2. Después de que el cliente seleccione el método de pago apropiado e ingrese los detalles de pago en el HPP, habilite un redireccionamiento a su tienda B2B.
  3. Maneje la respuesta del proveedor de pago, que puede resultar en una autorización de pago o un error.
  4. Refleje los estados de pago en el comercio B2B para poder proporcionarlos a un ERP u otro sistema más adelante.

B2B Commerce en Lightning Experience proporciona una variedad de flujos de pago listos para usar. Para esta publicación de blog, no nos centraremos en esos flujos específicos. En cambio, adoptaremos un enfoque agnóstico.

Acceda a la página de pago alojada con LWC y Apex

La primera tarea es dirigir al comprador a la página de pago alojada. Como ya habrá adivinado, no es solo un componente web Lightning simple el que puede lograr este lado del cliente. También involucra a Apex, que habla con el proveedor de pagos y envía los resultados dados. El flujo se ve así:

  1. El comprador inicia el pago a través de un componente web Lightning.
  2. El componente invoca un método Apex.
  3. El método Apex se comunica con el proveedor de servicios de pago y comunica los resultados al componente web Lightning.

Primero echaremos un vistazo al método Apex. Para almacenar configuraciones y parámetros para la página de pago alojada, utilizamos metadatos personalizados . Se hace referencia a ellos como MerchantConfig todo el código.

El método de Apex initializePaymentPage es un extracto que muestra que se inicia una solicitud al proveedor de servicios de pago. Tras una respuesta exitosa, el proveedor devuelve la URL para redirigir a la página de pago alojada. Además, el objeto WebCart se modifica para indicar que el carrito se encuentra actualmente en un estado de redireccionamiento. Al regresar a la caja, esto se puede usar para reiniciar la caja en el estado correcto.

 @AuraEnabled (Cacheable = false)
public static Map <String, String> initializePaymentPage (String cartId, String comercianteConfig) { Map <String, String> resultMap = new Map <String, String> (); // Recupera la configuración de Merchang MerchantAccount__mdt config = getMerchantConfig (comercianteConfig); Carrito de Webcart = [SELECT ID, GrandTotalAmount FROM Webcart WHERE Id =: cartId LIMIT 1]; String currentRequestURL = URL.getCurrentRequestUrl (). GetProtocol (); + ': //' + URL.getCurrentRequestUrl (). GetHost (); // Crea una solicitud para el proveedor de pagos // .... // Crea URL de devolución para el pago proporcionado returnUrls.Success = currentRequestURL + '/' + config.successURL__c + '/' + cartId; returnUrls.Fail = currentRequestURL + '/' + config.errorURL__c + '/? recordId =' + cartId + '& paymentState = error'; // Crea la solicitud HTTP para el proveedor de pagos // ... HttpResponse httpResponse = http.send (req); // Resultado exitoso almacenar esto como método de pago con tarjeta if (httpResponse.getStatusCode () == 200) { // Desezerializar la respuesta PaymentVO.InitPaymentResponse paymentMethodsResponse = (PaymentVO.InitPaymentResponse) JSON.deserialize (httpResponse.getBody (), PaymentVO.InitPaymentResponse.class); CardPaymentMethod cpm = nuevo CardPaymentMethod (); cpm.Status = 'Activo'; // Almacenar más información en CardPaymentMethod insertar cpm; cart.PaymentMethodId = cpm.ID; cart.CartHandling__c = 'Redirigir'; actualización de la compra; resultMap.put ('Éxito', 'verdadero'); // Almacene la URL de redireccionamiento para el componente LWC resultMap.put ('RedirectUrl', paymentMethodsResponse.RedirectUrl); } demás { resultMap.put ('Éxito', 'falso'); } return resultMap; }

El componente web Lightning invoca el método Apex con la información del carrito y del comerciante. Y en el caso de una respuesta exitosa, utiliza el RedirectURL para redirigir al cliente.

 importar {api, LightningElement} de 'lwc';
importar initializePaymentPage desde '@ salesforce / apex / PaymentService.initializePaymentPage'; exportar clase predeterminada PaymentExampleLWC extiende LightningElement { @api cartId; @api comercianteConfig; async initializePayment () { let paymentInitResponse = await initializePaymentPage ({ cartId: this.cartId, comercianteConfig: this.merchantConfig }); // redirigimos a la URL de éxito (página de pago alojada) if (paymentInitResponse.Success && paymentInitResponse.RedirectUrl) { window.location = paymentInitResponse.RedirectUrl; } }
}

Veamos cómo se vería esto (de una manera muy simplificada) usando un flujo. Si no hay una redirección pendiente, el cliente deberá ser redirigido a la página de pago alojada por primera vez. De lo contrario, si ya hay una redirección pendiente, podemos asumir con seguridad que el comprador ha sido redirigido desde la página de pago a la tienda B2B. En ese caso, podemos procesar la transacción de pago para la creación del pedido.

Ahora que analizamos cómo crear un flujo de pago, veamos cómo autorizar sus pagos mediante un adaptador de pasarela de pago.

Autorizar pagos mediante un adaptador de pasarela de pago

Para encargarnos de autorizar la llamada de pago, usaremos un adaptador de pasarela de pago (que veremos con más detalle más adelante). Primero, necesitamos configurar la pasarela de pago para su tienda siguiendo las instrucciones de Configuración de pago .

Pasarela de pago: el pegamento para nuestra integración

Los adaptadores de pasarela de pago representan la integración entre su plataforma de pago en Salesforce y una pasarela de pago externa (consulte la documentación de pago B2B ). Para nuestras necesidades, la pasarela de pago es el punto central de la plataforma Salesforce para integrarse con cualquier tipo de proveedor de pago. El repositorio de inicio rápido de B2B LE proporciona buenos ejemplos sobre cómo escribir su propio adaptador de pasarela de pago . Recomendamos comprobarlos cuando cree su propia implementación, ya que proporcionan un buen punto de partida.

Invocación y contexto de la pasarela de pago

Como queremos integrar la comunicación con la pasarela de pago en nuestro flujo, primero crearemos un nuevo InvocableMethod . Este método obtiene la información relevante de la pasarela e inicia la autorización con la pasarela utilizando la API de pago .

 public class AuthorizeTokenizedPayment { @InvocableMethod (callout = true label = 'Autorizar pago con token' description = 'Autoriza el pago de información crediticia que se tokenizó previamente' categoría = 'Comercio') Public static List <String> authorizePaymentInfo (List <AuthorizeTokenizedPaymentRequest> solicitud) { String cartId = solicitud [0] .cartId; Carrito web = [SELECT WebStoreId, GrandTotalAmount, AccountId, PaymentMethodId FROM WebCart DONDE Id =: cartId]; String paymentGatewayId = [SELECT Integration FROM StoreIntegratedService DONDE ServiceProviderType = 'Payment' AND StoreId =: cart.WebStoreId] .Integration; ConnectApi.AuthorizationRequest authRequest = new ConnectApi.AuthorizationRequest (); ConnectApi.AuthApiPaymentMethodRequest authApiPaymentMethodRequest = new ConnectApi.AuthApiPaymentMethodRequest (); authApiPaymentMethodRequest.Id = cart.PaymentMethodId; authRequest.accountId = cart.AccountId; authRequest.amount = cart.GrandTotalAmount; authRequest.paymentGatewayId = paymentGatewayId; authRequest.paymentMethod = authApiPaymentMethodRequest; authRequest.paymentGroup = getPaymentGroup (cartId); // Llamar a processRequest en el PaymentGatewayAdapter ConnectApi.AuthorizationResponse authResponse = ConnectApi.Payments.authorize (authRequest) // .... }
}

La API de pagos proporciona varios métodos, como authorize o capture , como puede ver con la invocación de ConnectApi.Payments.authorize(authRequest) en el fragmento de código anterior. Siempre que se invoca uno de los métodos de la API de pagos, automáticamente llama a un método processRequest A medida que implementamos nuestra propia pasarela de pago, tenemos que proporcionar ese método nosotros mismos.

Los siguientes ejemplos simplificados muestran cómo puede implementar processRequest . En la invocación, el contexto de la pasarela de pago seleccionada se pasa a través del objeto PaymentGatewayContext

 global con clase de uso compartido MyPaymentGatewayAdapter implementa CommercePayments.PaymentGatewayAdapter { global CommercePayments.GatewayResponse processRequest (CommercePayments.paymentGatewayContext gatewayContext) { CommercePayments.RequestType requestType = gatewayContext.getPaymentRequestType (); if (requestType == CommercePayments.RequestType.Authorize) { // Manejar autorizar } else if (requestType == CommercePayments.RequestType.Capture) { // Manejar captura } demás { // Otros tipos de solicitud } devolver nulo; }
}

El siguiente código proporciona un ejemplo de cómo crear una autorización con el proveedor de servicios de pago de su elección. Lo llamaría cuando el tipo de solicitud de pago sea CommercePayments.RequestType.Authorize como se muestra en el ejemplo anterior.

Es importante comprender que estamos interactuando dentro del contexto de la pasarela de pago y, por lo tanto, proporcionamos una funcionalidad HttpCallout especial lista para usar que está diseñada para pasarelas de pago: CommercePayments.PaymentsHttp() . Esto automáticamente hace referencia a las credenciales con nombre adjuntas a su PaymentGatewayProvider . Además, crea el PaymentAuthorization PaymentAuthorization y adjunta todos los detalles necesarios.

 CommercePayments.GatewayResponse estático privado handleAuthorization (CommercePayments.paymentGatewayContext gatewayContext) { CommercePayments.AuthorizationRequest commerceAuthRequest = (CommercePayments.AuthorizationRequest) gatewayContext.getPaymentRequest (); CommercePayments.AuthApiPaymentMethodRequest authPaymentMethod = commerceAuthRequest.paymentMethod; String paymentMethodId = authPaymentMethod.Id; CardPaymentMethod paymentMethod = [SELECT ID, GatewayToken, PaymentConfiguration__c FROM CardPaymentMethod WHERE ID =: paymentMethodId]; HttpRequest req = PaymentUtils.buildRequest (método de pago); CommercePayments.PaymentsHttp http = new commercepayments.PaymentsHttp (); HttpResponse res = http.send (req); if (res.getStatusCode () == 200) { CommercePayments.AuthorizationResponse commerceResponse = new CommercePayments.AuthorizationResponse (); PaymentVO.PaymentAssertResponse paymentAssertResponse = (PaymentVO.PaymentAssertResponse) JSON.deserialize (resBody, PaymentVO.PaymentAssertResponse.class); commercepayments.PaymentMethodTokenizationResponse paymentMethodTokenizationResponse = new CommercePayments.PaymentMethodTokenizationResponse (); commerceResponse.setGatewayResultCode (paymentAssertResponse.Transaction_x.ApprovalCode); commerceResponse.setGatewayReferenceNumber (paymentAssertResponse.Transaction_x.Id); commerceResponse.setSalesforceResultCodeInfo (SUCCESS_SALESFORCE_RESULT_CODE_INFO); return commerceResponse; } demás { CommercePayments.AuthorizationResponse commerceResponse = new CommercePayments.AuthorizationResponse (); PaymentVO.PaymentErrorResponse paymentErrorResponse = (PaymentVO.PaymentErrorResponse) JSON.deserialize (res.getBody (), PaymentVO.PaymentErrorResponse.class); String errorName = paymentErrorResponse.ErrorName; CommerceResponse.setSalesforceResultCodeInfo (DECLINE_SALESFORCE_RESULT_CODE_INFO); CommercePayments.GatewayErrorResponse error = nuevo CommercePayments.GatewayErrorResponse (String.valueOf (res.getStatusCode ()), paymentErrorResponse.ErrorName); retorno de error; }
}

Volviendo a nuestro flujo simplificado, podemos verificar, dependiendo del manejo del carrito, si necesitamos llamar al redireccionamiento a la página de pagos alojada o si podemos proceder con la autorización de pago.

Manejo de estados de pago y creación de redireccionamientos personalizados

Con el manejo de pagos, una de las cosas a considerar es una respuesta de pago fallida. Como habrá notado a lo largo de este artículo, proporcionamos una URL de error para el proveedor de servicios de pago.

 returnUrls.Fail = currentRequestURL + '/' + config.errorURL__c + '/? recordId =' + cartId + '& paymentState = error';

Hagámoslo más real y redirigamos al cliente a una página de carrito después de que se denegó el pago. Nuestra URL de error se vería así:

 returnUrls.Fail = 'https: // <yourdomain> / MyShop / s / <nombre de la página de experiencia> / <nombre del flujo> +' /? recordId = '+ cartId +' & paymentState = error ';

Para mostrar la página del carrito, creamos un nuevo flujo (en este caso, un flujo de pantalla). Este flujo manejará los errores / respuestas de pago no exitosas que pueden ocurrir durante la transacción de pago.

Verá que proporcionamos una pantalla de redireccionamiento al final del flujo. En esta pantalla, estamos incorporando otro componente web Lightning personalizado. El código JavaScript a continuación muestra que este componente está enviando al cliente a la página de resultado de error correspondiente (en nuestro caso, la página del carrito).

 importar {LightningElement, api} de 'lwc';
importar {NavigationMixin} de 'relámpago / navegación'; exportar clase predeterminada PaymentRedirect extiende NavigationMixin (LightningElement) { @api recordId; @api pageName; @api objectApiName; connectedCallback () { este [NavigationMixin.Navigate] ({ tipo: 'standard__recordPage', atributos: { recordId: this.recordId, objectApiName: this.objectApiName, actionName: 'vista' }, Expresar: { paymentState: 'error' } }); }
}

Para activar el flujo, que comienza al recibir un error del proveedor de servicios de pago, necesitaremos proporcionar un punto de entrada común. Por lo tanto, estamos agregando el flujo de pantalla creado a una página "Redirigir" recién creada en Experience Builder . Tan pronto como se carga la página, se inicia el flujo.

Como puede personalizar las URL para sitios de experiencias, puede crear URL agradables y legibles por humanos, como esta:

https://<your url>/MyShop/s/<name of the experience page>/<name of the flow>

Conclusión

La integración de pagos en nuestra tienda B2B es realmente sencilla con las herramientas de Comercio B2B en Lightning Experience. Cuando se utilizan las API proporcionadas, la plataforma se encarga de proporcionar todos los sObjects relevantes y los adjunta durante todo el proceso de pago. Las pasarelas de pago brindan un marco poderoso que le permite conectar sin problemas sus pagos al proceso de pago de la tienda y le permite ejecutarlos en cualquier paso de pago necesario. Al combinar Apex, Lightning Web Components y Flow, puede ir más allá del mecanismo predeterminado proporcionado y adaptar la experiencia de pago a los requisitos de su organización.

Sobre el Autor

Christoph Hallmann es arquitecto técnico sénior del equipo de prestación de servicios profesionales. Es responsable de las implementaciones con Salesforce B2B / B2C Commerce Cloud y la gestión de pedidos de Salesforce.

Esta es una traducción realizada por EGA Futura, y este es el link a la publicación original: https://developer.salesforce.com/blogs/2021/12/integrate-payments-into-a-b2b-commerce-store-with-ease.html

Entradas recomendadas