Commerce Core 2.25 expands payment, coupon, and promotion management
We released Commerce Core 2.25 on June 30th, 2021. This release kicks off a new schedule that focuses on feature releases once a quarter with bug fix / minor patch releases in the intervening months, giving us time to focus on our other modules as well. Our efforts for this release centered around store administration improvements, Layout Builder integration, and general performance and stability improvements. We also reviewed our code to ensure we had solutions or a roadmap for changes required by Brexit and the EU July 2021 eCommerce VAT package.
Store administration improvements
As with the 2.24 release, our work with multiple large merchants continued to drive store administration improvements throughout the 2.25 development cycle. This release packs in features related to payment administration, coupon administration, and promotion configuration in addition to quality of life improvements in one of our main dependencies, State Machine.
New payment entry options
Until this release, store administrators wanting to enter a new payment for an order could only do so using stored payment methods previously created by the customer. Several years ago, Drupal Commerce contributor Brad Jones kicked off development of a major feature patch to add support for the creation of new payment methods in the order management interface. This is particularly helpful for customer service representatives placing orders for customers who do not have accounts or stored payment methods on their sites yet.
In addition to this new feature in the order management interface, we expanded support for the creation of stored payment methods on user account pages. Whereas we previously only supported the management of stored payment methods for a single payment gateway, the interface now more closely tracks the payment method checkout pane, supporting payment method creation for multiple payment gateways.
Commerce Core 2.x provides a robust promotion system, including single and bulk coupon support per promotion. As of this release, promotions now log the creator and both promotions and their associated coupons track their created / changed times for logging purposes.
Multiple merchants needed more out of the coupon lists, so we converted it to use Views. This makes it easier to control the fields displayed, adjust the number of coupons shown per page, and allow for exporting the list of coupons codes to a CSV. This is often necessary after generating a lot of coupon codes in a batch for a marketing campaign.
That said, we cannot easily provide CSV export functionality in Commerce Core itself without introducing extra module dependencies. We try to avoid that as much as possible for the sake of maintenance / stability, but it's relatively straightforward to add exporting to the existing View using a module like VBO export or Views Data Export. My personal preference is the VBO export module thanks to its integration with the Views Bulk Operations module.
Surprisingly, until Commerce 2.25 it wasn't actually possible to discount both shipping and the order subtotal through a single promotion. We made this happen by introducing a new Combination offer plugin, allowing you to combine multiple different types of offers together.
Fully discounting the order total (assuming the order has neither fees nor custom adjustments applied) can now be achieved with the following configuration:
State machine improvements
I devoted a lot of time to improving State Machine, one of our key Commerce Core dependencies, in conjunction with this release. These include some under the hood API improvements, multiple bug fixes, and the prevention of invalid transitions at the code level (see this change record).
Transition confirmation forms
One of the most significant improvements, though, is the addition of confirmation forms to state transitions triggered through the UI. On new Commerce installations, a confirmation form will now be presented to the user before applying any state transition to ensure dangerous / irreversible transitions (i.e transitions that can potentially trigger emails, API calls, etc.) are applied on purpose.
Layout Builder integration
In addition to improving State Machine, we incorporated multiple improvements to our Layout Builder integration thanks to contribution from Matt Glaman. Layout Builder is a core Drupal module that lets you configure more complex layouts for various types of pages on your site, with the following issues landing to improve your ability to create more custom product display pages:
- ProductVariationContext improperly implements ContextProviderInterface
- ProductVariationContext is causing extra generate sample images to be generated
- Layout Builder for product with empty variation field not working
Finally, while we are always looking for ways to improve the performance and stability of Commerce Core at scale, we're very excited to launch a new feature in 2.25 related to order locking. Order locking occurs when one page request loads an order and instructs the database not to permit any other page request to write updates to that order until the current page request is done with it. Decoupled architectures, API integrations, and even just twitchy customers can create data loss issues where concurrent requests against your site try to update the same data.
Commerce 1.x used "pessimistic" locking to "lock" every order on load, assuming if it was going to be loaded, it was liable to be updated. However, the vast majority of order loads are for read purposes only and never result in a save. While this approach was good at preventing data overwrite / data loss, it had this own set of issues - database deadlocks, performance problems, and inconsistencies due to hooks prematurely saving an order (cf. Improve commerce entities locking).
Until the 2.25 release, Commerce 2.x only supported an explicit locking API for offsite payment gateways to ensure orders were not updated when they reached the payment step (cf. Provide a way to explicitly lock the order).
An alternative approach to pessimistic locking is "optimistic" locking. Because we preferred to be optimistic this time 🙂, this is the approach we've chosen; it is perfectly described in this Stack Overflow post:
Optimistic Locking is a strategy where you read a record, take note of a version number, and check that the version hasn't changed before you write the record back.
As of Commerce Core 2.25, each time an order is successfully saved, a "version" field on it gets incremented right before the save (i.e on order pre-save). The version currently stored in the database is then compared against the version that is about to be saved. If the order that is about to be saved isn't the "latest" version, you can choose whether or not to permit the save with a debug message stored in your log or to prevent the save altogether:
In order for this change to be as little disruptive as possible, we "log" the order version mismatch by default and allow the order save to go through. This isn't ideal, as it technically permits overwriting newer data with "old" data, but our hope is the appearance of log messages now gives developers (our own team included!) the ability to track down places where concurrent saves occur and find strategies to prevent them. To always force such updates to fail, toggle the setting in the order settings interface.
We have a lot more to share, including updates to other Centarro maintained Commerce contribs. Stay tuned for those and more as we continue to advance the system thanks to our customers and community contributors.