1
0
mirror of synced 2026-08-03 05:37:04 +00:00

FEATURE: Allow one-time purchases on products (#18)

Building off the foundation of using the Prices API, this PR adds the ability to create a one-time purchase plan for any product, which then can add a user to the specified plan group.

Some things to be aware of:

    One-time purchases cannot have trials.
    One-time purchases use the Invoice API instead of Subscriptions. Invoices are created then charged immediately.
    Users should receive emails for these invoices directly from Stripe just like subscriptions.
This commit is contained in:
Justin DiRose
2020-07-22 11:06:34 -05:00
committed by GitHub
parent fcc90e4fcc
commit 587661fafb
31 changed files with 272 additions and 533 deletions
+6 -1
View File
@@ -98,7 +98,12 @@ module DiscourseSubscriptions
it "creates a plan with an interval" do
::Stripe::Price.expects(:create).with(has_entry(recurring: { interval: 'week' }))
post "/s/admin/plans.json", params: { interval: 'week', metadata: { group_name: '' } }
post "/s/admin/plans.json", params: { type: 'recurring', interval: 'week', metadata: { group_name: '' } }
end
it "creates a plan as a one-time purchase" do
::Stripe::Price.expects(:create).with(Not(has_key(:recurring)))
post "/s/admin/plans.json", params: { metadata: { group_name: '' } }
end
it "creates a plan with an amount" do
-54
View File
@@ -1,54 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
module DiscourseSubscriptions
RSpec.describe InvoicesController do
describe "index" do
describe "not authenticated" do
it "does not list the invoices" do
::Stripe::Invoice.expects(:list).never
get "/s/invoices.json"
expect(response.status).to eq 403
end
end
describe "authenticated" do
let(:user) { Fabricate(:user) }
let(:stripe_customer) { { id: 'cus_id4567' } }
before do
sign_in(user)
end
describe "other user invoices" do
it "does not list the invoices" do
::Stripe::Invoice.expects(:list).never
get "/s/invoices.json", params: { user_id: 999999 }
end
end
describe "own invoices" do
context "stripe customer does not exist" do
it "lists empty" do
::Stripe::Invoice.expects(:list).never
get "/s/invoices.json", params: { user_id: user.id }
expect(response.body).to eq "[]"
end
end
context "stripe customer exists" do
before do
DiscourseSubscriptions::Customer.create_customer(user, stripe_customer)
end
it "lists the invoices" do
::Stripe::Invoice.expects(:list).with(customer: 'cus_id4567')
get "/s/invoices.json", params: { user_id: user.id }
end
end
end
end
end
end
end
-50
View File
@@ -1,50 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
module DiscourseSubscriptions
RSpec.describe PaymentsController do
context "not authenticated" do
it "does not create a payment intent" do
::Stripe::PaymentIntent.expects(:create).never
post "/s/payments.json", params: {
payment_method: 'pm_123',
amount: 999,
currency: 'gdp'
}
end
end
context "authenticated" do
let(:user) { Fabricate(:user) }
before do
sign_in(user)
end
describe "create" do
it "creates a payment intent" do
::Stripe::Customer.expects(:create).with(
email: user.email
).returns(id: 'cus_87653')
::Stripe::PaymentIntent.expects(:create).with(
payment_method_types: ['card'],
payment_method: 'pm_123',
amount: '999',
currency: 'gdp',
confirm: true,
customer: 'cus_87653'
)
post "/s/payments.json", params: {
payment_method: 'pm_123',
amount: 999,
currency: 'gdp'
}
end
end
end
end
end
+26 -4
View File
@@ -22,6 +22,7 @@ module DiscourseSubscriptions
describe "create" do
it "creates a subscription" do
::Stripe::Price.expects(:retrieve).returns(
type: 'recurring',
product: 'product_12345',
metadata: {
group_name: 'awesome',
@@ -41,8 +42,29 @@ module DiscourseSubscriptions
}.to change { DiscourseSubscriptions::Customer.count }
end
it "creates a one time payment subscription" do
::Stripe::Price.expects(:retrieve).returns(
type: 'one_time',
product: 'product_12345',
metadata: {
group_name: 'awesome'
}
)
::Stripe::InvoiceItem.expects(:create)
::Stripe::Invoice.expects(:create).returns(id: 'in_123')
::Stripe::Invoice.expects(:pay).returns(status: 'paid')
expect {
post '/s/subscriptions.json', params: { plan: 'plan_1234', customer: 'cus_1234' }
}.to change { DiscourseSubscriptions::Customer.count }
end
it "creates a customer model" do
::Stripe::Price.expects(:retrieve).returns(metadata: {})
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: {})
::Stripe::Subscription.expects(:create).returns(status: 'active')
expect {
@@ -61,13 +83,13 @@ module DiscourseSubscriptions
end
it "does not add the user to the admins group" do
::Stripe::Price.expects(:retrieve).returns(metadata: { group_name: 'admins' })
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: 'admins' })
post "/s/subscriptions.json", params: { plan: 'plan_1234', customer: 'cus_1234' }
expect(user.admin).to eq false
end
it "does not add the user to other group" do
::Stripe::Price.expects(:retrieve).returns(metadata: { group_name: 'other' })
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: 'other' })
post "/s/subscriptions.json", params: { plan: 'plan_1234', customer: 'cus_1234' }
expect(user.groups).to be_empty
end
@@ -75,7 +97,7 @@ module DiscourseSubscriptions
context "plan has group in metadata" do
before do
::Stripe::Price.expects(:retrieve).returns(metadata: { group_name: group_name })
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: group_name })
end
it "does not add the user to the group when subscription fails" do