Skip to content

Generalize Pay::Stripe::Sync to Pay::Sync for every processor - #1276

Merged
excid3 merged 1 commit into
mainfrom
generalize-sync
Sep 20, 2026
Merged

excid3 merged 1 commit into
mainfrom
generalize-sync

Conversation

@excid3

@excid3 excid3 commented Sep 20, 2026

Copy link
Copy Markdown
Collaborator

Replaces #1270, which GitHub closed when its stacked base branch was deleted on merge. Same change, rebased onto main.

Summary

Pay::Stripe::Sync from #1266 had nothing Stripe-specific in it, and the same "retrieve unless given, find the customer, retry on a uniqueness race" skeleton was copy-pasted across the other four processors in three different shapes. Two methods declared try:, retries: with no rescue at all; two had no retry despite the same race.

  • lib/pay/sync.rb replaces lib/pay/stripe/sync.rb. sync_with_retries is unchanged. find_pay_customer takes the processor's customer ID and derives the processor from the class namespace via pay_processor.
  • Every Charge.sync, Subscription.sync, and PaymentMethod.sync in Braintree, Paddle Billing, Paddle Classic, and Lemon Squeezy now extend Pay::Sync and runs inside sync_with_retries. Same for Lemon Squeezy's sync_order and sync_subscription_invoice.
  • Each block retrieves into its own local when no object was passed, so a retry re-reads from the processor. A passed object is reused.
  • Paddle Classic and Lemon Squeezy syncs gain the retry. Braintree's payment method sync gains the one it declared. Paddle Billing's flat 0.1s delay becomes the shared growing delay.
  • The internal try:, retries: keywords are removed from the non-Stripe signatures. Nothing passed them.

Not breaking: Pay::Stripe::Sync was added after 11.8.0 and never released.

Test plan

  • New test: Paddle Billing subscription sync retries after a stale lookup and retrieves twice.
  • New test: pay_processor derives the right name for three processors.
  • Full suite on the rebased branch: 602 runs, 0 failures, 0 errors. standardrb clean.

🤖 Generated with Claude Code

Nothing in the shared retry or customer lookup was Stripe-specific,
and the same prelude and retry block were copy-pasted in three
different shapes across Braintree, Paddle Billing, Paddle Classic and
Lemon Squeezy. Two of those declared try/retries kwargs without any
rescue; two others had no retry at all.

Pay::Sync provides sync_with_retries, find_pay_customer(processor_id)
keyed off the class namespace, and pay_processor. Every processor's
Charge, Subscription and PaymentMethod sync now extends it. The
internal try/retries kwargs are gone from the non-Stripe signatures;
nothing passed them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@excid3
excid3 merged commit 2770f08 into main Sep 20, 2026
37 checks passed
@excid3
excid3 deleted the generalize-sync branch September 20, 2026 22:23
excid3 added a commit that referenced this pull request Sep 21, 2026
…1277)

* Prepare for 12.0: upgrade guide, grouped changelog, Pay.mailer fix

- UPGRADE.md gains a Pay 12.0 section covering every breaking change
  in the unreleased set: the removed methods with replacements,
  NotImplementedError for unsupported operations, Pay::Stripe::Error
  everywhere, RecordNotUnique on duplicates, the webhook controller
  extension points, regenerating the SCA view, and the Lemon Squeezy
  data update (moved from a 11.9 heading).
- The Unreleased changelog is grouped into Breaking changes, Fixes and
  Improvements, and the duplicated Pay::Sync entry left over from the
  #1270 to #1276 replacement is removed.
- Pay.mailer no longer memoizes the constantized class. The memo lived
  in a non-reloadable module, so development reloads returned a stale
  mailer class.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Keep Pay::Charge.sorted

Jumpstart Pro's billing page calls pay_charges.sorted, so removing it
breaks every app built on it. Restore the scope, drop it from the 12.0
removals, and add a test so it isn't flagged as dead code again.

* Raise Pay::NotSupportedError and deprecate instead of removing sync methods

Unsupported operations now raise Pay::NotSupportedError, a subclass of
Pay::Error, instead of NotImplementedError. Apps that wrap these calls in
`rescue Pay::Error` (Jumpstart Pro's subscription cancel and pause
controllers do) caught the old Pay::Error on Lemon Squeezy and would have
started returning 500s. Braintree pause and change_quantity and Paddle
Classic change_quantity move over too, so every processor uses one error.

Pay::Stripe::Subscription.sync_from_checkout_session and
Pay::PaddleBilling::Subscription.sync_from_transaction come back as
deprecated wrappers around Pay::Stripe.sync_checkout_session and
Pay::PaddleBilling.sync_transaction, to be removed in Pay 13. Adds
Pay.deprecator, registered with the app on Rails 7.1+.

Restores the Pay::Subscription.cancelled scope to match the cancelled?
predicate, and documents sync_checkout_session for Checkout success pages.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant