Skip to content

Commit 103b567

Browse files
excid3claude
andauthored
Prefer active subscriptions in Pay::Customer#subscription (#1249)
Pay::Customer#subscription returned the most recently created subscription regardless of status, so a customer with an older active subscription and a newer canceled one would get the canceled one back. Now prefer an active or paused subscription for the name, falling back to the most recently created subscription when none are active. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent a5dde91 commit 103b567

4 files changed

Lines changed: 43 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
### Unreleased
44

5+
* `Pay::Customer#subscription` now prefers an active or paused subscription over a newer canceled one, falling back to the most recently created subscription when none are active
6+
57
### 11.7.1
68

79
* Preserve existing Stripe api key if already set when Pay initializes #1248

app/models/pay/customer.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ def update_payment_method(payment_method_id)
3434
add_payment_method(payment_method_id, default: true)
3535
end
3636

37+
# Returns the active or paused subscription for the given name, falling
38+
# back to the most recently created subscription when none are active.
3739
def subscription(name: Pay.default_product_name)
38-
subscriptions.order(created_at: :desc).for_name(name).first
40+
scope = subscriptions.for_name(name).order(created_at: :desc)
41+
scope.active_or_paused.first || scope.first
3942
end
4043

4144
def subscribed?(name: Pay.default_product_name, processor_plan: nil)

test/models/pay/customer_test.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,36 @@ class Pay::CustomerTest < ActiveSupport::TestCase
2828
assert pay_customer.update_api_record(promotion_code: "promo_xxx123")
2929
end
3030

31+
test "subscription prefers an active subscription over a newer canceled one" do
32+
pay_customer = pay_customers(:fake)
33+
active = pay_customer.subscriptions.first
34+
canceled = pay_customer.subscriptions.create!(processor_id: "fake_2", name: "default", processor_plan: "default", status: "canceled", ends_at: 1.day.ago, created_at: 1.day.from_now)
35+
36+
assert_equal active, pay_customer.subscription
37+
assert_not_equal canceled, pay_customer.subscription
38+
end
39+
40+
test "subscription prefers a paused subscription over a newer canceled one" do
41+
pay_customer = pay_customers(:fake)
42+
paused = pay_customer.subscriptions.first
43+
paused.update!(status: "paused")
44+
pay_customer.subscriptions.create!(processor_id: "fake_2", name: "default", processor_plan: "default", status: "canceled", ends_at: 1.day.ago, created_at: 1.day.from_now)
45+
46+
assert_equal paused, pay_customer.subscription
47+
end
48+
49+
test "subscription falls back to the most recent subscription when none are active" do
50+
pay_customer = pay_customers(:fake)
51+
pay_customer.subscriptions.first.update!(status: "canceled", ends_at: 2.days.ago)
52+
newer = pay_customer.subscriptions.create!(processor_id: "fake_2", name: "default", processor_plan: "default", status: "canceled", ends_at: 1.day.ago, created_at: 1.day.from_now)
53+
54+
assert_equal newer, pay_customer.subscription
55+
end
56+
57+
test "subscription returns nil when there are no subscriptions for the name" do
58+
assert_nil pay_customers(:fake).subscription(name: "nonexistent")
59+
end
60+
3161
test "not_fake scope" do
3262
assert_not_includes Pay::Customer.not_fake_processor, pay_customers(:fake)
3363
assert_includes Pay::Customer.not_fake_processor, pay_customers(:stripe)

test/models/pay/subscription_test.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,14 +433,19 @@ class Pay::Subscription::Test < ActiveSupport::TestCase
433433

434434
subscription_2 = create_subscription(status: "canceled", processor_id: 2)
435435

436-
assert_equal subscription_2, @pay_customer.subscription
437-
assert_equal subscription_2, @pay_customer.subscription
436+
# The active subscription is preferred over a newer canceled one
437+
assert_equal subscription_1, @pay_customer.subscription
438+
assert_equal subscription_1, @pay_customer.subscription
438439

439440
subscription_1.update_columns(status: "canceled")
441+
pay_subscriptions(:stripe).update_columns(status: "canceled")
440442

441443
@pay_customer.reload
442444
assert_not @pay_customer.subscriptions.loaded?
443445

446+
# With no active subscriptions, the most recently created one is returned
447+
assert_equal subscription_2, @pay_customer.subscription
448+
444449
@pay_customer.subscriptions.load
445450
assert_equal subscription_2, @pay_customer.subscription
446451
end

0 commit comments

Comments
 (0)