401 lines
15 KiB
Ruby
401 lines
15 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
module DiscourseSubscriptions
|
|
RSpec.describe SubscribeController do
|
|
let (:user) { Fabricate(:user) }
|
|
let (:campaign_user) { Fabricate(:user) }
|
|
|
|
context "showing products" do
|
|
let(:product) do
|
|
{
|
|
id: "prodct_23456",
|
|
name: "Very Special Product",
|
|
metadata: {
|
|
description: "Many people listened to my phone call with the Ukrainian President while it was being made",
|
|
repurchaseable: false
|
|
},
|
|
otherstuff: true,
|
|
}
|
|
end
|
|
|
|
let(:prices) do
|
|
{
|
|
data: [
|
|
{ id: 'plan_id123', unit_amount: 1220, currency: 'aud', recurring: { interval: 'year' }, metadata: {} },
|
|
{ id: 'plan_id234', unit_amount: 1399, currency: 'usd', recurring: { interval: 'year' }, metadata: {} },
|
|
{ id: 'plan_id678', unit_amount: 1000, currency: 'aud', recurring: { interval: 'week' }, metadata: {} }
|
|
]
|
|
}
|
|
end
|
|
|
|
let(:product_ids) { ["prodct_23456"] }
|
|
|
|
before do
|
|
sign_in(user)
|
|
Fabricate(:product, external_id: "prodct_23456")
|
|
SiteSetting.discourse_subscriptions_public_key = "public-key"
|
|
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
|
|
end
|
|
|
|
describe "#index" do
|
|
|
|
it "gets products" do
|
|
::Stripe::Product.expects(:list).with(ids: product_ids, active: true).returns(data: [product])
|
|
|
|
get "/s.json"
|
|
|
|
expect(response.parsed_body).to eq([{
|
|
"id" => "prodct_23456",
|
|
"name" => "Very Special Product",
|
|
"description" => PrettyText.cook("Many people listened to my phone call with the Ukrainian President while it was being made"),
|
|
"subscribed" => false,
|
|
"repurchaseable" => false,
|
|
}])
|
|
end
|
|
|
|
it "is subscribed" do
|
|
Fabricate(:customer, product_id: product[:id], user_id: user.id, customer_id: 'x')
|
|
::Stripe::Product.expects(:list).with(ids: product_ids, active: true).returns(data: [product])
|
|
|
|
get "/s.json"
|
|
data = response.parsed_body
|
|
expect(data.first["subscribed"]).to eq true
|
|
end
|
|
|
|
it "is not subscribed" do
|
|
::DiscourseSubscriptions::Customer.delete_all
|
|
::Stripe::Product.expects(:list).with(ids: product_ids, active: true).returns(data: [product])
|
|
|
|
get "/s.json"
|
|
data = response.parsed_body
|
|
expect(data.first["subscribed"]).to eq false
|
|
end
|
|
end
|
|
|
|
describe "#get_contributors" do
|
|
before do
|
|
Fabricate(:product, external_id: "prod_campaign")
|
|
Fabricate(:customer, product_id: "prodct_23456", user_id: user.id, customer_id: 'x')
|
|
Fabricate(:customer, product_id: "prod_campaign", user_id: campaign_user.id, customer_id: 'y')
|
|
end
|
|
context 'not showing contributors' do
|
|
it 'returns nothing if not set to show contributors' do
|
|
SiteSetting.discourse_subscriptions_campaign_show_contributors = false
|
|
get "/s/contributors.json"
|
|
|
|
data = response.parsed_body
|
|
expect(data).to be_empty
|
|
end
|
|
end
|
|
|
|
context 'showing contributors' do
|
|
before do
|
|
SiteSetting.discourse_subscriptions_campaign_show_contributors = true
|
|
end
|
|
|
|
it 'filters users by campaign product if set' do
|
|
SiteSetting.discourse_subscriptions_campaign_product = "prod_campaign"
|
|
|
|
get "/s/contributors.json"
|
|
|
|
data = response.parsed_body
|
|
expect(data.first["id"]).to eq campaign_user.id
|
|
expect(data.length).to eq 1
|
|
end
|
|
|
|
it 'shows all purchases if campaign product not set' do
|
|
SiteSetting.discourse_subscriptions_campaign_product = nil
|
|
|
|
get "/s/contributors.json"
|
|
|
|
data = response.parsed_body
|
|
expect(data.length).to eq 2
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#show" do
|
|
it 'retrieves the product' do
|
|
::Stripe::Product.expects(:retrieve).with('prod_walterwhite').returns(product)
|
|
::Stripe::Price.expects(:list).with(active: true, product: 'prod_walterwhite').returns(prices)
|
|
get "/s/prod_walterwhite.json"
|
|
|
|
expect(response.parsed_body).to eq({
|
|
"product" => {
|
|
"id" => "prodct_23456",
|
|
"name" => "Very Special Product",
|
|
"description" => PrettyText.cook("Many people listened to my phone call with the Ukrainian President while it was being made"),
|
|
"subscribed" => false,
|
|
"repurchaseable" => false
|
|
},
|
|
"plans" => [
|
|
{ "currency" => "aud", "id" => "plan_id123", "recurring" => { "interval" => "year" }, "unit_amount" => 1220 },
|
|
{ "currency" => "usd", "id" => "plan_id234", "recurring" => { "interval" => "year" }, "unit_amount" => 1399 },
|
|
{ "currency" => "aud", "id" => "plan_id678", "recurring" => { "interval" => "week" }, "unit_amount" => 1000 }
|
|
]
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
context "creating subscriptions" do
|
|
context "unauthenticated" do
|
|
it "does not create a subscription" do
|
|
::Stripe::Customer.expects(:create).never
|
|
::Stripe::Price.expects(:retrieve).never
|
|
::Stripe::Subscription.expects(:create).never
|
|
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
|
end
|
|
end
|
|
|
|
context "authenticated" do
|
|
before do
|
|
sign_in(user)
|
|
end
|
|
|
|
describe "#create" do
|
|
before do
|
|
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
|
|
end
|
|
|
|
it "creates a subscription" do
|
|
::Stripe::Price.expects(:retrieve).returns(
|
|
type: 'recurring',
|
|
product: 'product_12345',
|
|
metadata: {
|
|
group_name: 'awesome',
|
|
trial_period_days: 0
|
|
}
|
|
)
|
|
|
|
::Stripe::Subscription.expects(:create).with(
|
|
customer: 'cus_1234',
|
|
items: [ price: 'plan_1234' ],
|
|
metadata: { user_id: user.id, username: user.username_lower },
|
|
trial_period_days: 0,
|
|
promotion_code: nil
|
|
).returns(status: 'active', customer: 'cus_1234')
|
|
|
|
expect {
|
|
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
|
}.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(status: 'open', id: 'in_123')
|
|
|
|
::Stripe::Invoice.expects(:finalize_invoice).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123')
|
|
|
|
::Stripe::Invoice.expects(:retrieve).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123')
|
|
|
|
::Stripe::PaymentIntent.expects(:retrieve).returns(status: 'successful')
|
|
|
|
::Stripe::Invoice.expects(:pay).returns(status: 'paid', customer: 'cus_1234')
|
|
|
|
expect {
|
|
post '/s/create.json', params: { plan: 'plan_1234', source: 'tok_1234' }
|
|
}.to change { DiscourseSubscriptions::Customer.count }
|
|
end
|
|
|
|
it "creates a customer model" do
|
|
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: {}).twice
|
|
::Stripe::Subscription.expects(:create).returns(status: 'active', customer: 'cus_1234')
|
|
|
|
expect {
|
|
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
|
}.to change { DiscourseSubscriptions::Customer.count }
|
|
|
|
::Stripe::Customer.expects(:retrieve).with('cus_1234')
|
|
|
|
expect {
|
|
post "/s/create.json", params: { plan: 'plan_5678', source: 'tok_5678' }
|
|
}.not_to change { DiscourseSubscriptions::Customer.count }
|
|
end
|
|
|
|
context "with promo code" do
|
|
context "invalid code" do
|
|
it "prevents use of invalid coupon codes" do
|
|
::Stripe::Price.expects(:retrieve).returns(
|
|
type: 'recurring',
|
|
product: 'product_12345',
|
|
metadata: {
|
|
group_name: 'awesome',
|
|
trial_period_days: 0
|
|
}
|
|
)
|
|
|
|
::Stripe::PromotionCode.expects(:list).with({ code: 'invalid' }).returns(
|
|
data: []
|
|
)
|
|
|
|
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: 'invalid' }
|
|
|
|
data = response.parsed_body
|
|
expect(data["errors"]).not_to be_blank
|
|
end
|
|
end
|
|
|
|
context "valid code" do
|
|
before do
|
|
::Stripe::PromotionCode.expects(:list).with({ code: '123' }).returns(
|
|
data: [{
|
|
id: 'promo123',
|
|
coupon: { id: 'c123' }
|
|
}]
|
|
)
|
|
end
|
|
|
|
it "applies promo code to recurring subscription" do
|
|
::Stripe::Price.expects(:retrieve).returns(
|
|
type: 'recurring',
|
|
product: 'product_12345',
|
|
metadata: {
|
|
group_name: 'awesome',
|
|
trial_period_days: 0
|
|
}
|
|
)
|
|
|
|
::Stripe::Subscription.expects(:create).with(
|
|
customer: 'cus_1234',
|
|
items: [ price: 'plan_1234' ],
|
|
metadata: { user_id: user.id, username: user.username_lower },
|
|
trial_period_days: 0,
|
|
promotion_code: 'promo123'
|
|
).returns(status: 'active', customer: 'cus_1234')
|
|
|
|
expect {
|
|
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' }
|
|
}.to change { DiscourseSubscriptions::Customer.count }
|
|
|
|
end
|
|
|
|
it "applies promo code to one time purchase" do
|
|
::Stripe::Price.expects(:retrieve).returns(
|
|
type: 'one_time',
|
|
product: 'product_12345',
|
|
metadata: {
|
|
group_name: 'awesome'
|
|
}
|
|
)
|
|
|
|
::Stripe::InvoiceItem.expects(:create).with(customer: 'cus_1234', price: 'plan_1234', discounts: [{ coupon: 'c123' }])
|
|
|
|
::Stripe::Invoice.expects(:create).returns(status: 'open', id: 'in_123')
|
|
|
|
::Stripe::Invoice.expects(:finalize_invoice).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123')
|
|
|
|
::Stripe::Invoice.expects(:retrieve).returns(id: 'in_123', status: 'open', payment_intent: 'pi_123')
|
|
|
|
::Stripe::PaymentIntent.expects(:retrieve).returns(status: 'successful')
|
|
|
|
::Stripe::Invoice.expects(:pay).returns(status: 'paid', customer: 'cus_1234')
|
|
|
|
expect {
|
|
post '/s/create.json', params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' }
|
|
}.to change { DiscourseSubscriptions::Customer.count }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#finalize strong customer authenticated transaction" do
|
|
context "with subscription" do
|
|
it "finalizes the subscription" do
|
|
::Stripe::Price.expects(:retrieve).returns(id: "plan_1234", product: "prod_1234", metadata: {})
|
|
::Stripe::Subscription.expects(:retrieve).returns(id: "sub_123", customer: 'cus_1234', status: "active")
|
|
|
|
expect {
|
|
post "/s/finalize.json", params: { plan: 'plan_1234', transaction: 'sub_1234' }
|
|
}.to change { DiscourseSubscriptions::Customer.count }
|
|
end
|
|
end
|
|
|
|
context "with one-time payment" do
|
|
it "finalizes the one-time payment" do
|
|
::Stripe::Price.expects(:retrieve).returns(id: "plan_1234", product: "prod_1234", metadata: {})
|
|
::Stripe::Invoice.expects(:retrieve).returns(id: "in_123", customer: 'cus_1234', status: "paid")
|
|
|
|
expect {
|
|
post "/s/finalize.json", params: { plan: 'plan_1234', transaction: 'in_1234' }
|
|
}.to change { DiscourseSubscriptions::Customer.count }
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "user groups" do
|
|
let(:group_name) { 'group-123' }
|
|
let(:group) { Fabricate(:group, name: group_name) }
|
|
|
|
context "unauthorized group" do
|
|
before do
|
|
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
|
|
::Stripe::Subscription.expects(:create).returns(status: 'active')
|
|
end
|
|
|
|
it "does not add the user to the admins group" do
|
|
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: 'admins' })
|
|
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
|
expect(user.admin).to eq false
|
|
end
|
|
|
|
it "does not add the user to other group" do
|
|
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: 'other' })
|
|
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
|
expect(user.groups).to be_empty
|
|
end
|
|
end
|
|
|
|
context "plan has group in metadata" do
|
|
before do
|
|
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
|
|
::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
|
|
::Stripe::Subscription.expects(:create).returns(status: 'failed')
|
|
|
|
expect {
|
|
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
|
}.not_to change { group.users.count }
|
|
|
|
expect(user.groups).to be_empty
|
|
end
|
|
|
|
it "adds the user to the group when the subscription is active" do
|
|
::Stripe::Subscription.expects(:create).returns(status: 'active')
|
|
|
|
expect {
|
|
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
|
}.to change { group.users.count }
|
|
|
|
expect(user.groups).not_to be_empty
|
|
end
|
|
|
|
it "adds the user to the group when the subscription is trialing" do
|
|
::Stripe::Subscription.expects(:create).returns(status: 'trialing')
|
|
|
|
expect {
|
|
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
|
}.to change { group.users.count }
|
|
|
|
expect(user.groups).not_to be_empty
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|