|
| 1 | +--- |
| 2 | +title: Checkout gateway |
| 3 | +date: 2024-04-01 |
| 4 | +area: checkout |
| 5 | +tags: [checkout, app, payment, shipping, cart] |
| 6 | +--- |
| 7 | + |
| 8 | +# Checkout gateway |
| 9 | + |
| 10 | +::: info |
| 11 | +This document represents an architecture decision record (ADR) and has been mirrored from the ADR section in our Shopware 6 repository. |
| 12 | +You can find the original version [here](https://github.com/shopware/shopware/blob/trunk/adr/2024-04-01-checkout-gateway.md) |
| 13 | +::: |
| 14 | + |
| 15 | +# ADR: Enhanced Checkout Gateway Feature |
| 16 | +## Context |
| 17 | +In response to the evolving landscape of checkout decision-making, we propose the introduction of a centralized and opinionated solution. |
| 18 | +This solution aims to facilitate informed decisions during the checkout process based on both the cart contents and the current sales channel context. |
| 19 | +The app-system, in particular, stands to benefit significantly, enabling seamless communication with the app server. |
| 20 | +Presently, achieving such functionality is constrained to app scripts, limiting the capacity for making nuanced decisions during checkout based on app server logic. |
| 21 | + |
| 22 | +Moreover, payment and shipping providers necessitate specific criteria for determining the availability of their respective methods. |
| 23 | +These criteria include considerations such as risk assessment related to the current customer and cart, unavailability criteria, |
| 24 | +merchant connection status validation (e.g., checking for correct credentials), and service availability testing (e.g., detecting provider outages). |
| 25 | +Additionally, these providers require the ability to block carts during checkout based on risk assessment decisions. |
| 26 | + |
| 27 | +While this ADR focuses on the aforementioned features, the implementation is designed to allow for seamless future extensions. |
| 28 | + |
| 29 | +## Decision |
| 30 | +### CheckoutGatewayInterface |
| 31 | +To address the outlined challenges, we propose the introduction of the CheckoutGatewayInterface. |
| 32 | +This interface will be invoked during the checkout process to determine a response tailored to the current cart and sales channel context. |
| 33 | + |
| 34 | +```php |
| 35 | +<?php declare(strict_types=1); |
| 36 | + |
| 37 | +namespace Shopware\Core\Checkout\Gateway; |
| 38 | + |
| 39 | +use Shopware\Core\Checkout\Gateway\Command\Struct\CheckoutGatewayPayloadStruct; |
| 40 | +use Shopware\Core\Framework\Log\Package; |
| 41 | + |
| 42 | +#[Package('checkout')] |
| 43 | +interface CheckoutGatewayInterface |
| 44 | +{ |
| 45 | + /** |
| 46 | + * The input struct consists of the cart, sales channel context and currently available payment and shipping methods. |
| 47 | + */ |
| 48 | + public function process(CheckoutGatewayPayloadStruct): CheckoutGatewayResponse; |
| 49 | +} |
| 50 | +``` |
| 51 | + |
| 52 | +Plugin developers are encouraged to create custom implementations of the `CheckoutGatewayInterface` for their specific checkout logic based on decisions from external systems (e.g., ERP, PIM). |
| 53 | + |
| 54 | +The `CheckoutGatewayResponse` will include an `EntityCollection` of payment and shipping methods suitable for the current context, along with a collection of `CartErrors`. |
| 55 | +The input struct and the response is designed for future extension, allowing for more intricate decision-making during checkout. |
| 56 | + |
| 57 | +#### Store-API |
| 58 | +A new store API route, `CheckoutGatewayRoute` '/store-api/checkout/gateway', will be introduced. |
| 59 | +This route will call a `CheckoutGatewayInterface` implementation and respond accordingly, |
| 60 | +and is integral to `CartOrderRoute` requests, ensuring the cart's validity for checkout during the order process. |
| 61 | + |
| 62 | +#### Storefront |
| 63 | +The default invocation of the `CheckoutGatewayRoute` will occur during the checkout-confirm page and edit-order page (so-called "after order"). |
| 64 | +Any changes to the context (e.g., language, currency) will trigger a reload of the payment method selection, calling the app server again. |
| 65 | + |
| 66 | +#### Checkout Gateway Commands |
| 67 | +For streamlined response manipulation by plugins and app servers alike, we propose an executable chain of `CheckoutGatewayCommands`. |
| 68 | +The implementation of the app-system will heavily rely on the command structure. |
| 69 | +However, it is encouraged, but not mandatory for a custom implementation plugin-system implementation of the `CheckoutGatewayInterface` to follow the command structure. |
| 70 | + |
| 71 | +These commands, chosen from a predefined set, can be responded with by plugins and app servers. |
| 72 | +The initial release will include the following commands: `add-payment-method`, `remove-payment-method`, `add-shipping-method`, `remove-shipping-method`, and `add-cart-error`. |
| 73 | +Depending on the command, the payload may differ, necessitating updates to the documentation. |
| 74 | +We propose the use of a handler pattern, to facilitate the execution of these commands. |
| 75 | +Commands will be executed in the order provided in the response. |
| 76 | + |
| 77 | +### App-System |
| 78 | +For the initial release, Shopware will support a single implementation of the `CheckoutGatewayInterface`, provided by the app-system. |
| 79 | +The `AppCheckoutGateway` will sequentially call active apps, but only if the app has a defined `checkout-gateway-url` in its manifest.xml file. |
| 80 | + |
| 81 | +#### App Manifest |
| 82 | +To address challenges for apps, a new app endpoint can be defined in the manifest.xml. |
| 83 | +A new key `gateways` will be added to the manifest file, with a sub-key `checkout` to define the endpoint. |
| 84 | +The `gateways` key signalizes possible future similar endpoints for different purposes. |
| 85 | +The checkout gateway endpoint is configured using a new element called `checkout`. |
| 86 | + |
| 87 | +```xml |
| 88 | +<?xml version="1.0" encoding="UTF-8"?> |
| 89 | +<manifest> |
| 90 | + <!-- ... --> |
| 91 | + |
| 92 | + <gateways> |
| 93 | + <checkout>https://example.com/checkout/gateway</checkout> |
| 94 | + </gateways> |
| 95 | +</manifest> |
| 96 | +``` |
| 97 | + |
| 98 | +#### Checkout Gateway App Payload |
| 99 | +The app server will receive the current `SalesChannelContext`, `Cart`, and available payment and shipping methods as part of the payload. |
| 100 | +The `AppCheckoutGateway` will call the app server with this payload. |
| 101 | + |
| 102 | +```json |
| 103 | +{ |
| 104 | + "salesChannelContext": SalesChannelContextObject, |
| 105 | + "cart": CartObject, |
| 106 | + "paymentMethods": [ |
| 107 | + "payment-method-technical-name-1", |
| 108 | + "payment-method-technical-name-2", |
| 109 | + "payment-method-technical-name-3", |
| 110 | + ... |
| 111 | + ], |
| 112 | + "shippingMethods": [ |
| 113 | + "shipping-method-technical-name-1", |
| 114 | + "shipping-method-technical-name-2", |
| 115 | + "shipping-method-technical-name-3", |
| 116 | + ... |
| 117 | + ] |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +Note that the paymentMethods and shippingMethods arrays will only contain the technical names of the methods, not the full entities. |
| 122 | + |
| 123 | +#### Checkout Gateway App Response |
| 124 | + |
| 125 | +```json |
| 126 | +[ |
| 127 | + { |
| 128 | + "command": "remove-payment-method", |
| 129 | + "payload": { |
| 130 | + "paymentMethodTechnicalName": "payment-myApp-payment-method" |
| 131 | + } |
| 132 | + }, |
| 133 | + { |
| 134 | + "command": "add-cart-error", |
| 135 | + "payload": { |
| 136 | + "reason": "Payment method not available for this cart.", |
| 137 | + "level": 20, |
| 138 | + "blockOrder": true |
| 139 | + } |
| 140 | + } |
| 141 | +] |
| 142 | +``` |
| 143 | + |
| 144 | +#### Event |
| 145 | +A new event `CheckoutGatewayCommandsCollectedEvent` will be introduced. |
| 146 | +This event is dispatched after the `AppCheckoutGateway` has collected all commands from all app servers. |
| 147 | +It allows plugins to manipulate the commands before they are executed, based on the same payload the app servers retrieve. |
| 148 | + |
| 149 | +## Consequences |
| 150 | +### App PHP SDK |
| 151 | +The app-php-sdk will be enhanced to support the new endpoint and data types, ensuring seamless integration with the command structure. |
| 152 | +The following adaptations will be made: |
| 153 | + |
| 154 | +Checkout gateway requests with payload will be deserialized into a `CheckoutGatewayRequest` object. |
| 155 | +Checkout gateway responses will be deserialized into a `CheckoutGatewayResponse` object. |
| 156 | +Every possible checkout gateway command will have a class representing it, facilitating easy manipulation of its payload. |
0 commit comments