FIX: Pricing table for one-off purchases (#228)

When using the Stripe Pricing table for one-off purchases
(non-subscriptions) the webhook was encountering an error because it was
expecting subscription information which does not exist for one-off
purchases. This fix addresses that issue ensuring that no errors occur,
that users are added to the appropriate group, and that uses can see
their purchase on the billing page.
This commit is contained in:
Blake Erickson 2024-08-20 13:32:32 -06:00 committed by GitHub
parent 52cae7b1a9
commit f0b4984cee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 80 additions and 16 deletions

View File

@ -44,23 +44,27 @@ module DiscourseSubscriptions
discourse_customer = Customer.create(user_id: user.id, customer_id: customer_id)
Subscription.create(
customer_id: discourse_customer.id,
external_id: checkout_session[:subscription],
)
subscription = checkout_session[:subscription]
if !subscription.nil?
Subscription.create(customer_id: discourse_customer.id, external_id: subscription)
end
line_items =
::Stripe::Checkout::Session.list_line_items(checkout_session[:id], { limit: 1 })
item = line_items[:data].first
group = plan_group(item[:price])
group.add(user) unless group.nil?
discourse_customer.product_id = item[:price][:product]
discourse_customer.save!
::Stripe::Subscription.update(
checkout_session[:subscription],
{ metadata: { user_id: user.id, username: user.username } },
)
if !subscription.nil?
::Stripe::Subscription.update(
subscription,
{ metadata: { user_id: user.id, username: user.username } },
)
end
when "customer.subscription.created"
when "customer.subscription.updated"
subscription = event[:data][:object]

View File

@ -27,7 +27,12 @@ module DiscourseSubscriptions
payments = ::Stripe::PaymentIntent.list(customer: customer_id)
payments_from_invoices =
payments[:data].select { |payment| invoice_ids.include?(payment[:invoice]) }
data = data | payments_from_invoices
# Pricing table one-off purchases do not have invoices
payments_without_invoices =
payments[:data].select { |payment| payment[:invoice].nil? }
data = data | payments_from_invoices | payments_without_invoices
end
end
@ -42,14 +47,13 @@ module DiscourseSubscriptions
private
def parse_invoices(all_invoices, product_ids)
invoices_with_products =
all_invoices[:data].select do |invoice|
invoice_lines = invoice[:lines][:data][0] if invoice[:lines] && invoice[:lines][:data]
if invoice_lines
invoice_product_id = parse_invoice_lines(invoice_lines)
product_ids.include?(invoice_product_id)
end
all_invoices[:data].select do |invoice|
invoice_lines = invoice[:lines][:data][0] if invoice[:lines] && invoice[:lines][:data]
if invoice_lines
invoice_product_id = parse_invoice_lines(invoice_lines)
product_ids.include?(invoice_product_id)
end
end
end
def parse_invoice_lines(invoice_lines)

View File

@ -83,6 +83,27 @@ RSpec.describe DiscourseSubscriptions::HooksController do
}
end
let(:checkout_session_completed_data_one_off) do
{
object: {
id: "cs_test_a1ENei5A9TGOaEketyV5qweiQR5CyJWHT5j8T3HheQY3uah3RxzKttVUKZ",
object: "checkout.session",
customer: customer.customer_id,
customer_email: user.email,
invoice: nil,
metadata: {
},
mode: "subscription",
payment_status: "paid",
status: "complete",
submit_type: nil,
subscription: nil,
success_url: "http://localhost:4200/my/billing/subscriptions",
url: nil,
},
}
end
let(:checkout_session_completed_bad_data) do
{
object: {
@ -184,6 +205,26 @@ RSpec.describe DiscourseSubscriptions::HooksController do
end
end
describe "checkout.session.completed for one-off purchase" do
before do
event = {
type: "checkout.session.completed",
data: checkout_session_completed_data_one_off,
}
::Stripe::Checkout::Session
.stubs(:list_line_items)
.with(checkout_session_completed_data[:object][:id], { limit: 1 })
.returns(list_line_items_data)
::Stripe::Webhook.stubs(:construct_event).returns(event)
end
it "is returns 200" do
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(1)
expect(response.status).to eq 200
end
end
describe "checkout.session.completed with anonymous user" do
before do
checkout_session_completed_bad_data[:object][:customer_email] = "anonymous@example.com"

View File

@ -60,5 +60,20 @@ RSpec.describe DiscourseSubscriptions::User::PaymentsController do
expect(invoice).to eq("inv_900007")
expect(parsed_body.count).to eq(2)
end
it "gets pricing table one-off purchases" do
::Stripe::Invoice.expects(:list).with(customer: "c_345678").returns(data: [])
::Stripe::PaymentIntent
.expects(:list)
.with(customer: "c_345678")
.returns(data: [{ id: "pi_900010", invoice: nil, created: Time.now }])
get "/s/user/payments.json"
parsed_body = response.parsed_body
expect(parsed_body.count).to eq(1)
end
end
end