flamingo.me/flamingo-commerce/v3@v3.11.0/checkout/Readme.md (about) 1 # Checkout Package 2 3 This package provides a one page standard checkout with the following features: 4 5 * Concept for PaymentProviders, that can be used to implement specific Payments 6 * An "offline payment" provider is part of the module 7 8 **Table of content** 9 10 * [Configurations](#configurations) 11 * [Checkout Controller](#checkout-controller) 12 * [GraphQL Place Order Process](#graphql-place-order-process) 13 + [Queries / Mutations](#queries---mutations) 14 + [Place Order States](#place-order-states) 15 + [Context store](#context-store) 16 - [Ports / Implementation](#ports---implementation) 17 + [Locking](#locking) 18 - [Ports / Implementation](#ports---implementation-1) 19 * [Provided Ports](#provided-ports) 20 + [Process Context Store](#process-context-store) 21 + [Process Lock](#process-lock) 22 23 ## Configurations 24 25 If your template does not want to ask for all the information required you can also set default values for the checkoutform (strings) 26 27 ```yaml 28 commerce: 29 checkout: 30 # to enable the offline payment provider 31 enableOfflinePaymentProvider: true 32 33 # checkout flow control flags: 34 skipStartAction: false 35 skipReviewAction: false 36 showReviewStepAfterPaymentError: false 37 showEmptyCartPageIfNoItems: false 38 redirectToCartOnInvalideCart: false 39 40 # checkout form settings: 41 useDeliveryForms: true 42 usePersonalDataForm: false 43 privacyPolicyRequired: true 44 45 # GraphQL place order process 46 placeorder: 47 lock: 48 type: "memory" # only suited for single node applications, use "redis" for multi node setup 49 contextstore: 50 type: "memory" # only suited for single node applications, use "redis" for multi node setup 51 ``` 52 53 54 ## Checkout Controller 55 56 This module implements a controller for the following checkout flow (the checkout process for the end customer): 57 58 1. StartAction (optional) 59 * check if user is logged in 60 * yes: next action 61 * no: show start template (where the user can login) 62 1. Checkout Action 63 * this is the main step, and the template should render the big checkout form (or at least the parts that are interesting). 64 * on submit and if everything was valid: 65 * Action will update the cart - specifically the following information: 66 * Update billing (on cart level) 67 * Update deliveryinfos on (each) delivery in the cart (e.g. used to set shipping address) 68 * Select Payment Gateway and preferred Payment Method 69 * Optional Save the wished payment split for each item in the cart 70 * Optional add Vouchers/GiftCards (may already happened before) 71 * If Review Action is skipped: 72 * Start payment and place order if needed (EarlyPlaceOrder) 73 * Redirect to Payment Action 74 * If Review Step is not skipped: 75 * Redirect to Review Action 76 1. Review Action (Optional) 77 * Renders "review" template that can be used to review the cart 78 * After confirming start the payment and place order if needed (EarlyPlaceOrder) 79 1. Payment Action 80 * Ask Payment Gateway about FlowStatus and handle it 81 * FlowStatus: 82 * Error / Abort by customer: Regenerate Idempotency Key of PaymentSelection, redirect to checkout and reopen cart if needed 83 * Success / Approved: Redirect to PalceOrderAction 84 * Unapproved: Render payment template and let frontend decide how to continue in flow (e.g. redirect to payment provider) 85 1. Place Order Action 86 * Check if order already placed (EarlyPlaceOrder) 87 * If order not already placed check FlowStatus and place order 88 * Put order infos in flash message and redirect to Success Action 89 1. Success Action: 90 * Renders order success template 91 92 ## GraphQL Place Order Process 93 94 When we introduced GraphQL, we rethought the checkout process from the ground up. Among other things, we decided to 95 map the individual steps of the checkout to states of a newly created place order state machine. 96 This should mainly make the process more robust and make it easier to roll back operations in case of errors. 97 98 **Important:** when you start using the new place order process please ensure that you use the "OnWrite" Flamingo session save mode: 99 ``` 100 flamingo.session.saveMode: "OnWrite" 101 ``` 102 103 ### Queries / Mutations 104 105 The checkout module exposes the following Mutations and Queries: 106 107 * `mutation Commerce_Checkout_StartPlaceOrder` 108 starts a place order process and returns the process' UUID. If there is already a running process, it will be replaced by the new one. 109 The processing is started in background and continues after the return of the mutation until an 110 action is required or a final state (error or success) is reached. 111 * `mutation Commerce_Checkout_RefreshPlaceOrder` 112 refreshes the process and tries to start the background processing again if it is not running anymore. The result is the state 113 at the moment of the mutation. If the background process is still running, this mutation is non-operational. 114 * `mutation Commerce_Checkout_RefreshPlaceOrderBlocking` 115 refreshes the process and starts the background processing again if it is not running anymore. It **waits** with the return 116 until the background process comes to a final state or need an action. 117 * `mutation Commerce_Checkout_CancelPlaceOrder` 118 cancels the running process if it is not yet in a final state. 119 * `mutation Commerce_Checkout_ClearPlaceOrder` 120 clears the last stored process. (Non-operational if there is no last process) 121 * `query Commerce_Checkout_ActivePlaceOrder` 122 checks if there is a place order process in a non-final state. 123 * `query Commerce_Checkout_CurrentContext` 124 returns the current state **without** restarting the background processing. 125 126 127 ### Place Order States 128 129 We differentiate between internal and exposed states. 130 131 Internal states implement the interface `checkout/domain/placeorder/process.State`. There is a map binding on this interface using the name of the state. 132 This way, other modules can overwrite specific states to introduce their own implementation. 133 134 The start and failed states are defined by an annotated binding with annotations `startState` and `failedState`, respectively. 135 136 Exposed states implement the interface `checkout/interfaces/graphql/dto.State`. To map internal states to exposed states, 137 we use a map binding on the `dto.State` interface with the internal state names as keys and the exposed state as target. 138 139 The default implementation defines the state flow as follows (for an cart that needs payment): 140 141  142 143 Fully discounted carts don't need a payment, therefore the state flow is similar but lacks the payment creation/validation: 144 145  146 147 ### Context store 148 149 The place order context must be stored aside of the session, since it is manipulated by a background process. 150 151 #### Ports / Implementation 152 153 **In Memory** 154 155 _Important: This context store is only suited for single node applications, please use redis for multi node setup_ 156 157 Default context store implementation. Provides a map based in memory adapter for the `ContextStore` port. 158 159 ```yaml 160 commerce.checkout.placeorder.contextstore.type: "memory" 161 ``` 162 163 **Redis** 164 165 The Redis implementation writes the context into the configured redis instance. The complete entry will be gob-encoded. 166 167 **Be aware that you have to gob-register your own `StateData` if you introduce some.** 168 169 ```yaml 170 commerce.checkout.placeorder.contextstore: 171 type: "redis" 172 redis: 173 maxIdle: 25 174 idleTimeoutMilliseconds: 240000 175 network: "tcp" 176 address: "localhost:6379" 177 database: 0 178 ``` 179 180 ### Locking 181 182 To ensure that the state machine cannot be processed multiple times for one process, we have decided to introduce a process lock. 183 At the start of each place order transaction an attempt is made to obtain a lock, if this is not possible a transaction is already running and we just wait. 184 185 #### Ports / Implementation 186 187 The module offers the `TryLock` port and currently two implementations (Memory, Redis). 188 189 **In Memory** 190 191 _Important: This lock is only suited for single node applications, please use redis for multi node setup_ 192 193 Default lock implementation. Provides a mutex based in memory adapter for the `TryLock` port. 194 195 ```yaml 196 commerce.checkout.placeorder.lock.type: "memory" 197 ``` 198 199 **Redis** 200 201 Provides a redis based lock implementation using the [go-redsync/redsync](https://github.com/go-redsync/redsync) package. 202 Node acquires the lock and refreshes it every X second, if the node dies the lock is automatically released after the provided max duration. 203 204 ```yaml 205 commerce.checkout.placeorder.lock: 206 type: "redis" 207 redis: 208 maxIdle: 25 209 idleTimeoutMilliseconds: 240000 210 network: "tcp" 211 address: "localhost:6379" 212 database: 0 213 ``` 214 215 216 ## Provided Ports 217 218 ### Process Context Store 219 New GraphQL related process context store. For more details see [Context store](#context-store) 220 221 ### Process Lock 222 New GraphQL related process lock. For more details see [Locking](#locking) 223