Skip to content

Re-use Payments in Checkout - #6564

Open
adammathys wants to merge 5 commits into
solidusio:mainfrom
SuperGoodSoft:feature/reuse-payments-in-checkout
Open

Re-use Payments in Checkout#6564
adammathys wants to merge 5 commits into
solidusio:mainfrom
SuperGoodSoft:feature/reuse-payments-in-checkout

Conversation

@adammathys

@adammathys adammathys commented Aug 31, 2026

Copy link
Copy Markdown
Member

Summary

While repeatedly going through the payment step of checkout, we would create a new payment record each time and invalidate all of the old ones. This could eventually lead to a long list of invalidated payments which is confusing for admins and provides no real value. (It also causes issues for gateways like Stripe that expect there to be a single payment intent for a customer checkout session, and we typically tie the intent to the payment record.)

Instead, we now check for an existing valid payment record and reuse it if it exists. This means that the payment step of checkout will only ever create a single unprocessed payment record for a given payment method on each order.

This change is largely backwards compatible. Existing stores will not benefit from the new change without updating their storefront code to pass the payment ID when appropriate. If the ID is omitted, there's no functional change to behaviour.

We considered updating the admin and API uses, but felt both of those were clearer leaving the existing behaviour because they involve either an explicit call to create a payment (API) or a "New Payment" button (admin).

Possibly Breaking Changes

This updates the Order#payments association to have autosave: true enabled so that we can persist the payment and its source when calling save! on the order itself.

Checklist

Check out our PR guidelines for more details.

The following are mandatory for all PRs:

@adammathys adammathys self-assigned this Aug 31, 2026
@adammathys
adammathys requested a review from a team as a code owner August 31, 2026 18:05
@github-actions github-actions Bot added the changelog:solidus_core Changes to the solidus_core gem label Aug 31, 2026
@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.27%. Comparing base (e7fee10) to head (f288281).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6564   +/-   ##
=======================================
  Coverage   92.26%   92.27%           
=======================================
  Files        1037     1037           
  Lines       21211    21229   +18     
=======================================
+ Hits        19570    19588   +18     
  Misses       1641     1641           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@adammathys
adammathys force-pushed the feature/reuse-payments-in-checkout branch from 3b53200 to 146bc7c Compare August 31, 2026 18:21
Comment thread storefront/templates/app/views/checkouts/steps/_payment_step.html.erb Outdated
Comment thread core/app/models/spree/order.rb Outdated

# Payments
has_many :payments, dependent: :destroy, inverse_of: :order
has_many :payments, dependent: :destroy, inverse_of: :order, autosave: true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worry about this. Feels like it could be considered a breaking change.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same. That's why I called it out in the pull-request description.

Comment thread core/app/models/spree/order_update_attributes.rb
Comment thread core/app/models/spree/order.rb Outdated
@jarednorman

Copy link
Copy Markdown
Member

We want to update the wallet source fieldsets too, right? Saved cards won't reused payments methods the way you ahve this PR, if I understand correctly.

@adammathys
adammathys force-pushed the feature/reuse-payments-in-checkout branch from 146bc7c to 050aa3e Compare September 1, 2026 17:32
@adammathys

Copy link
Copy Markdown
Member Author

We want to update the wallet source fieldsets too, right? Saved cards won't reused payments methods the way you ahve this PR, if I understand correctly.

Yeah, that's correct. This change does not work for wallet sources because of how we completely override the payments_attributes for them. I'll take a stab at trying to change that behaviour to allow for having some payments_attributes persist when using the special wallet_payment_source_id param.

@jarednorman

Copy link
Copy Markdown
Member

Are you going to do that in this PR or make that separate?

@adammathys

Copy link
Copy Markdown
Member Author

I'll add that to this pull-request.

adammathys and others added 3 commits September 2, 2026 10:08
When persisting an order, we want to persist changes made to the
associated payments as well if there are any.

This is a breaking change from previous behaviour, but will make it
easier for us to reuse existing payment records in checkout instead of
creating a new one and invalidating all of the existing ones every time
the customer navigates through that step.

Co-authored-by: Noah Silvera <noah@super.gd>
This will allow for updating an existing payment instead of always
creating new ones. Which will lead to us being able to cut down on the
number of invalid payments created on orders when customers navigated
through the payment step repeatedly.

Co-authored-by: Noah Silvera <noah@super.gd>
Changes the behaviour of OrderUpdateAttributes to update an existing
payment if an ID is passed through for that payment instead of always
creating a new one.

Co-authored-by: Noah Silvera <noah@super.gd>
@adammathys
adammathys force-pushed the feature/reuse-payments-in-checkout branch from 050aa3e to cbe4262 Compare September 2, 2026 17:57
adammathys and others added 2 commits September 2, 2026 11:04
If we've already got a unprocessed payment record for a specific payment
method, then let's just re-use it and update the source instead of
creating a brand new payment record and invalidating the old one leading
to a bunch of junk invalidated payment data we don't care about.

Co-authored-by: Noah Silvera <noah@super.gd>
Co-authored-by: Senem <senem@super.gd>
Updates Order#validate_payments_attributes to also check if a passed
payment ID param matches an ID of a payment that belongs to the order.
This will ensure we don't create the possibility to modify a payment
that does not belong to this order.

Co-authored-by: Noah Silvera <noah@super.gd>
@adammathys
adammathys force-pushed the feature/reuse-payments-in-checkout branch from cbe4262 to f288281 Compare September 2, 2026 18:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog:solidus_core Changes to the solidus_core gem

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants