DEV: Add pagination to plans request (#272)

When pulling up a users subscriptions a 500 might occur if we don't find
their plan. If your account happens to have over 100 plans this can be
the cause of the 500 error. This change adds pagination when fetching
plans form stripe, so that we fetch them all.

https://meta.discourse.org/t/problem-with-500-error-with-subscriptions/360808?u=blake
This commit is contained in:
Blake Erickson 2025-04-10 07:35:31 -06:00 committed by GitHub
parent 3dd59a60da
commit 100b276c9d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 53 additions and 2 deletions

View File

@ -24,7 +24,14 @@ module DiscourseSubscriptions
subscriptions = []
if subscription_ids
plans = ::Stripe::Price.list(expand: ["data.product"], limit: 100)
prices = []
price_params = { limit: 100, expand: ["data.product"] }
loop do
response = ::Stripe::Price.list(price_params)
prices.concat(response[:data])
break unless response[:has_more]
price_params[:starting_after] = response[:data].last.id
end
all_subscriptions = []
stripe_customer_ids.each do |stripe_customer_id|
@ -35,7 +42,7 @@ module DiscourseSubscriptions
subscriptions = all_subscriptions.select { |sub| subscription_ids.include?(sub[:id]) }
subscriptions.map! do |subscription|
plan = plans[:data].find { |p| p[:id] == subscription[:items][:data][0][:price][:id] }
plan = prices.find { |p| p[:id] == subscription[:items][:data][0][:price][:id] }
subscription.to_h.except!(:plan)
subscription.to_h.merge(plan: plan, product: plan[:product].to_h.slice(:id, :name))
end

View File

@ -5,6 +5,14 @@ require "rails_helper"
RSpec.describe DiscourseSubscriptions::User::SubscriptionsController do
before { SiteSetting.discourse_subscriptions_enabled = true }
def create_price(id, product)
price = { id: id, product: product }
def price.id
self[:id]
end
price
end
it "is a subclass of ApplicationController" do
expect(DiscourseSubscriptions::User::SubscriptionsController < ::ApplicationController).to eq(
true,
@ -80,6 +88,42 @@ RSpec.describe DiscourseSubscriptions::User::SubscriptionsController do
expect(subscription[:items][:data][0][:plan][:id]).to eq("price_1OrmlvEYXaQnncShNahrpKvA")
expect(subscription[:product][:name]).to eq("Exclusive Access")
end
it "aggregates prices from multiple pages using pagination logic" do
subscription_data = { id: "sub_10z", items: { data: [{ price: { id: "price_200" } }] } }
::Stripe::Subscription
.stubs(:list)
.with(customer: "cus_23456", status: "all")
.returns({ data: [subscription_data] })
# Build the first page of 100 prices that do NOT include the desired price.
prices_page_1 =
(1..100).map do |i|
create_price("price_#{i}", { id: "prod_dummy", name: "Dummy Product #{i}" })
end
# Second page containing the desired price.
prices_page_2 = [create_price("price_200", { id: "prod_200", name: "Matching Product" })]
::Stripe::Price
.expects(:list)
.with(has_entries(limit: 100, expand: ["data.product"]))
.returns({ data: prices_page_1, has_more: true })
::Stripe::Price
.expects(:list)
.with(has_entries(limit: 100, expand: ["data.product"], starting_after: "price_100"))
.returns({ data: prices_page_2, has_more: false })
get "/s/user/subscriptions.json"
result = JSON.parse(response.body, symbolize_names: true)
subscription = result.first
expect(subscription[:id]).to eq("sub_10z")
expect(subscription[:plan][:id]).to eq("price_200")
expect(subscription[:product][:id]).to eq("prod_200")
expect(subscription[:product][:name]).to eq("Matching Product")
end
end
describe "update" do