Synchronous Order Processing
Synchronous Order Processing
To complete the checkout process, an order needs to be created and transitioned through a number of synchronous steps before it can be sent to fulfillment. This synchronous order processing is implemented by the CheckoutService. To process an order, the CheckoutService requires a ShoppingCart and an OrderPayment. The ShoppingCart essentially represents an order for products, complete with the customer and shipping information. The OrderPayment provides information about how the customer will pay for the items in the cart. CheckoutService.checkout() is invoked with these two parameters and will throw an exception if anything goes wrong. The exception may be an EpServiceException, or any of the standard exceptions thrown by implementors of the PaymentGateway interface (see Payment Processing).
The main responsibility of the checkout operation is to process the payment and persist the order. It is assumed that customer and product information can be changed at any time; therefore, all information about the order, product, customer, and payment must be stored as copies in separate database tables.
Checkout Actions
Synchronous order processing is performed by checkout action classes that implement one of the CheckoutAction, ReversibleCheckoutAction or FinalizeCheckoutAction interfaces.
Checkout actions can be broken down into three subgroups of actions which occur after the customer submits his/her purchase
- Setup actions that implement an execute() method.
- Reversible actions that implement execute() and rollback() methods.
- Finalize actions that implement an execute() method.
The checkout actions are defined in three separate lists that are injected into the abstractCheckoutServiceDelegate bean in the checkout.xml file in ep-core.
<util:list id="setupActions" list-class="java.util.ArrayList"> <ref bean="preCheckoutCheckoutAction" /> <ref bean="shippingInformationCheckoutAction" /> <ref bean="giftCertificateBalanceCheckerCheckoutAction" /> <ref bean="stockCheckerCheckoutAction" /> <ref bean="updateCustomerCheckoutAction" /> </util:list> <util:list id="reversibleActions" list-class="java.util.ArrayList"> <ref bean="createNewOrderCheckoutAction" /> <ref bean="populateOrderDataCheckoutAction" /> <ref bean="createGiftCertificatesCheckoutAction" /> <ref bean="populateTemplateOrderPaymentCheckoutAction" /> <ref bean="authorizePaymentsCheckoutAction" /> <ref bean="updateLimitedUsageNumbersCheckoutAction" /> <ref bean="subscriptionCreditCheckCheckoutAction" /> <ref bean="updateOrderCheckoutAction" /> <ref bean="commitOrderTaxCheckoutAction" /> <ref bean="processCouponCustomerAssignmentsCheckoutAction" /> <ref bean="createNewOrderEventCheckoutAction" /> <ref bean="initiateFulfilmentCheckoutAction" /> <ref bean="capturePaymentsCheckoutAction" /> </util:list> <util:list id="finalizeActions" list-class="java.util.ArrayList"> <ref bean="clearShoppingCartCheckoutAction" /> <ref bean="postCheckoutCheckoutAction" /> </util:list>
These checkout action lists can be overridden in your extensions project to add custom checkout actions, or to remove or reorder existing actions.
preCheckoutCheckoutAction and postCheckoutCheckoutAction do nothing in the OOTB source code.
The CheckoutAction implementations of each step delegate to the following key classes and files:
Key classes and files
- CheckoutService - Service that executes a checkout.
- CheckoutEventHandler - Interface implemented by a class wired via Spring to the CheckoutService so that it can be notified of events during the checkout execution. This is useful for extending or modifying checkout functionality.
- ShoppingCart - The shopping cart contains items to be purchased during a checkout.
- OrderPayment - An order payment represents information about how the customer will pay for the order.
- PaymentGateway - Interface implemented by payment gateways that handle financial transactions such as credit card or PayPal payments.
- Order - Represents a completed order for products.
- OrderSku - A snapshot of information about a purchased SKU at the time of checkout.
- OrderShipment - Contains shipping information for an order.
- Inventory - Contains inventory information for a particular product SKU.
- OrderAddress - A snapshot of the customer's address (billing and shipping) at the time of checkout.
Implementing Checkout Event Handlers
- preCheckout - called before any other checkout action is executed
- preCheckoutOrderPersist - called just before the order is persisted
- postCheckout called after all other checkout actions have completed
For example, if you wanted to call a webservice every time a checkout was completed, you could write a new class that extends the CheckoutEventHandler and implement the web service call in the postCheckout() method.
Important concepts
Transaction boundaries
The checkout service is configured in Spring so that checkout methods do NOT run as transactions. This is required to persist audit trails for checkout actions. For example, if a credit card payment fails, we want to record this in the OrderPayment table. If the checkout method was transactional, the database operation would be rolled back automatically.
However, the service methods invoked by checkout actions need to execute within transactions if they update the database.
Creating an Order
The CheckoutService creates an Order object and passes it to the OrderService to persist.
Every Order must have a unique OrderNumber, set at Order creation time (not at persist time). Unique order numbers are obtained from the OrderService.getNextOrderNumber() method.
OrderService
The OrderService provides services to query on Orders and persist Orders, but not to generate Orders. Order generation is performed by the CheckoutService.
There are methods to search for orders by various basic criteria, or you can pass in an OrderSearchCriteria object. The search methods must translate the given criteria into a Criteria String for the Persistence engine, and they do so via an OrderCriterion factory class.
Data replication
At order time a snapshot of various objects must be created and stored in separate tables to insulate the Order details from any future changes in prices, inventory, addresses, etc. Objects are copied as follows:
ProductSku --> OrderSku BillingAddress --> OrderAddress (for the Order) ShippingAddress --> OrderAddress (for the OrderShipment)
Attributes such as shipping cost, quantity, taxes, etc. are calculated at Order time and frozen in the appropriate object (Order, OrderShipment, OrderSku, etc).
Failed Orders
Failed orders are saved to the database (TORDER table) with the order's STATUS set to FAILED. The Quartz job, cleanupFailedOrdersJob, will eventually remove the failed order from your system.