DEV: Introduce syntax_tree for ruby formatting (#144)
This commit is contained in:
parent
cbbc23fd5a
commit
4e1a17c40c
|
@ -55,3 +55,12 @@ jobs:
|
||||||
- name: Rubocop
|
- name: Rubocop
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
run: bundle exec rubocop .
|
run: bundle exec rubocop .
|
||||||
|
|
||||||
|
- name: Syntax Tree
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
run: |
|
||||||
|
if test -f .streerc; then
|
||||||
|
bundle exec stree check Gemfile $(git ls-files '*.rb') $(git ls-files '*.rake')
|
||||||
|
else
|
||||||
|
echo "Stree config not detected for this repository. Skipping."
|
||||||
|
fi
|
||||||
|
|
|
@ -80,7 +80,7 @@ jobs:
|
||||||
|
|
||||||
- name: Get yarn cache directory
|
- name: Get yarn cache directory
|
||||||
id: yarn-cache-dir
|
id: yarn-cache-dir
|
||||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Yarn cache
|
- name: Yarn cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
|
@ -130,7 +130,7 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
if [ 0 -lt $(find plugins/${{ github.event.repository.name }}/spec -type f -name "*.rb" 2> /dev/null | wc -l) ]; then
|
if [ 0 -lt $(find plugins/${{ github.event.repository.name }}/spec -type f -name "*.rb" 2> /dev/null | wc -l) ]; then
|
||||||
echo "::set-output name=files_exist::true"
|
echo "files_exist=true" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Plugin RSpec
|
- name: Plugin RSpec
|
||||||
|
@ -142,7 +142,7 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
if [ 0 -lt $(find plugins/${{ github.event.repository.name }}/test/javascripts -type f \( -name "*.js" -or -name "*.es6" \) 2> /dev/null | wc -l) ]; then
|
if [ 0 -lt $(find plugins/${{ github.event.repository.name }}/test/javascripts -type f \( -name "*.js" -or -name "*.es6" \) 2> /dev/null | wc -l) ]; then
|
||||||
echo "::set-output name=files_exist::true"
|
echo "files_exist=true" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Plugin QUnit
|
- name: Plugin QUnit
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
inherit_gem:
|
inherit_gem:
|
||||||
rubocop-discourse: default.yml
|
rubocop-discourse: stree-compat.yml
|
||||||
AllCops:
|
AllCops:
|
||||||
Exclude:
|
Exclude:
|
||||||
- "gems/**/*"
|
- "gems/**/*"
|
||||||
|
|
7
Gemfile
7
Gemfile
|
@ -1,8 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
source 'https://rubygems.org'
|
source "https://rubygems.org"
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'translations-manager', git: 'https://github.com/discourse/translations-manager.git'
|
gem "translations-manager", git: "https://github.com/discourse/translations-manager.git"
|
||||||
gem 'rubocop-discourse'
|
gem "rubocop-discourse"
|
||||||
|
gem "syntax_tree"
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,7 @@ GEM
|
||||||
parallel (1.22.1)
|
parallel (1.22.1)
|
||||||
parser (3.1.2.1)
|
parser (3.1.2.1)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
|
prettier_print (1.2.0)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
regexp_parser (2.6.0)
|
regexp_parser (2.6.0)
|
||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
|
@ -33,6 +34,8 @@ GEM
|
||||||
rubocop-rspec (2.13.2)
|
rubocop-rspec (2.13.2)
|
||||||
rubocop (~> 1.33)
|
rubocop (~> 1.33)
|
||||||
ruby-progressbar (1.11.0)
|
ruby-progressbar (1.11.0)
|
||||||
|
syntax_tree (5.1.0)
|
||||||
|
prettier_print (>= 1.2.0)
|
||||||
unicode-display_width (2.3.0)
|
unicode-display_width (2.3.0)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
|
@ -40,6 +43,7 @@ PLATFORMS
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
rubocop-discourse
|
rubocop-discourse
|
||||||
|
syntax_tree
|
||||||
translations-manager!
|
translations-manager!
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
|
|
|
@ -9,7 +9,8 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_stripe_configured?
|
def is_stripe_configured?
|
||||||
SiteSetting.discourse_subscriptions_public_key.present? && SiteSetting.discourse_subscriptions_secret_key.present?
|
SiteSetting.discourse_subscriptions_public_key.present? &&
|
||||||
|
SiteSetting.discourse_subscriptions_secret_key.present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,23 +18,24 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
params.require([:promo, :discount_type, :discount, :active])
|
params.require(%i[promo discount_type discount active])
|
||||||
begin
|
begin
|
||||||
coupon_params = {
|
coupon_params = { duration: "forever" }
|
||||||
duration: 'forever',
|
|
||||||
}
|
|
||||||
|
|
||||||
case params[:discount_type]
|
case params[:discount_type]
|
||||||
when 'amount'
|
when "amount"
|
||||||
coupon_params[:amount_off] = params[:discount].to_i * 100
|
coupon_params[:amount_off] = params[:discount].to_i * 100
|
||||||
coupon_params[:currency] = SiteSetting.discourse_subscriptions_currency
|
coupon_params[:currency] = SiteSetting.discourse_subscriptions_currency
|
||||||
when 'percent'
|
when "percent"
|
||||||
coupon_params[:percent_off] = params[:discount]
|
coupon_params[:percent_off] = params[:discount]
|
||||||
end
|
end
|
||||||
|
|
||||||
coupon = ::Stripe::Coupon.create(coupon_params)
|
coupon = ::Stripe::Coupon.create(coupon_params)
|
||||||
|
|
||||||
promo_code = ::Stripe::PromotionCode.create({ coupon: coupon[:id], code: params[:promo] }) if coupon.present?
|
promo_code =
|
||||||
|
::Stripe::PromotionCode.create(
|
||||||
|
{ coupon: coupon[:id], code: params[:promo] },
|
||||||
|
) if coupon.present?
|
||||||
|
|
||||||
render_json_dump promo_code
|
render_json_dump promo_code
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
|
@ -43,14 +44,9 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
params.require([:id, :active])
|
params.require(%i[id active])
|
||||||
begin
|
begin
|
||||||
promo_code = ::Stripe::PromotionCode.update(
|
promo_code = ::Stripe::PromotionCode.update(params[:id], { active: params[:active] })
|
||||||
params[:id],
|
|
||||||
{
|
|
||||||
active: params[:active]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
render_json_dump promo_code
|
render_json_dump promo_code
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
|
|
|
@ -27,15 +27,11 @@ module DiscourseSubscriptions
|
||||||
active: params[:active],
|
active: params[:active],
|
||||||
metadata: {
|
metadata: {
|
||||||
group_name: params[:metadata][:group_name],
|
group_name: params[:metadata][:group_name],
|
||||||
trial_period_days: params[:trial_period_days]
|
trial_period_days: params[:trial_period_days],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if params[:type] == 'recurring'
|
price_object[:recurring] = { interval: params[:interval] } if params[:type] == "recurring"
|
||||||
price_object[:recurring] = {
|
|
||||||
interval: params[:interval]
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
plan = ::Stripe::Price.create(price_object)
|
plan = ::Stripe::Price.create(price_object)
|
||||||
|
|
||||||
|
@ -56,14 +52,16 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
interval = nil
|
interval = nil
|
||||||
if plan[:recurring] && plan[:recurring][:interval]
|
interval = plan[:recurring][:interval] if plan[:recurring] && plan[:recurring][:interval]
|
||||||
interval = plan[:recurring][:interval]
|
|
||||||
end
|
|
||||||
|
|
||||||
serialized = plan.to_h.merge(trial_period_days: trial_days, currency: plan[:currency].upcase, interval: interval)
|
serialized =
|
||||||
|
plan.to_h.merge(
|
||||||
|
trial_period_days: trial_days,
|
||||||
|
currency: plan[:currency].upcase,
|
||||||
|
interval: interval,
|
||||||
|
)
|
||||||
|
|
||||||
render_json_dump serialized
|
render_json_dump serialized
|
||||||
|
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -71,15 +69,16 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
def update
|
def update
|
||||||
begin
|
begin
|
||||||
plan = ::Stripe::Price.update(
|
plan =
|
||||||
params[:id],
|
::Stripe::Price.update(
|
||||||
nickname: params[:nickname],
|
params[:id],
|
||||||
active: params[:active],
|
nickname: params[:nickname],
|
||||||
metadata: {
|
active: params[:active],
|
||||||
group_name: params[:metadata][:group_name],
|
metadata: {
|
||||||
trial_period_days: params[:trial_period_days]
|
group_name: params[:metadata][:group_name],
|
||||||
}
|
trial_period_days: params[:trial_period_days],
|
||||||
)
|
},
|
||||||
|
)
|
||||||
|
|
||||||
render_json_dump plan
|
render_json_dump plan
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
|
|
|
@ -27,20 +27,15 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
def create
|
def create
|
||||||
begin
|
begin
|
||||||
create_params = product_params.merge!(type: 'service')
|
create_params = product_params.merge!(type: "service")
|
||||||
|
|
||||||
if params[:statement_descriptor].blank?
|
create_params.except!(:statement_descriptor) if params[:statement_descriptor].blank?
|
||||||
create_params.except!(:statement_descriptor)
|
|
||||||
end
|
|
||||||
|
|
||||||
product = ::Stripe::Product.create(create_params)
|
product = ::Stripe::Product.create(create_params)
|
||||||
|
|
||||||
Product.create(
|
Product.create(external_id: product[:id])
|
||||||
external_id: product[:id]
|
|
||||||
)
|
|
||||||
|
|
||||||
render_json_dump product
|
render_json_dump product
|
||||||
|
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -51,7 +46,6 @@ module DiscourseSubscriptions
|
||||||
product = ::Stripe::Product.retrieve(params[:id])
|
product = ::Stripe::Product.retrieve(params[:id])
|
||||||
|
|
||||||
render_json_dump product
|
render_json_dump product
|
||||||
|
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -59,13 +53,9 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
def update
|
def update
|
||||||
begin
|
begin
|
||||||
product = ::Stripe::Product.update(
|
product = ::Stripe::Product.update(params[:id], product_params)
|
||||||
params[:id],
|
|
||||||
product_params
|
|
||||||
)
|
|
||||||
|
|
||||||
render_json_dump product
|
render_json_dump product
|
||||||
|
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -78,7 +68,6 @@ module DiscourseSubscriptions
|
||||||
Product.delete_by(external_id: params[:id])
|
Product.delete_by(external_id: params[:id])
|
||||||
|
|
||||||
render_json_dump product
|
render_json_dump product
|
||||||
|
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -95,8 +84,8 @@ module DiscourseSubscriptions
|
||||||
statement_descriptor: params[:statement_descriptor],
|
statement_descriptor: params[:statement_descriptor],
|
||||||
metadata: {
|
metadata: {
|
||||||
description: params.dig(:metadata, :description),
|
description: params.dig(:metadata, :description),
|
||||||
repurchaseable: params.dig(:metadata, :repurchaseable)
|
repurchaseable: params.dig(:metadata, :repurchaseable),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,20 +16,23 @@ module DiscourseSubscriptions
|
||||||
has_more: false,
|
has_more: false,
|
||||||
data: [],
|
data: [],
|
||||||
length: 0,
|
length: 0,
|
||||||
last_record: params[:last_record]
|
last_record: params[:last_record],
|
||||||
}
|
}
|
||||||
|
|
||||||
if subscription_ids.present? && is_stripe_configured?
|
if subscription_ids.present? && is_stripe_configured?
|
||||||
while subscriptions[:length] < PAGE_LIMIT
|
while subscriptions[:length] < PAGE_LIMIT
|
||||||
current_set = get_subscriptions(subscriptions[:last_record])
|
current_set = get_subscriptions(subscriptions[:last_record])
|
||||||
|
|
||||||
until valid_subscriptions = find_valid_subscriptions(current_set[:data], subscription_ids) do
|
until valid_subscriptions =
|
||||||
|
find_valid_subscriptions(current_set[:data], subscription_ids)
|
||||||
current_set = get_subscriptions(current_set[:data].last)
|
current_set = get_subscriptions(current_set[:data].last)
|
||||||
break if current_set[:has_more] == false
|
break if current_set[:has_more] == false
|
||||||
end
|
end
|
||||||
|
|
||||||
subscriptions[:data] = subscriptions[:data].concat(valid_subscriptions.to_a)
|
subscriptions[:data] = subscriptions[:data].concat(valid_subscriptions.to_a)
|
||||||
subscriptions[:last_record] = current_set[:data].last[:id] if current_set[:data].present?
|
subscriptions[:last_record] = current_set[:data].last[:id] if current_set[
|
||||||
|
:data
|
||||||
|
].present?
|
||||||
subscriptions[:length] = subscriptions[:data].length
|
subscriptions[:length] = subscriptions[:data].length
|
||||||
subscriptions[:has_more] = current_set[:has_more]
|
subscriptions[:has_more] = current_set[:has_more]
|
||||||
break if subscriptions[:has_more] == false
|
break if subscriptions[:has_more] == false
|
||||||
|
@ -50,10 +53,11 @@ module DiscourseSubscriptions
|
||||||
refund_subscription(params[:id]) if params[:refund]
|
refund_subscription(params[:id]) if params[:refund]
|
||||||
subscription = ::Stripe::Subscription.delete(params[:id])
|
subscription = ::Stripe::Subscription.delete(params[:id])
|
||||||
|
|
||||||
customer = Customer.find_by(
|
customer =
|
||||||
product_id: subscription[:plan][:product],
|
Customer.find_by(
|
||||||
customer_id: subscription[:customer]
|
product_id: subscription[:plan][:product],
|
||||||
)
|
customer_id: subscription[:customer],
|
||||||
|
)
|
||||||
|
|
||||||
Subscription.delete_by(external_id: params[:id])
|
Subscription.delete_by(external_id: params[:id])
|
||||||
|
|
||||||
|
@ -65,7 +69,6 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
render_json_dump subscription
|
render_json_dump subscription
|
||||||
|
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -74,7 +77,11 @@ module DiscourseSubscriptions
|
||||||
private
|
private
|
||||||
|
|
||||||
def get_subscriptions(start)
|
def get_subscriptions(start)
|
||||||
::Stripe::Subscription.list(expand: ['data.plan.product'], limit: PAGE_LIMIT, starting_after: start)
|
::Stripe::Subscription.list(
|
||||||
|
expand: ["data.plan.product"],
|
||||||
|
limit: PAGE_LIMIT,
|
||||||
|
starting_after: start,
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_valid_subscriptions(data, ids)
|
def find_valid_subscriptions(data, ids)
|
||||||
|
@ -85,11 +92,11 @@ module DiscourseSubscriptions
|
||||||
# this will only refund the most recent subscription payment
|
# this will only refund the most recent subscription payment
|
||||||
def refund_subscription(subscription_id)
|
def refund_subscription(subscription_id)
|
||||||
subscription = ::Stripe::Subscription.retrieve(subscription_id)
|
subscription = ::Stripe::Subscription.retrieve(subscription_id)
|
||||||
invoice = ::Stripe::Invoice.retrieve(subscription[:latest_invoice]) if subscription[:latest_invoice]
|
invoice = ::Stripe::Invoice.retrieve(subscription[:latest_invoice]) if subscription[
|
||||||
|
:latest_invoice
|
||||||
|
]
|
||||||
payment_intent = invoice[:payment_intent] if invoice[:payment_intent]
|
payment_intent = invoice[:payment_intent] if invoice[:payment_intent]
|
||||||
refund = ::Stripe::Refund.create({
|
refund = ::Stripe::Refund.create({ payment_intent: payment_intent })
|
||||||
payment_intent: payment_intent,
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,7 +14,7 @@ module DiscourseSubscriptions
|
||||||
def create
|
def create
|
||||||
begin
|
begin
|
||||||
payload = request.body.read
|
payload = request.body.read
|
||||||
sig_header = request.env['HTTP_STRIPE_SIGNATURE']
|
sig_header = request.env["HTTP_STRIPE_SIGNATURE"]
|
||||||
webhook_secret = SiteSetting.discourse_subscriptions_webhook_secret
|
webhook_secret = SiteSetting.discourse_subscriptions_webhook_secret
|
||||||
|
|
||||||
event = ::Stripe::Webhook.construct_event(payload, sig_header, webhook_secret)
|
event = ::Stripe::Webhook.construct_event(payload, sig_header, webhook_secret)
|
||||||
|
@ -25,37 +25,39 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
case event[:type]
|
case event[:type]
|
||||||
when 'customer.subscription.created'
|
when "customer.subscription.created"
|
||||||
when 'customer.subscription.updated'
|
when "customer.subscription.updated"
|
||||||
customer = Customer.find_by(
|
customer =
|
||||||
customer_id: event[:data][:object][:customer],
|
Customer.find_by(
|
||||||
product_id: event[:data][:object][:plan][:product],
|
customer_id: event[:data][:object][:customer],
|
||||||
)
|
product_id: event[:data][:object][:plan][:product],
|
||||||
|
)
|
||||||
|
|
||||||
return render_json_error 'customer not found' if !customer
|
return render_json_error "customer not found" if !customer
|
||||||
return head 200 if event[:data][:object][:status] != 'complete'
|
return head 200 if event[:data][:object][:status] != "complete"
|
||||||
|
|
||||||
user = ::User.find_by(id: customer.user_id)
|
user = ::User.find_by(id: customer.user_id)
|
||||||
return render_json_error 'user not found' if !user
|
return render_json_error "user not found" if !user
|
||||||
|
|
||||||
if group = plan_group(event[:data][:object][:plan])
|
if group = plan_group(event[:data][:object][:plan])
|
||||||
group.add(user)
|
group.add(user)
|
||||||
end
|
end
|
||||||
when 'customer.subscription.deleted'
|
when "customer.subscription.deleted"
|
||||||
customer = Customer.find_by(
|
customer =
|
||||||
customer_id: event[:data][:object][:customer],
|
Customer.find_by(
|
||||||
product_id: event[:data][:object][:plan][:product],
|
customer_id: event[:data][:object][:customer],
|
||||||
)
|
product_id: event[:data][:object][:plan][:product],
|
||||||
|
)
|
||||||
|
|
||||||
return render_json_error 'customer not found' if !customer
|
return render_json_error "customer not found" if !customer
|
||||||
|
|
||||||
Subscription.find_by(
|
Subscription.find_by(
|
||||||
customer_id: customer.id,
|
customer_id: customer.id,
|
||||||
external_id: event[:data][:object][:id]
|
external_id: event[:data][:object][:id],
|
||||||
)&.destroy!
|
)&.destroy!
|
||||||
|
|
||||||
user = ::User.find(customer.user_id)
|
user = ::User.find(customer.user_id)
|
||||||
return render_json_error 'user not found' if !user
|
return render_json_error "user not found" if !user
|
||||||
|
|
||||||
if group = plan_group(event[:data][:object][:plan])
|
if group = plan_group(event[:data][:object][:plan])
|
||||||
group.remove(user)
|
group.remove(user)
|
||||||
|
|
|
@ -5,7 +5,7 @@ module DiscourseSubscriptions
|
||||||
include DiscourseSubscriptions::Stripe
|
include DiscourseSubscriptions::Stripe
|
||||||
include DiscourseSubscriptions::Group
|
include DiscourseSubscriptions::Group
|
||||||
before_action :set_api_key
|
before_action :set_api_key
|
||||||
requires_login except: [:index, :contributors, :show]
|
requires_login except: %i[index contributors show]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
begin
|
begin
|
||||||
|
@ -13,19 +13,12 @@ module DiscourseSubscriptions
|
||||||
products = []
|
products = []
|
||||||
|
|
||||||
if product_ids.present? && is_stripe_configured?
|
if product_ids.present? && is_stripe_configured?
|
||||||
response = ::Stripe::Product.list({
|
response = ::Stripe::Product.list({ ids: product_ids, active: true })
|
||||||
ids: product_ids,
|
|
||||||
active: true
|
|
||||||
})
|
|
||||||
|
|
||||||
products = response[:data].map do |p|
|
|
||||||
serialize_product(p)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
products = response[:data].map { |p| serialize_product(p) }
|
||||||
end
|
end
|
||||||
|
|
||||||
render_json_dump products
|
render_json_dump products
|
||||||
|
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -36,7 +29,11 @@ module DiscourseSubscriptions
|
||||||
contributor_ids = Set.new
|
contributor_ids = Set.new
|
||||||
|
|
||||||
campaign_product = SiteSetting.discourse_subscriptions_campaign_product
|
campaign_product = SiteSetting.discourse_subscriptions_campaign_product
|
||||||
campaign_product.present? ? contributor_ids.merge(Customer.where(product_id: campaign_product).last(5).pluck(:user_id)) : contributor_ids.merge(Customer.last(5).pluck(:user_id))
|
if campaign_product.present?
|
||||||
|
contributor_ids.merge(Customer.where(product_id: campaign_product).last(5).pluck(:user_id))
|
||||||
|
else
|
||||||
|
contributor_ids.merge(Customer.last(5).pluck(:user_id))
|
||||||
|
end
|
||||||
|
|
||||||
contributors = ::User.where(id: contributor_ids)
|
contributors = ::User.where(id: contributor_ids)
|
||||||
|
|
||||||
|
@ -49,10 +46,7 @@ module DiscourseSubscriptions
|
||||||
product = ::Stripe::Product.retrieve(params[:id])
|
product = ::Stripe::Product.retrieve(params[:id])
|
||||||
plans = ::Stripe::Price.list(active: true, product: params[:id])
|
plans = ::Stripe::Price.list(active: true, product: params[:id])
|
||||||
|
|
||||||
response = {
|
response = { product: serialize_product(product), plans: serialize_plans(plans) }
|
||||||
product: serialize_product(product),
|
|
||||||
plans: serialize_plans(plans)
|
|
||||||
}
|
|
||||||
|
|
||||||
render_json_dump response
|
render_json_dump response
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
|
@ -61,7 +55,7 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
params.require([:source, :plan])
|
params.require(%i[source plan])
|
||||||
begin
|
begin
|
||||||
customer = find_or_create_customer(params[:source])
|
customer = find_or_create_customer(params[:source])
|
||||||
plan = ::Stripe::Price.retrieve(params[:plan])
|
plan = ::Stripe::Price.retrieve(params[:plan])
|
||||||
|
@ -70,38 +64,46 @@ module DiscourseSubscriptions
|
||||||
promo_code = ::Stripe::PromotionCode.list({ code: params[:promo] })
|
promo_code = ::Stripe::PromotionCode.list({ code: params[:promo] })
|
||||||
promo_code = promo_code[:data][0] # we assume promo codes have a unique name
|
promo_code = promo_code[:data][0] # we assume promo codes have a unique name
|
||||||
|
|
||||||
return render_json_error I18n.t("js.discourse_subscriptions.subscribe.invalid_coupon") if promo_code.blank?
|
if promo_code.blank?
|
||||||
|
return render_json_error I18n.t("js.discourse_subscriptions.subscribe.invalid_coupon")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
recurring_plan = plan[:type] == 'recurring'
|
recurring_plan = plan[:type] == "recurring"
|
||||||
|
|
||||||
if recurring_plan
|
if recurring_plan
|
||||||
trial_days = plan[:metadata][:trial_period_days] if plan[:metadata] && plan[:metadata][:trial_period_days]
|
trial_days = plan[:metadata][:trial_period_days] if plan[:metadata] &&
|
||||||
|
plan[:metadata][:trial_period_days]
|
||||||
|
|
||||||
promo_code_id = promo_code[:id] if promo_code
|
promo_code_id = promo_code[:id] if promo_code
|
||||||
|
|
||||||
transaction = ::Stripe::Subscription.create(
|
transaction =
|
||||||
customer: customer[:id],
|
::Stripe::Subscription.create(
|
||||||
items: [{ price: params[:plan] }],
|
customer: customer[:id],
|
||||||
metadata: metadata_user,
|
items: [{ price: params[:plan] }],
|
||||||
trial_period_days: trial_days,
|
metadata: metadata_user,
|
||||||
promotion_code: promo_code_id
|
trial_period_days: trial_days,
|
||||||
)
|
promotion_code: promo_code_id,
|
||||||
|
)
|
||||||
|
|
||||||
payment_intent = retrieve_payment_intent(transaction[:latest_invoice]) if transaction[:status] == 'incomplete'
|
payment_intent = retrieve_payment_intent(transaction[:latest_invoice]) if transaction[
|
||||||
|
:status
|
||||||
|
] == "incomplete"
|
||||||
else
|
else
|
||||||
coupon_id = promo_code[:coupon][:id] if promo_code && promo_code[:coupon] && promo_code[:coupon][:id]
|
coupon_id = promo_code[:coupon][:id] if promo_code && promo_code[:coupon] &&
|
||||||
invoice_item = ::Stripe::InvoiceItem.create(
|
promo_code[:coupon][:id]
|
||||||
customer: customer[:id],
|
invoice_item =
|
||||||
price: params[:plan],
|
::Stripe::InvoiceItem.create(
|
||||||
discounts: [{ coupon: coupon_id }]
|
customer: customer[:id],
|
||||||
)
|
price: params[:plan],
|
||||||
invoice = ::Stripe::Invoice.create(
|
discounts: [{ coupon: coupon_id }],
|
||||||
customer: customer[:id]
|
)
|
||||||
)
|
invoice = ::Stripe::Invoice.create(customer: customer[:id])
|
||||||
transaction = ::Stripe::Invoice.finalize_invoice(invoice[:id])
|
transaction = ::Stripe::Invoice.finalize_invoice(invoice[:id])
|
||||||
payment_intent = retrieve_payment_intent(transaction[:id]) if transaction[:status] == 'open'
|
payment_intent = retrieve_payment_intent(transaction[:id]) if transaction[:status] ==
|
||||||
transaction = ::Stripe::Invoice.pay(invoice[:id]) if payment_intent[:status] == 'successful'
|
"open"
|
||||||
|
transaction = ::Stripe::Invoice.pay(invoice[:id]) if payment_intent[:status] ==
|
||||||
|
"successful"
|
||||||
end
|
end
|
||||||
|
|
||||||
finalize_transaction(transaction, plan) if transaction_ok(transaction)
|
finalize_transaction(transaction, plan) if transaction_ok(transaction)
|
||||||
|
@ -115,7 +117,7 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
def finalize
|
def finalize
|
||||||
params.require([:plan, :transaction])
|
params.require(%i[plan transaction])
|
||||||
begin
|
begin
|
||||||
price = ::Stripe::Price.retrieve(params[:plan])
|
price = ::Stripe::Price.retrieve(params[:plan])
|
||||||
transaction = retrieve_transaction(params[:transaction])
|
transaction = retrieve_transaction(params[:transaction])
|
||||||
|
@ -132,17 +134,15 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
group.add(current_user) if group
|
group.add(current_user) if group
|
||||||
|
|
||||||
customer = Customer.create(
|
customer =
|
||||||
user_id: current_user.id,
|
Customer.create(
|
||||||
customer_id: transaction[:customer],
|
user_id: current_user.id,
|
||||||
product_id: plan[:product]
|
customer_id: transaction[:customer],
|
||||||
)
|
product_id: plan[:product],
|
||||||
|
|
||||||
if transaction[:object] == 'subscription'
|
|
||||||
Subscription.create(
|
|
||||||
customer_id: customer.id,
|
|
||||||
external_id: transaction[:id]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if transaction[:object] == "subscription"
|
||||||
|
Subscription.create(customer_id: customer.id, external_id: transaction[:id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -154,23 +154,20 @@ module DiscourseSubscriptions
|
||||||
name: product[:name],
|
name: product[:name],
|
||||||
description: PrettyText.cook(product[:metadata][:description]),
|
description: PrettyText.cook(product[:metadata][:description]),
|
||||||
subscribed: current_user_products.include?(product[:id]),
|
subscribed: current_user_products.include?(product[:id]),
|
||||||
repurchaseable: product[:metadata][:repurchaseable]
|
repurchaseable: product[:metadata][:repurchaseable],
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_user_products
|
def current_user_products
|
||||||
return [] if current_user.nil?
|
return [] if current_user.nil?
|
||||||
|
|
||||||
Customer
|
Customer.select(:product_id).where(user_id: current_user.id).map { |c| c.product_id }.compact
|
||||||
.select(:product_id)
|
|
||||||
.where(user_id: current_user.id)
|
|
||||||
.map { |c| c.product_id }.compact
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def serialize_plans(plans)
|
def serialize_plans(plans)
|
||||||
plans[:data].map do |plan|
|
plans[:data]
|
||||||
plan.to_h.slice(:id, :unit_amount, :currency, :type, :recurring)
|
.map { |plan| plan.to_h.slice(:id, :unit_amount, :currency, :type, :recurring) }
|
||||||
end.sort_by { |plan| plan[:amount] }
|
.sort_by { |plan| plan[:amount] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_or_create_customer(source)
|
def find_or_create_customer(source)
|
||||||
|
@ -179,10 +176,7 @@ module DiscourseSubscriptions
|
||||||
if customer.present?
|
if customer.present?
|
||||||
::Stripe::Customer.retrieve(customer.customer_id)
|
::Stripe::Customer.retrieve(customer.customer_id)
|
||||||
else
|
else
|
||||||
::Stripe::Customer.create(
|
::Stripe::Customer.create(email: current_user.email, source: source)
|
||||||
email: current_user.email,
|
|
||||||
source: source
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,8 @@ module DiscourseSubscriptions
|
||||||
invoices_with_products = parse_invoices(all_invoices, product_ids)
|
invoices_with_products = parse_invoices(all_invoices, product_ids)
|
||||||
invoice_ids = invoices_with_products.map { |invoice| invoice[:id] }
|
invoice_ids = invoices_with_products.map { |invoice| invoice[:id] }
|
||||||
payments = ::Stripe::PaymentIntent.list(customer: customer_id)
|
payments = ::Stripe::PaymentIntent.list(customer: customer_id)
|
||||||
payments_from_invoices = payments[:data].select { |payment| invoice_ids.include?(payment[:invoice]) }
|
payments_from_invoices =
|
||||||
|
payments[:data].select { |payment| invoice_ids.include?(payment[:invoice]) }
|
||||||
data = data | payments_from_invoices
|
data = data | payments_from_invoices
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -30,7 +31,6 @@ module DiscourseSubscriptions
|
||||||
data = data.sort_by { |pmt| pmt[:created] }.reverse
|
data = data.sort_by { |pmt| pmt[:created] }.reverse
|
||||||
|
|
||||||
render_json_dump data
|
render_json_dump data
|
||||||
|
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -39,16 +39,19 @@ module DiscourseSubscriptions
|
||||||
private
|
private
|
||||||
|
|
||||||
def parse_invoices(all_invoices, product_ids)
|
def parse_invoices(all_invoices, product_ids)
|
||||||
invoices_with_products = all_invoices[:data].select do |invoice|
|
invoices_with_products =
|
||||||
invoice_lines = invoice[:lines][:data][0] if invoice[:lines] && invoice[:lines][:data]
|
all_invoices[:data].select do |invoice|
|
||||||
invoice_product_id = parse_invoice_lines(invoice_lines)
|
invoice_lines = invoice[:lines][:data][0] if invoice[:lines] && invoice[:lines][:data]
|
||||||
product_ids.include?(invoice_product_id)
|
invoice_product_id = parse_invoice_lines(invoice_lines)
|
||||||
end
|
product_ids.include?(invoice_product_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_invoice_lines(invoice_lines)
|
def parse_invoice_lines(invoice_lines)
|
||||||
invoice_product_id = invoice_lines[:price][:product] if invoice_lines[:price] && invoice_lines[:price][:product]
|
invoice_product_id = invoice_lines[:price][:product] if invoice_lines[:price] &&
|
||||||
invoice_product_id = invoice_lines[:plan][:product] if invoice_lines[:plan] && invoice_lines[:plan][:product]
|
invoice_lines[:price][:product]
|
||||||
|
invoice_product_id = invoice_lines[:plan][:product] if invoice_lines[:plan] &&
|
||||||
|
invoice_lines[:plan][:product]
|
||||||
invoice_product_id
|
invoice_product_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,24 +12,21 @@ module DiscourseSubscriptions
|
||||||
begin
|
begin
|
||||||
customer = Customer.where(user_id: current_user.id)
|
customer = Customer.where(user_id: current_user.id)
|
||||||
customer_ids = customer.map { |c| c.id } if customer
|
customer_ids = customer.map { |c| c.id } if customer
|
||||||
subscription_ids = Subscription.where("customer_id in (?)", customer_ids).pluck(:external_id) if customer_ids
|
subscription_ids =
|
||||||
|
Subscription.where("customer_id in (?)", customer_ids).pluck(
|
||||||
|
:external_id,
|
||||||
|
) if customer_ids
|
||||||
|
|
||||||
subscriptions = []
|
subscriptions = []
|
||||||
|
|
||||||
if subscription_ids
|
if subscription_ids
|
||||||
plans = ::Stripe::Price.list(
|
plans = ::Stripe::Price.list(expand: ["data.product"], limit: 100)
|
||||||
expand: ['data.product'],
|
|
||||||
limit: 100
|
|
||||||
)
|
|
||||||
|
|
||||||
customers = ::Stripe::Customer.list(
|
customers =
|
||||||
email: current_user.email,
|
::Stripe::Customer.list(email: current_user.email, expand: ["data.subscriptions"])
|
||||||
expand: ['data.subscriptions']
|
|
||||||
)
|
|
||||||
|
|
||||||
subscriptions = customers[:data].map do |sub_customer|
|
subscriptions =
|
||||||
sub_customer[:subscriptions][:data]
|
customers[:data].map { |sub_customer| sub_customer[:subscriptions][:data] }.flatten(1)
|
||||||
end.flatten(1)
|
|
||||||
|
|
||||||
subscriptions = subscriptions.select { |sub| subscription_ids.include?(sub[:id]) }
|
subscriptions = subscriptions.select { |sub| subscription_ids.include?(sub[:id]) }
|
||||||
|
|
||||||
|
@ -41,7 +38,6 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
render_json_dump subscriptions
|
render_json_dump subscriptions
|
||||||
|
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -51,14 +47,13 @@ module DiscourseSubscriptions
|
||||||
# we cancel but don't remove until the end of the period
|
# we cancel but don't remove until the end of the period
|
||||||
# full removal is done via webhooks
|
# full removal is done via webhooks
|
||||||
begin
|
begin
|
||||||
subscription = ::Stripe::Subscription.update(params[:id], { cancel_at_period_end: true, })
|
subscription = ::Stripe::Subscription.update(params[:id], { cancel_at_period_end: true })
|
||||||
|
|
||||||
if subscription
|
if subscription
|
||||||
render_json_dump subscription
|
render_json_dump subscription
|
||||||
else
|
else
|
||||||
render_json_error I18n.t('discourse_subscriptions.customer_not_found')
|
render_json_error I18n.t("discourse_subscriptions.customer_not_found")
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue ::Stripe::InvalidRequestError => e
|
rescue ::Stripe::InvalidRequestError => e
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
|
@ -70,7 +65,11 @@ module DiscourseSubscriptions
|
||||||
subscription = Subscription.where(external_id: params[:id]).first
|
subscription = Subscription.where(external_id: params[:id]).first
|
||||||
begin
|
begin
|
||||||
attach_method_to_customer(subscription.customer_id, params[:payment_method])
|
attach_method_to_customer(subscription.customer_id, params[:payment_method])
|
||||||
subscription = ::Stripe::Subscription.update(params[:id], { default_payment_method: params[:payment_method] })
|
subscription =
|
||||||
|
::Stripe::Subscription.update(
|
||||||
|
params[:id],
|
||||||
|
{ default_payment_method: params[:payment_method] },
|
||||||
|
)
|
||||||
render json: success_json
|
render json: success_json
|
||||||
rescue ::Stripe::InvalidRequestError
|
rescue ::Stripe::InvalidRequestError
|
||||||
render_json_error I18n.t("discourse_subscriptions.card.invalid")
|
render_json_error I18n.t("discourse_subscriptions.card.invalid")
|
||||||
|
@ -81,12 +80,7 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
def attach_method_to_customer(customer_id, method)
|
def attach_method_to_customer(customer_id, method)
|
||||||
customer = Customer.find(customer_id)
|
customer = Customer.find(customer_id)
|
||||||
::Stripe::PaymentMethod.attach(
|
::Stripe::PaymentMethod.attach(method, { customer: customer.customer_id })
|
||||||
method,
|
|
||||||
{
|
|
||||||
customer: customer.customer_id
|
|
||||||
}
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
module ::Jobs
|
module ::Jobs
|
||||||
class ManuallyUpdateCampaignData < ::Jobs::Base
|
class ManuallyUpdateCampaignData < ::Jobs::Base
|
||||||
|
|
||||||
def execute(args)
|
def execute(args)
|
||||||
return unless SiteSetting.discourse_subscriptions_campaign_enabled
|
return unless SiteSetting.discourse_subscriptions_campaign_enabled
|
||||||
DiscourseSubscriptions::Campaign.new.refresh_data
|
DiscourseSubscriptions::Campaign.new.refresh_data
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
class PaymentSerializer < ApplicationSerializer
|
class PaymentSerializer < ApplicationSerializer
|
||||||
attributes :payment_intent_id,
|
attributes :payment_intent_id,
|
||||||
:receipt_email,
|
:receipt_email,
|
||||||
:url,
|
:url,
|
||||||
:created_at_age,
|
:created_at_age,
|
||||||
:amount,
|
:amount,
|
||||||
:amount_currency,
|
:amount_currency,
|
||||||
:username,
|
:username,
|
||||||
:user_id
|
:user_id
|
||||||
|
|
||||||
def created_at_age
|
def created_at_age
|
||||||
Time.now - object.created_at
|
Time.now - object.created_at
|
||||||
|
@ -19,7 +19,7 @@ module DiscourseSubscriptions
|
||||||
ActiveSupport::NumberHelper.number_to_currency(
|
ActiveSupport::NumberHelper.number_to_currency(
|
||||||
object.amount / 100,
|
object.amount / 100,
|
||||||
precision: 2,
|
precision: 2,
|
||||||
unit: currency_unit
|
unit: currency_unit,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ module DiscourseSubscriptions
|
||||||
def user
|
def user
|
||||||
begin
|
begin
|
||||||
User.find(object.user_id)
|
User.find(object.user_id)
|
||||||
rescue
|
rescue StandardError
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,9 +23,7 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
# Fetch product purchases
|
# Fetch product purchases
|
||||||
one_time_payments = get_one_time_payments(product_ids)
|
one_time_payments = get_one_time_payments(product_ids)
|
||||||
one_time_payments.each do |c|
|
one_time_payments.each { |c| amount += c[:price].to_f / 100.00 }
|
||||||
amount += c[:price].to_f / 100.00
|
|
||||||
end
|
|
||||||
|
|
||||||
# get number of subscribers
|
# get number of subscribers
|
||||||
SiteSetting.discourse_subscriptions_campaign_subscribers = subscriptions&.length.to_i
|
SiteSetting.discourse_subscriptions_campaign_subscribers = subscriptions&.length.to_i
|
||||||
|
@ -57,7 +55,7 @@ module DiscourseSubscriptions
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def goal_met_date_key
|
def goal_met_date_key
|
||||||
'subscriptions_goal_met_date'
|
"subscriptions_goal_met_date"
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_goal_status
|
def check_goal_status
|
||||||
|
@ -91,9 +89,9 @@ module DiscourseSubscriptions
|
||||||
SiteSetting.discourse_subscriptions_campaign_group = group[:id]
|
SiteSetting.discourse_subscriptions_campaign_group = group[:id]
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
full_name: I18n.t('js.discourse_subscriptions.campaign.supporters'),
|
full_name: I18n.t("js.discourse_subscriptions.campaign.supporters"),
|
||||||
title: I18n.t('js.discourse_subscriptions.campaign.supporter'),
|
title: I18n.t("js.discourse_subscriptions.campaign.supporter"),
|
||||||
flair_icon: "donate"
|
flair_icon: "donate",
|
||||||
}
|
}
|
||||||
|
|
||||||
group.update(params)
|
group.update(params)
|
||||||
|
@ -104,11 +102,11 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
def create_campaign_product
|
def create_campaign_product
|
||||||
product_params = {
|
product_params = {
|
||||||
name: I18n.t('js.discourse_subscriptions.campaign.title'),
|
name: I18n.t("js.discourse_subscriptions.campaign.title"),
|
||||||
active: true,
|
active: true,
|
||||||
metadata: {
|
metadata: {
|
||||||
description: I18n.t('js.discourse_subscriptions.campaign.body'),
|
description: I18n.t("js.discourse_subscriptions.campaign.body"),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
product = ::Stripe::Product.create(product_params)
|
product = ::Stripe::Product.create(product_params)
|
||||||
|
@ -123,13 +121,9 @@ module DiscourseSubscriptions
|
||||||
monthly_prices = [3, 5, 10, 25]
|
monthly_prices = [3, 5, 10, 25]
|
||||||
yearly_prices = [50, 100]
|
yearly_prices = [50, 100]
|
||||||
|
|
||||||
monthly_prices.each do |price|
|
monthly_prices.each { |price| create_price(product[:id], group, price, "month") }
|
||||||
create_price(product[:id], group, price, "month")
|
|
||||||
end
|
|
||||||
|
|
||||||
yearly_prices.each do |price|
|
yearly_prices.each { |price| create_price(product[:id], group, price, "year") }
|
||||||
create_price(product[:id], group, price, "year")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_price(product_id, group_name, amount, recurrence)
|
def create_price(product_id, group_name, amount, recurrence)
|
||||||
|
@ -140,11 +134,11 @@ module DiscourseSubscriptions
|
||||||
currency: SiteSetting.discourse_subscriptions_currency,
|
currency: SiteSetting.discourse_subscriptions_currency,
|
||||||
active: true,
|
active: true,
|
||||||
recurring: {
|
recurring: {
|
||||||
interval: recurrence
|
interval: recurrence,
|
||||||
},
|
},
|
||||||
metadata: {
|
metadata: {
|
||||||
group_name: group_name
|
group_name: group_name,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
plan = ::Stripe::Price.create(price_object)
|
plan = ::Stripe::Price.create(price_object)
|
||||||
|
@ -152,18 +146,13 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
def get_one_time_payments(product_ids)
|
def get_one_time_payments(product_ids)
|
||||||
one_time_payments = []
|
one_time_payments = []
|
||||||
current_set = {
|
current_set = { has_more: true, last_record: nil }
|
||||||
has_more: true,
|
|
||||||
last_record: nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if product_ids.present?
|
if product_ids.present?
|
||||||
# lots of matching because the Stripe API doesn't make it easy to match products => payments except from invoices
|
# lots of matching because the Stripe API doesn't make it easy to match products => payments except from invoices
|
||||||
until current_set[:has_more] == false
|
until current_set[:has_more] == false
|
||||||
all_invoices = ::Stripe::Invoice.list(
|
all_invoices =
|
||||||
limit: 100,
|
::Stripe::Invoice.list(limit: 100, starting_after: current_set[:last_record])
|
||||||
starting_after: current_set[:last_record]
|
|
||||||
)
|
|
||||||
|
|
||||||
current_set[:last_record] = all_invoices[:data].last[:id] if all_invoices[:data].present?
|
current_set[:last_record] = all_invoices[:data].last[:id] if all_invoices[:data].present?
|
||||||
current_set[:has_more] = all_invoices[:has_more]
|
current_set[:has_more] = all_invoices[:has_more]
|
||||||
|
@ -173,11 +162,8 @@ module DiscourseSubscriptions
|
||||||
next if invoice[:paid] != true
|
next if invoice[:paid] != true
|
||||||
line_item = invoice[:lines][:data][0] if invoice[:lines] && invoice[:lines][:data] # Discourse only makes single-line item charges
|
line_item = invoice[:lines][:data][0] if invoice[:lines] && invoice[:lines][:data] # Discourse only makes single-line item charges
|
||||||
# check if non-subscription and that the plan is active
|
# check if non-subscription and that the plan is active
|
||||||
if line_item[:plan] == nil &&
|
if line_item[:plan] == nil && line_item[:price] &&
|
||||||
line_item[:price] &&
|
line_item[:price][:recurring] == nil && line_item[:price][:active] == true
|
||||||
line_item[:price][:recurring] == nil &&
|
|
||||||
line_item[:price][:active] == true
|
|
||||||
|
|
||||||
product_id = line_item[:price][:product]
|
product_id = line_item[:price][:product]
|
||||||
if product_ids.include? product_id
|
if product_ids.include? product_id
|
||||||
line_data = {
|
line_data = {
|
||||||
|
@ -197,17 +183,15 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
def get_subscription_data
|
def get_subscription_data
|
||||||
subscriptions = []
|
subscriptions = []
|
||||||
current_set = {
|
current_set = { has_more: true, last_record: nil }
|
||||||
has_more: true,
|
|
||||||
last_record: nil
|
|
||||||
}
|
|
||||||
|
|
||||||
until current_set[:has_more] == false
|
until current_set[:has_more] == false
|
||||||
current_set = ::Stripe::Subscription.list(
|
current_set =
|
||||||
expand: ['data.plan.product'],
|
::Stripe::Subscription.list(
|
||||||
limit: 100,
|
expand: ["data.plan.product"],
|
||||||
starting_after: current_set[:last_record]
|
limit: 100,
|
||||||
)
|
starting_after: current_set[:last_record],
|
||||||
|
)
|
||||||
|
|
||||||
current_set[:last_record] = current_set[:data].last[:id] if current_set[:data].present?
|
current_set[:last_record] = current_set[:data].last[:id] if current_set[:data].present?
|
||||||
subscriptions.concat(current_set[:data].to_a)
|
subscriptions.concat(current_set[:data].to_a)
|
||||||
|
@ -217,13 +201,14 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_to_subscriptions_products(data, ids)
|
def filter_to_subscriptions_products(data, ids)
|
||||||
valid = data.select do |sub|
|
valid =
|
||||||
# cannot .dig stripe objects
|
data.select do |sub|
|
||||||
items = sub[:items][:data][0] if sub[:items] && sub[:items][:data]
|
# cannot .dig stripe objects
|
||||||
product = items[:price][:product] if items[:price] && items[:price][:product]
|
items = sub[:items][:data][0] if sub[:items] && sub[:items][:data]
|
||||||
|
product = items[:price][:product] if items[:price] && items[:price][:product]
|
||||||
|
|
||||||
ids.include?(product)
|
ids.include?(product)
|
||||||
end
|
end
|
||||||
valid.empty? ? nil : valid
|
valid.empty? ? nil : valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,31 +2,31 @@
|
||||||
require_dependency "subscriptions_user_constraint"
|
require_dependency "subscriptions_user_constraint"
|
||||||
|
|
||||||
DiscourseSubscriptions::Engine.routes.draw do
|
DiscourseSubscriptions::Engine.routes.draw do
|
||||||
scope 'admin' do
|
scope "admin" do
|
||||||
get '/' => 'admin#index'
|
get "/" => "admin#index"
|
||||||
post '/refresh' => 'admin#refresh_campaign'
|
post "/refresh" => "admin#refresh_campaign"
|
||||||
post '/create-campaign' => 'admin#create_campaign'
|
post "/create-campaign" => "admin#create_campaign"
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :admin, constraints: AdminConstraint.new do
|
namespace :admin, constraints: AdminConstraint.new do
|
||||||
resources :plans
|
resources :plans
|
||||||
resources :subscriptions, only: [:index, :destroy]
|
resources :subscriptions, only: %i[index destroy]
|
||||||
resources :products
|
resources :products
|
||||||
resources :coupons, only: [:index, :create]
|
resources :coupons, only: %i[index create]
|
||||||
resource :coupons, only: [:destroy, :update]
|
resource :coupons, only: %i[destroy update]
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :user do
|
namespace :user do
|
||||||
resources :payments, only: [:index]
|
resources :payments, only: [:index]
|
||||||
resources :subscriptions, only: [:index, :update, :destroy]
|
resources :subscriptions, only: %i[index update destroy]
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/' => 'subscribe#index'
|
get "/" => "subscribe#index"
|
||||||
get '.json' => 'subscribe#index'
|
get ".json" => "subscribe#index"
|
||||||
get '/contributors' => 'subscribe#contributors'
|
get "/contributors" => "subscribe#contributors"
|
||||||
get '/:id' => 'subscribe#show'
|
get "/:id" => "subscribe#show"
|
||||||
post '/create' => 'subscribe#create'
|
post "/create" => "subscribe#create"
|
||||||
post '/finalize' => 'subscribe#finalize'
|
post "/finalize" => "subscribe#finalize"
|
||||||
|
|
||||||
post '/hooks' => 'hooks#create'
|
post "/hooks" => "hooks#create"
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
module ::DiscourseSubscriptions
|
module ::DiscourseSubscriptions
|
||||||
class Engine < ::Rails::Engine
|
class Engine < ::Rails::Engine
|
||||||
engine_name 'discourse-subscriptions'
|
engine_name "discourse-subscriptions"
|
||||||
isolate_namespace DiscourseSubscriptions
|
isolate_namespace DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'stripe'
|
require "stripe"
|
||||||
require 'highline/import'
|
require "highline/import"
|
||||||
|
|
||||||
desc 'Import subscriptions from Stripe'
|
desc "Import subscriptions from Stripe"
|
||||||
task 'subscriptions:subscriptions_import' => :environment do
|
task "subscriptions:subscriptions_import" => :environment do
|
||||||
setup_api
|
setup_api
|
||||||
products = get_stripe_products
|
products = get_stripe_products
|
||||||
strip_products_to_import = []
|
strip_products_to_import = []
|
||||||
|
|
||||||
procourse_import = false
|
procourse_import = false
|
||||||
procourse_import_response = ask("Were the subscriptions you are importing created in Procourse Memberships?: (y/N)")
|
procourse_import_response =
|
||||||
if procourse_import_response.downcase == 'y'
|
ask("Were the subscriptions you are importing created in Procourse Memberships?: (y/N)")
|
||||||
procourse_import = true
|
procourse_import = true if procourse_import_response.downcase == "y"
|
||||||
end
|
|
||||||
|
|
||||||
products.each do |product|
|
products.each do |product|
|
||||||
confirm_import = ask("Do you wish to import product #{product[:name]} (id: #{product[:id]}): (y/N)")
|
confirm_import =
|
||||||
next if confirm_import.downcase != 'y'
|
ask("Do you wish to import product #{product[:name]} (id: #{product[:id]}): (y/N)")
|
||||||
|
next if confirm_import.downcase != "y"
|
||||||
strip_products_to_import << product
|
strip_products_to_import << product
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -26,28 +26,28 @@ task 'subscriptions:subscriptions_import' => :environment do
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_stripe_products(starting_after: nil)
|
def get_stripe_products(starting_after: nil)
|
||||||
puts 'Getting products from Stripe API'
|
puts "Getting products from Stripe API"
|
||||||
|
|
||||||
all_products = []
|
all_products = []
|
||||||
|
|
||||||
loop do
|
loop do
|
||||||
products = Stripe::Product.list({ type: 'service', starting_after: starting_after, active: true })
|
products =
|
||||||
|
Stripe::Product.list({ type: "service", starting_after: starting_after, active: true })
|
||||||
all_products += products[:data]
|
all_products += products[:data]
|
||||||
break if products[:has_more] == false
|
break if products[:has_more] == false
|
||||||
starting_after = products[:data].last["id"]
|
starting_after = products[:data].last["id"]
|
||||||
end
|
end
|
||||||
|
|
||||||
all_products
|
all_products
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_stripe_subscriptions(starting_after: nil)
|
def get_stripe_subscriptions(starting_after: nil)
|
||||||
puts 'Getting Subscriptions from Stripe API'
|
puts "Getting Subscriptions from Stripe API"
|
||||||
|
|
||||||
all_subscriptions = []
|
all_subscriptions = []
|
||||||
|
|
||||||
loop do
|
loop do
|
||||||
subscriptions = Stripe::Subscription.list({ starting_after: starting_after, status: 'active' })
|
subscriptions = Stripe::Subscription.list({ starting_after: starting_after, status: "active" })
|
||||||
all_subscriptions += subscriptions[:data]
|
all_subscriptions += subscriptions[:data]
|
||||||
break if subscriptions[:has_more] == false
|
break if subscriptions[:has_more] == false
|
||||||
starting_after = subscriptions[:data].last["id"]
|
starting_after = subscriptions[:data].last["id"]
|
||||||
|
@ -57,7 +57,7 @@ def get_stripe_subscriptions(starting_after: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_stripe_customers(starting_after: nil)
|
def get_stripe_customers(starting_after: nil)
|
||||||
puts 'Getting Customers from Stripe API'
|
puts "Getting Customers from Stripe API"
|
||||||
|
|
||||||
all_customers = []
|
all_customers = []
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ def get_stripe_customers(starting_after: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def import_products(products)
|
def import_products(products)
|
||||||
puts 'Importing products:'
|
puts "Importing products:"
|
||||||
|
|
||||||
products.each do |product|
|
products.each do |product|
|
||||||
puts "Looking for external_id #{product[:id]} ..."
|
puts "Looking for external_id #{product[:id]} ..."
|
||||||
|
@ -86,7 +86,7 @@ def import_products(products)
|
||||||
end
|
end
|
||||||
|
|
||||||
def import_subscriptions(procourse_import)
|
def import_subscriptions(procourse_import)
|
||||||
puts 'Importing subscriptions'
|
puts "Importing subscriptions"
|
||||||
product_ids = DiscourseSubscriptions::Product.all.pluck(:external_id)
|
product_ids = DiscourseSubscriptions::Product.all.pluck(:external_id)
|
||||||
|
|
||||||
all_customers = get_stripe_customers
|
all_customers = get_stripe_customers
|
||||||
|
@ -95,7 +95,8 @@ def import_subscriptions(procourse_import)
|
||||||
subscriptions = get_stripe_subscriptions
|
subscriptions = get_stripe_subscriptions
|
||||||
puts "Total Active Subscriptions available: #{subscriptions.length.to_s}"
|
puts "Total Active Subscriptions available: #{subscriptions.length.to_s}"
|
||||||
|
|
||||||
subscriptions_for_products = subscriptions.select { |sub| product_ids.include?(sub[:items][:data][0][:price][:product]) }
|
subscriptions_for_products =
|
||||||
|
subscriptions.select { |sub| product_ids.include?(sub[:items][:data][0][:price][:product]) }
|
||||||
puts "Total Subscriptions matching Products to Import: #{subscriptions_for_products.length.to_s}"
|
puts "Total Subscriptions matching Products to Import: #{subscriptions_for_products.length.to_s}"
|
||||||
|
|
||||||
subscriptions_for_products.each do |subscription|
|
subscriptions_for_products.each do |subscription|
|
||||||
|
@ -113,29 +114,38 @@ def import_subscriptions(procourse_import)
|
||||||
end
|
end
|
||||||
|
|
||||||
if product_id && customer_id && subscription_id
|
if product_id && customer_id && subscription_id
|
||||||
subscriptions_customer = DiscourseSubscriptions::Customer.find_by(user_id: user_id, customer_id: customer_id, product_id: product_id)
|
subscriptions_customer =
|
||||||
|
DiscourseSubscriptions::Customer.find_by(
|
||||||
|
user_id: user_id,
|
||||||
|
customer_id: customer_id,
|
||||||
|
product_id: product_id,
|
||||||
|
)
|
||||||
|
|
||||||
if subscriptions_customer.nil? && user_id && user_id > 0
|
if subscriptions_customer.nil? && user_id && user_id > 0
|
||||||
# create the customer record if doesn't exist only if the user_id and username match, which
|
# create the customer record if doesn't exist only if the user_id and username match, which
|
||||||
# prevents issues if multiple sites use the same Stripe account. Does not apply to a Procourse import.
|
# prevents issues if multiple sites use the same Stripe account. Does not apply to a Procourse import.
|
||||||
user = User.find(user_id)
|
user = User.find(user_id)
|
||||||
if procourse_import || (user && (user.username == username))
|
if procourse_import || (user && (user.username == username))
|
||||||
subscriptions_customer = DiscourseSubscriptions::Customer.create(
|
subscriptions_customer =
|
||||||
user_id: user_id,
|
DiscourseSubscriptions::Customer.create(
|
||||||
customer_id: customer_id,
|
user_id: user_id,
|
||||||
product_id: product_id
|
customer_id: customer_id,
|
||||||
)
|
product_id: product_id,
|
||||||
puts "Subscriptions Customer user_id: #{user_id}, customer_id: #{customer_id}, product_id: #{product_id}) CREATED"
|
)
|
||||||
|
puts "Subscriptions Customer user_id: #{user_id}, customer_id: #{customer_id}, product_id: #{product_id}) CREATED"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
puts "Subscriptions Customer user_id: #{user_id}, customer_id: #{customer_id}, product_id: #{product_id}) already exists"
|
puts "Subscriptions Customer user_id: #{user_id}, customer_id: #{customer_id}, product_id: #{product_id}) already exists"
|
||||||
end
|
end
|
||||||
|
|
||||||
if subscriptions_customer
|
if subscriptions_customer
|
||||||
if DiscourseSubscriptions::Subscription.find_by(customer_id: subscriptions_customer.id, external_id: subscription_id).blank?
|
if DiscourseSubscriptions::Subscription.find_by(
|
||||||
|
customer_id: subscriptions_customer.id,
|
||||||
|
external_id: subscription_id,
|
||||||
|
).blank?
|
||||||
DiscourseSubscriptions::Subscription.create(
|
DiscourseSubscriptions::Subscription.create(
|
||||||
customer_id: subscriptions_customer.id,
|
customer_id: subscriptions_customer.id,
|
||||||
external_id: subscription_id
|
external_id: subscription_id,
|
||||||
)
|
)
|
||||||
puts "Discourse Subscription customer_id: #{subscriptions_customer.id}, external_id: #{subscription_id}) CREATED"
|
puts "Discourse Subscription customer_id: #{subscriptions_customer.id}, external_id: #{subscription_id}) CREATED"
|
||||||
else
|
else
|
||||||
|
@ -147,9 +157,11 @@ def import_subscriptions(procourse_import)
|
||||||
discourse_user = User.find(user_id)
|
discourse_user = User.find(user_id)
|
||||||
puts "Discourse User: #{discourse_user.username_lower} found for Strip metadata update ..."
|
puts "Discourse User: #{discourse_user.username_lower} found for Strip metadata update ..."
|
||||||
|
|
||||||
updated_subscription = Stripe::Subscription.update(subscription_id,
|
updated_subscription =
|
||||||
{ metadata: { user_id: user_id,
|
Stripe::Subscription.update(
|
||||||
username: discourse_user.username_lower } })
|
subscription_id,
|
||||||
|
{ metadata: { user_id: user_id, username: discourse_user.username_lower } },
|
||||||
|
)
|
||||||
puts "Stripe Subscription: #{updated_subscription[:id]}, metadata: #{updated_subscription[:metadata]} UPDATED"
|
puts "Stripe Subscription: #{updated_subscription[:id]}, metadata: #{updated_subscription[:metadata]} UPDATED"
|
||||||
|
|
||||||
updated_customer = Stripe::Customer.update(customer_id, { email: discourse_user.email })
|
updated_customer = Stripe::Customer.update(customer_id, { email: discourse_user.email })
|
||||||
|
@ -163,6 +175,6 @@ end
|
||||||
private
|
private
|
||||||
|
|
||||||
def setup_api
|
def setup_api
|
||||||
api_key = SiteSetting.discourse_subscriptions_secret_key || ask('Input Stripe secret key')
|
api_key = SiteSetting.discourse_subscriptions_secret_key || ask("Input Stripe secret key")
|
||||||
Stripe.api_key = api_key
|
Stripe.api_key = api_key
|
||||||
end
|
end
|
||||||
|
|
65
plugin.rb
65
plugin.rb
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
enabled_site_setting :discourse_subscriptions_enabled
|
enabled_site_setting :discourse_subscriptions_enabled
|
||||||
|
|
||||||
gem 'stripe', '5.29.0'
|
gem "stripe", "5.29.0"
|
||||||
|
|
||||||
register_asset "stylesheets/common/main.scss"
|
register_asset "stylesheets/common/main.scss"
|
||||||
register_asset "stylesheets/common/layout.scss"
|
register_asset "stylesheets/common/layout.scss"
|
||||||
|
@ -18,47 +18,56 @@ register_asset "stylesheets/common/campaign.scss"
|
||||||
register_asset "stylesheets/mobile/main.scss"
|
register_asset "stylesheets/mobile/main.scss"
|
||||||
register_svg_icon "far-credit-card" if respond_to?(:register_svg_icon)
|
register_svg_icon "far-credit-card" if respond_to?(:register_svg_icon)
|
||||||
|
|
||||||
register_html_builder('server:before-head-close') do
|
register_html_builder("server:before-head-close") do
|
||||||
"<script src='https://js.stripe.com/v3/'></script>"
|
"<script src='https://js.stripe.com/v3/'></script>"
|
||||||
end
|
end
|
||||||
|
|
||||||
extend_content_security_policy(
|
extend_content_security_policy(script_src: %w[https://js.stripe.com/v3/ https://hooks.stripe.com])
|
||||||
script_src: ['https://js.stripe.com/v3/', 'https://hooks.stripe.com']
|
|
||||||
)
|
|
||||||
|
|
||||||
add_admin_route 'discourse_subscriptions.admin_navigation', 'discourse-subscriptions.products'
|
add_admin_route "discourse_subscriptions.admin_navigation", "discourse-subscriptions.products"
|
||||||
|
|
||||||
Discourse::Application.routes.append do
|
Discourse::Application.routes.append do
|
||||||
get '/admin/plugins/discourse-subscriptions' => 'admin/plugins#index', constraints: AdminConstraint.new
|
get "/admin/plugins/discourse-subscriptions" => "admin/plugins#index",
|
||||||
get '/admin/plugins/discourse-subscriptions/products' => 'admin/plugins#index', constraints: AdminConstraint.new
|
:constraints => AdminConstraint.new
|
||||||
get '/admin/plugins/discourse-subscriptions/products/:product_id' => 'admin/plugins#index', constraints: AdminConstraint.new
|
get "/admin/plugins/discourse-subscriptions/products" => "admin/plugins#index",
|
||||||
get '/admin/plugins/discourse-subscriptions/products/:product_id/plans' => 'admin/plugins#index', constraints: AdminConstraint.new
|
:constraints => AdminConstraint.new
|
||||||
get '/admin/plugins/discourse-subscriptions/products/:product_id/plans/:plan_id' => 'admin/plugins#index', constraints: AdminConstraint.new
|
get "/admin/plugins/discourse-subscriptions/products/:product_id" => "admin/plugins#index",
|
||||||
get '/admin/plugins/discourse-subscriptions/subscriptions' => 'admin/plugins#index', constraints: AdminConstraint.new
|
:constraints => AdminConstraint.new
|
||||||
get '/admin/plugins/discourse-subscriptions/plans' => 'admin/plugins#index', constraints: AdminConstraint.new
|
get "/admin/plugins/discourse-subscriptions/products/:product_id/plans" => "admin/plugins#index",
|
||||||
get '/admin/plugins/discourse-subscriptions/plans/:plan_id' => 'admin/plugins#index', constraints: AdminConstraint.new
|
:constraints => AdminConstraint.new
|
||||||
get '/admin/plugins/discourse-subscriptions/coupons' => 'admin/plugins#index', constraints: AdminConstraint.new
|
get "/admin/plugins/discourse-subscriptions/products/:product_id/plans/:plan_id" =>
|
||||||
get 'u/:username/billing' => 'users#show', constraints: { username: USERNAME_ROUTE_FORMAT }
|
"admin/plugins#index",
|
||||||
get 'u/:username/billing/:id' => 'users#show', constraints: { username: USERNAME_ROUTE_FORMAT }
|
:constraints => AdminConstraint.new
|
||||||
get 'u/:username/billing/subscriptions/card/:subscription_id' => 'users#show', constraints: { username: USERNAME_ROUTE_FORMAT }
|
get "/admin/plugins/discourse-subscriptions/subscriptions" => "admin/plugins#index",
|
||||||
|
:constraints => AdminConstraint.new
|
||||||
|
get "/admin/plugins/discourse-subscriptions/plans" => "admin/plugins#index",
|
||||||
|
:constraints => AdminConstraint.new
|
||||||
|
get "/admin/plugins/discourse-subscriptions/plans/:plan_id" => "admin/plugins#index",
|
||||||
|
:constraints => AdminConstraint.new
|
||||||
|
get "/admin/plugins/discourse-subscriptions/coupons" => "admin/plugins#index",
|
||||||
|
:constraints => AdminConstraint.new
|
||||||
|
get "u/:username/billing" => "users#show", :constraints => { username: USERNAME_ROUTE_FORMAT }
|
||||||
|
get "u/:username/billing/:id" => "users#show", :constraints => { username: USERNAME_ROUTE_FORMAT }
|
||||||
|
get "u/:username/billing/subscriptions/card/:subscription_id" => "users#show",
|
||||||
|
:constraints => {
|
||||||
|
username: USERNAME_ROUTE_FORMAT,
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
load File.expand_path('lib/discourse_subscriptions/engine.rb', __dir__)
|
load File.expand_path("lib/discourse_subscriptions/engine.rb", __dir__)
|
||||||
load File.expand_path('app/controllers/concerns/stripe.rb', __dir__)
|
load File.expand_path("app/controllers/concerns/stripe.rb", __dir__)
|
||||||
load File.expand_path('app/controllers/concerns/group.rb', __dir__)
|
load File.expand_path("app/controllers/concerns/group.rb", __dir__)
|
||||||
|
|
||||||
after_initialize do
|
after_initialize do
|
||||||
::Stripe.api_version = "2020-08-27"
|
::Stripe.api_version = "2020-08-27"
|
||||||
|
|
||||||
::Stripe.set_app_info(
|
::Stripe.set_app_info(
|
||||||
'Discourse Subscriptions',
|
"Discourse Subscriptions",
|
||||||
version: '2.8.1',
|
version: "2.8.1",
|
||||||
url: 'https://github.com/discourse/discourse-subscriptions'
|
url: "https://github.com/discourse/discourse-subscriptions",
|
||||||
)
|
)
|
||||||
|
|
||||||
Discourse::Application.routes.append do
|
Discourse::Application.routes.append { mount ::DiscourseSubscriptions::Engine, at: "s" }
|
||||||
mount ::DiscourseSubscriptions::Engine, at: 's'
|
|
||||||
end
|
|
||||||
|
|
||||||
add_to_serializer(:site, :show_campaign_banner) do
|
add_to_serializer(:site, :show_campaign_banner) do
|
||||||
begin
|
begin
|
||||||
|
@ -67,7 +76,7 @@ after_initialize do
|
||||||
goal_met = Discourse.redis.get("subscriptions_goal_met_date")
|
goal_met = Discourse.redis.get("subscriptions_goal_met_date")
|
||||||
|
|
||||||
enabled && campaign_enabled && (!goal_met || 7.days.ago <= Date.parse(goal_met))
|
enabled && campaign_enabled && (!goal_met || 7.days.ago <= Date.parse(goal_met))
|
||||||
rescue
|
rescue StandardError
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
RSpec.describe Jobs::RefreshSubscriptionsCampaignData do
|
RSpec.describe Jobs::RefreshSubscriptionsCampaignData do
|
||||||
|
before { SiteSetting.discourse_subscriptions_campaign_enabled = true }
|
||||||
|
|
||||||
before do
|
it "should execute the job only if stripe is configured" do
|
||||||
SiteSetting.discourse_subscriptions_campaign_enabled = true
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should execute the job only if stripe is configured' do
|
|
||||||
DiscourseSubscriptions::Campaign.any_instance.expects(:refresh_data).once
|
DiscourseSubscriptions::Campaign.any_instance.expects(:refresh_data).once
|
||||||
described_class.new.execute({})
|
described_class.new.execute({})
|
||||||
|
|
||||||
|
@ -16,5 +13,4 @@ RSpec.describe Jobs::RefreshSubscriptionsCampaignData do
|
||||||
SiteSetting.discourse_subscriptions_secret_key = "SECRET_KEY"
|
SiteSetting.discourse_subscriptions_secret_key = "SECRET_KEY"
|
||||||
described_class.new.execute({})
|
described_class.new.execute({})
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
RSpec.describe Customer do
|
RSpec.describe Customer do
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
let(:stripe_customer) { { id: 'cus_id4567' } }
|
let(:stripe_customer) { { id: "cus_id4567" } }
|
||||||
|
|
||||||
it "has a table name" do
|
it "has a table name" do
|
||||||
expect(described_class.table_name).to eq "discourse_subscriptions_customers"
|
expect(described_class.table_name).to eq "discourse_subscriptions_customers"
|
||||||
|
@ -13,14 +13,14 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
it "creates" do
|
it "creates" do
|
||||||
customer = described_class.create_customer(user, stripe_customer)
|
customer = described_class.create_customer(user, stripe_customer)
|
||||||
expect(customer.customer_id).to eq 'cus_id4567'
|
expect(customer.customer_id).to eq "cus_id4567"
|
||||||
expect(customer.user_id).to eq user.id
|
expect(customer.user_id).to eq user.id
|
||||||
end
|
end
|
||||||
|
|
||||||
it "has a user scope" do
|
it "has a user scope" do
|
||||||
described_class.create_customer(user, stripe_customer)
|
described_class.create_customer(user, stripe_customer)
|
||||||
customer = described_class.find_user(user)
|
customer = described_class.find_user(user)
|
||||||
expect(customer.customer_id).to eq 'cus_id4567'
|
expect(customer.customer_id).to eq "cus_id4567"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
RSpec.describe Admin::CouponsController do
|
RSpec.describe Admin::CouponsController do
|
||||||
it 'is a subclass of AdminController' do
|
it "is a subclass of AdminController" do
|
||||||
expect(DiscourseSubscriptions::Admin::CouponsController < ::Admin::AdminController).to eq(true)
|
expect(DiscourseSubscriptions::Admin::CouponsController < ::Admin::AdminController).to eq(
|
||||||
|
true,
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when unauthenticated' do
|
context "when unauthenticated" do
|
||||||
it "does nothing" do
|
it "does nothing" do
|
||||||
::Stripe::PromotionCode.expects(:list).never
|
::Stripe::PromotionCode.expects(:list).never
|
||||||
get "/s/admin/coupons.json"
|
get "/s/admin/coupons.json"
|
||||||
|
@ -16,36 +18,28 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when authenticated' do
|
context "when authenticated" do
|
||||||
let(:admin) { Fabricate(:admin) }
|
let(:admin) { Fabricate(:admin) }
|
||||||
|
|
||||||
before { sign_in(admin) }
|
before { sign_in(admin) }
|
||||||
|
|
||||||
describe "#index" do
|
describe "#index" do
|
||||||
it "returns a list of promo codes" do
|
it "returns a list of promo codes" do
|
||||||
::Stripe::PromotionCode.expects(:list).with({ limit: 100 }).returns({
|
::Stripe::PromotionCode
|
||||||
data: [{
|
.expects(:list)
|
||||||
id: 'promo_123',
|
.with({ limit: 100 })
|
||||||
coupon: {
|
.returns({ data: [{ id: "promo_123", coupon: { valid: true } }] })
|
||||||
valid: true
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
|
|
||||||
get "/s/admin/coupons.json"
|
get "/s/admin/coupons.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response.parsed_body[0]['id']).to eq('promo_123')
|
expect(response.parsed_body[0]["id"]).to eq("promo_123")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "only returns valid promo codes" do
|
it "only returns valid promo codes" do
|
||||||
::Stripe::PromotionCode.expects(:list).with({ limit: 100 }).returns({
|
::Stripe::PromotionCode
|
||||||
data: [{
|
.expects(:list)
|
||||||
id: 'promo_123',
|
.with({ limit: 100 })
|
||||||
coupon: {
|
.returns({ data: [{ id: "promo_123", coupon: { valid: false } }] })
|
||||||
valid: false
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
|
|
||||||
get "/s/admin/coupons.json"
|
get "/s/admin/coupons.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
|
@ -55,43 +49,39 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
describe "#create" do
|
describe "#create" do
|
||||||
it "creates a coupon with an amount off" do
|
it "creates a coupon with an amount off" do
|
||||||
::Stripe::Coupon.expects(:create).returns(id: 'coup_123')
|
::Stripe::Coupon.expects(:create).returns(id: "coup_123")
|
||||||
::Stripe::PromotionCode.expects(:create).returns({
|
::Stripe::PromotionCode.expects(:create).returns(
|
||||||
code: 'p123',
|
{ code: "p123", coupon: { amount_off: 2000 } },
|
||||||
coupon: {
|
)
|
||||||
amount_off: 2000
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
post "/s/admin/coupons.json", params: {
|
post "/s/admin/coupons.json",
|
||||||
promo: 'p123',
|
params: {
|
||||||
discount_type: 'amount',
|
promo: "p123",
|
||||||
discount: '2000',
|
discount_type: "amount",
|
||||||
active: true,
|
discount: "2000",
|
||||||
}
|
active: true,
|
||||||
|
}
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response.parsed_body['code']).to eq('p123')
|
expect(response.parsed_body["code"]).to eq("p123")
|
||||||
expect(response.parsed_body['coupon']['amount_off']).to eq(2000)
|
expect(response.parsed_body["coupon"]["amount_off"]).to eq(2000)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a coupon with a percent off" do
|
it "creates a coupon with a percent off" do
|
||||||
::Stripe::Coupon.expects(:create).returns(id: 'coup_123')
|
::Stripe::Coupon.expects(:create).returns(id: "coup_123")
|
||||||
::Stripe::PromotionCode.expects(:create).returns({
|
::Stripe::PromotionCode.expects(:create).returns(
|
||||||
code: 'p123',
|
{ code: "p123", coupon: { percent_off: 20 } },
|
||||||
coupon: {
|
)
|
||||||
percent_off: 20
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
post "/s/admin/coupons.json", params: {
|
post "/s/admin/coupons.json",
|
||||||
promo: 'p123',
|
params: {
|
||||||
discount_type: 'percent',
|
promo: "p123",
|
||||||
discount: '20',
|
discount_type: "percent",
|
||||||
active: true,
|
discount: "20",
|
||||||
}
|
active: true,
|
||||||
|
}
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response.parsed_body['code']).to eq('p123')
|
expect(response.parsed_body["code"]).to eq("p123")
|
||||||
expect(response.parsed_body['coupon']['percent_off']).to eq(20)
|
expect(response.parsed_body["coupon"]["percent_off"]).to eq(20)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
module Admin
|
module Admin
|
||||||
RSpec.describe PlansController do
|
RSpec.describe PlansController do
|
||||||
it 'is a subclass of AdminController' do
|
it "is a subclass of AdminController" do
|
||||||
expect(DiscourseSubscriptions::Admin::PlansController < ::Admin::AdminController).to eq(true)
|
expect(DiscourseSubscriptions::Admin::PlansController < ::Admin::AdminController).to eq(
|
||||||
|
true,
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when not authenticated' do
|
context "when not authenticated" do
|
||||||
describe "index" do
|
describe "index" do
|
||||||
it "does not get the plans" do
|
it "does not get the plans" do
|
||||||
::Stripe::Price.expects(:list).never
|
::Stripe::Price.expects(:list).never
|
||||||
|
@ -25,11 +27,11 @@ module DiscourseSubscriptions
|
||||||
describe "create" do
|
describe "create" do
|
||||||
it "does not create a plan" do
|
it "does not create a plan" do
|
||||||
::Stripe::Price.expects(:create).never
|
::Stripe::Price.expects(:create).never
|
||||||
post "/s/admin/plans.json", params: { name: 'Rick Astley', amount: 1, interval: 'week' }
|
post "/s/admin/plans.json", params: { name: "Rick Astley", amount: 1, interval: "week" }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is not ok" do
|
it "is not ok" do
|
||||||
post "/s/admin/plans.json", params: { name: 'Rick Astley', amount: 1, interval: 'week' }
|
post "/s/admin/plans.json", params: { name: "Rick Astley", amount: 1, interval: "week" }
|
||||||
expect(response.status).to eq 404
|
expect(response.status).to eq 404
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -54,7 +56,7 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when authenticated' do
|
context "when authenticated" do
|
||||||
let(:admin) { Fabricate(:admin) }
|
let(:admin) { Fabricate(:admin) }
|
||||||
|
|
||||||
before { sign_in(admin) }
|
before { sign_in(admin) }
|
||||||
|
@ -66,62 +68,78 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
it "lists the plans for the product" do
|
it "lists the plans for the product" do
|
||||||
::Stripe::Price.expects(:list).with({ product: 'prod_id123' })
|
::Stripe::Price.expects(:list).with({ product: "prod_id123" })
|
||||||
get "/s/admin/plans.json", params: { product_id: 'prod_id123' }
|
get "/s/admin/plans.json", params: { product_id: "prod_id123" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "show" do
|
describe "show" do
|
||||||
it "shows a plan" do
|
it "shows a plan" do
|
||||||
::Stripe::Price.expects(:retrieve).with('plan_12345').returns(currency: 'aud')
|
::Stripe::Price.expects(:retrieve).with("plan_12345").returns(currency: "aud")
|
||||||
get "/s/admin/plans/plan_12345.json"
|
get "/s/admin/plans/plan_12345.json"
|
||||||
expect(response.status).to eq 200
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
|
||||||
it "upcases the currency" do
|
it "upcases the currency" do
|
||||||
::Stripe::Price.expects(:retrieve).with('plan_12345').returns(currency: 'aud', recurring: { interval: 'year' })
|
::Stripe::Price
|
||||||
|
.expects(:retrieve)
|
||||||
|
.with("plan_12345")
|
||||||
|
.returns(currency: "aud", recurring: { interval: "year" })
|
||||||
get "/s/admin/plans/plan_12345.json"
|
get "/s/admin/plans/plan_12345.json"
|
||||||
|
|
||||||
plan = response.parsed_body
|
plan = response.parsed_body
|
||||||
expect(plan["currency"]).to eq 'AUD'
|
expect(plan["currency"]).to eq "AUD"
|
||||||
expect(plan["interval"]).to eq 'year'
|
expect(plan["interval"]).to eq "year"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "create" do
|
describe "create" do
|
||||||
it "creates a plan with a nickname" do
|
it "creates a plan with a nickname" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(:nickname, 'Veg'))
|
::Stripe::Price.expects(:create).with(has_entry(:nickname, "Veg"))
|
||||||
post "/s/admin/plans.json", params: { nickname: 'Veg', metadata: { group_name: '' } }
|
post "/s/admin/plans.json", params: { nickname: "Veg", metadata: { group_name: "" } }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a plan with a currency" do
|
it "creates a plan with a currency" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(:currency, 'AUD'))
|
::Stripe::Price.expects(:create).with(has_entry(:currency, "AUD"))
|
||||||
post "/s/admin/plans.json", params: { currency: 'AUD', metadata: { group_name: '' } }
|
post "/s/admin/plans.json", params: { currency: "AUD", metadata: { group_name: "" } }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a plan with an interval" do
|
it "creates a plan with an interval" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(recurring: { interval: 'week' }))
|
::Stripe::Price.expects(:create).with(has_entry(recurring: { interval: "week" }))
|
||||||
post "/s/admin/plans.json", params: { type: 'recurring', interval: 'week', metadata: { group_name: '' } }
|
post "/s/admin/plans.json",
|
||||||
|
params: {
|
||||||
|
type: "recurring",
|
||||||
|
interval: "week",
|
||||||
|
metadata: {
|
||||||
|
group_name: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a plan as a one-time purchase" do
|
it "creates a plan as a one-time purchase" do
|
||||||
::Stripe::Price.expects(:create).with(Not(has_key(:recurring)))
|
::Stripe::Price.expects(:create).with(Not(has_key(:recurring)))
|
||||||
post "/s/admin/plans.json", params: { metadata: { group_name: '' } }
|
post "/s/admin/plans.json", params: { metadata: { group_name: "" } }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a plan with an amount" do
|
it "creates a plan with an amount" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(:unit_amount, '102'))
|
::Stripe::Price.expects(:create).with(has_entry(:unit_amount, "102"))
|
||||||
post "/s/admin/plans.json", params: { amount: '102', metadata: { group_name: '' } }
|
post "/s/admin/plans.json", params: { amount: "102", metadata: { group_name: "" } }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a plan with a product" do
|
it "creates a plan with a product" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(product: 'prod_walterwhite'))
|
::Stripe::Price.expects(:create).with(has_entry(product: "prod_walterwhite"))
|
||||||
post "/s/admin/plans.json", params: { product: 'prod_walterwhite', metadata: { group_name: '' } }
|
post "/s/admin/plans.json",
|
||||||
|
params: {
|
||||||
|
product: "prod_walterwhite",
|
||||||
|
metadata: {
|
||||||
|
group_name: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a plan with an active status" do
|
it "creates a plan with an active status" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(:active, 'false'))
|
::Stripe::Price.expects(:create).with(has_entry(:active, "false"))
|
||||||
post "/s/admin/plans.json", params: { active: 'false', metadata: { group_name: '' } }
|
post "/s/admin/plans.json", params: { active: "false", metadata: { group_name: "" } }
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: Need to fix the metadata tests
|
# TODO: Need to fix the metadata tests
|
||||||
|
@ -141,7 +159,13 @@ module DiscourseSubscriptions
|
||||||
describe "update" do
|
describe "update" do
|
||||||
it "updates a plan" do
|
it "updates a plan" do
|
||||||
::Stripe::Price.expects(:update)
|
::Stripe::Price.expects(:update)
|
||||||
patch "/s/admin/plans/plan_12345.json", params: { trial_period_days: '14', metadata: { group_name: 'discourse-user-group-name' } }
|
patch "/s/admin/plans/plan_12345.json",
|
||||||
|
params: {
|
||||||
|
trial_period_days: "14",
|
||||||
|
metadata: {
|
||||||
|
group_name: "discourse-user-group-name",
|
||||||
|
},
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
module Admin
|
module Admin
|
||||||
RSpec.describe ProductsController do
|
RSpec.describe ProductsController do
|
||||||
it 'is a subclass of AdminController' do
|
it "is a subclass of AdminController" do
|
||||||
expect(DiscourseSubscriptions::Admin::ProductsController < ::Admin::AdminController).to eq(true)
|
expect(DiscourseSubscriptions::Admin::ProductsController < ::Admin::AdminController).to eq(
|
||||||
|
true,
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when unauthenticated' do
|
context "when unauthenticated" do
|
||||||
it "does not list the products" do
|
it "does not list the products" do
|
||||||
::Stripe::Product.expects(:list).never
|
::Stripe::Product.expects(:list).never
|
||||||
get "/s/admin/products.json"
|
get "/s/admin/products.json"
|
||||||
|
@ -41,12 +43,12 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when authenticated' do
|
context "when authenticated" do
|
||||||
let(:admin) { Fabricate(:admin) }
|
let(:admin) { Fabricate(:admin) }
|
||||||
|
|
||||||
before { sign_in(admin) }
|
before { sign_in(admin) }
|
||||||
|
|
||||||
describe 'index' do
|
describe "index" do
|
||||||
it "gets the empty products" do
|
it "gets the empty products" do
|
||||||
SiteSetting.discourse_subscriptions_public_key = "public-key"
|
SiteSetting.discourse_subscriptions_public_key = "public-key"
|
||||||
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
|
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
|
||||||
|
@ -55,61 +57,74 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'create' do
|
describe "create" do
|
||||||
it 'is of product type service' do
|
it "is of product type service" do
|
||||||
::Stripe::Product.expects(:create).with(has_entry(:type, 'service'))
|
::Stripe::Product.expects(:create).with(has_entry(:type, "service"))
|
||||||
post "/s/admin/products.json", params: {}
|
post "/s/admin/products.json", params: {}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has a name' do
|
it "has a name" do
|
||||||
::Stripe::Product.expects(:create).with(has_entry(:name, 'Jesse Pinkman'))
|
::Stripe::Product.expects(:create).with(has_entry(:name, "Jesse Pinkman"))
|
||||||
post "/s/admin/products.json", params: { name: 'Jesse Pinkman' }
|
post "/s/admin/products.json", params: { name: "Jesse Pinkman" }
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has an active attribute' do
|
it "has an active attribute" do
|
||||||
::Stripe::Product.expects(:create).with(has_entry(active: 'false'))
|
::Stripe::Product.expects(:create).with(has_entry(active: "false"))
|
||||||
post "/s/admin/products.json", params: { active: 'false' }
|
post "/s/admin/products.json", params: { active: "false" }
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has a statement descriptor' do
|
it "has a statement descriptor" do
|
||||||
::Stripe::Product.expects(:create).with(has_entry(statement_descriptor: 'Blessed are the cheesemakers'))
|
::Stripe::Product.expects(:create).with(
|
||||||
post "/s/admin/products.json", params: { statement_descriptor: 'Blessed are the cheesemakers' }
|
has_entry(statement_descriptor: "Blessed are the cheesemakers"),
|
||||||
|
)
|
||||||
|
post "/s/admin/products.json",
|
||||||
|
params: {
|
||||||
|
statement_descriptor: "Blessed are the cheesemakers",
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has no statement descriptor if empty' do
|
it "has no statement descriptor if empty" do
|
||||||
::Stripe::Product.expects(:create).with(has_key(:statement_descriptor)).never
|
::Stripe::Product.expects(:create).with(has_key(:statement_descriptor)).never
|
||||||
post "/s/admin/products.json", params: { statement_descriptor: '' }
|
post "/s/admin/products.json", params: { statement_descriptor: "" }
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has metadata' do
|
it "has metadata" do
|
||||||
::Stripe::Product.expects(:create).with(has_entry(metadata: { description: 'Oi, I think he just said bless be all the bignoses!', repurchaseable: 'false' }))
|
::Stripe::Product.expects(:create).with(
|
||||||
|
has_entry(
|
||||||
|
metadata: {
|
||||||
|
description: "Oi, I think he just said bless be all the bignoses!",
|
||||||
|
repurchaseable: "false",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
post "/s/admin/products.json", params: {
|
post "/s/admin/products.json",
|
||||||
metadata: {
|
params: {
|
||||||
description: 'Oi, I think he just said bless be all the bignoses!',
|
metadata: {
|
||||||
repurchaseable: 'false'
|
description: "Oi, I think he just said bless be all the bignoses!",
|
||||||
}
|
repurchaseable: "false",
|
||||||
}
|
},
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'show' do
|
describe "show" do
|
||||||
it 'retrieves the product' do
|
it "retrieves the product" do
|
||||||
::Stripe::Product.expects(:retrieve).with('prod_walterwhite')
|
::Stripe::Product.expects(:retrieve).with("prod_walterwhite")
|
||||||
get "/s/admin/products/prod_walterwhite.json"
|
get "/s/admin/products/prod_walterwhite.json"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'update' do
|
describe "update" do
|
||||||
it 'updates the product' do
|
it "updates the product" do
|
||||||
::Stripe::Product.expects(:update)
|
::Stripe::Product.expects(:update)
|
||||||
patch "/s/admin/products/prod_walterwhite.json", params: {}
|
patch "/s/admin/products/prod_walterwhite.json", params: {}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'delete' do
|
describe "delete" do
|
||||||
it 'deletes the product' do
|
it "deletes the product" do
|
||||||
::Stripe::Product.expects(:delete).with('prod_walterwhite')
|
::Stripe::Product.expects(:delete).with("prod_walterwhite")
|
||||||
delete "/s/admin/products/prod_walterwhite.json"
|
delete "/s/admin/products/prod_walterwhite.json"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,22 +1,26 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
RSpec.describe Admin::SubscriptionsController do
|
RSpec.describe Admin::SubscriptionsController do
|
||||||
it 'is a subclass of AdminController' do
|
it "is a subclass of AdminController" do
|
||||||
expect(DiscourseSubscriptions::Admin::SubscriptionsController < ::Admin::AdminController).to eq(true)
|
expect(
|
||||||
|
DiscourseSubscriptions::Admin::SubscriptionsController < ::Admin::AdminController,
|
||||||
|
).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
let(:customer) { Fabricate(:customer, user_id: user.id, customer_id: 'c_123', product_id: 'pr_34578') }
|
let(:customer) do
|
||||||
|
Fabricate(:customer, user_id: user.id, customer_id: "c_123", product_id: "pr_34578")
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Fabricate(:subscription, external_id: "sub_12345", customer_id: customer.id)
|
Fabricate(:subscription, external_id: "sub_12345", customer_id: customer.id)
|
||||||
Fabricate(:subscription, external_id: "sub_77777", customer_id: customer.id)
|
Fabricate(:subscription, external_id: "sub_77777", customer_id: customer.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when unauthenticated' do
|
context "when unauthenticated" do
|
||||||
it "does nothing" do
|
it "does nothing" do
|
||||||
::Stripe::Subscription.expects(:list).never
|
::Stripe::Subscription.expects(:list).never
|
||||||
get "/s/admin/subscriptions.json"
|
get "/s/admin/subscriptions.json"
|
||||||
|
@ -29,7 +33,7 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when authenticated' do
|
context "when authenticated" do
|
||||||
let(:admin) { Fabricate(:admin) }
|
let(:admin) { Fabricate(:admin) }
|
||||||
|
|
||||||
before { sign_in(admin) }
|
before { sign_in(admin) }
|
||||||
|
@ -41,15 +45,10 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
it "gets the subscriptions and products" do
|
it "gets the subscriptions and products" do
|
||||||
::Stripe::Subscription.expects(:list)
|
::Stripe::Subscription
|
||||||
.with(expand: ['data.plan.product'], limit: 10, starting_after: nil)
|
.expects(:list)
|
||||||
.returns(
|
.with(expand: ["data.plan.product"], limit: 10, starting_after: nil)
|
||||||
has_more: false,
|
.returns(has_more: false, data: [{ id: "sub_12345" }, { id: "sub_nope" }])
|
||||||
data: [
|
|
||||||
{ id: "sub_12345" },
|
|
||||||
{ id: "sub_nope" }
|
|
||||||
]
|
|
||||||
)
|
|
||||||
get "/s/admin/subscriptions.json"
|
get "/s/admin/subscriptions.json"
|
||||||
subscriptions = response.parsed_body["data"][0]["id"]
|
subscriptions = response.parsed_body["data"][0]["id"]
|
||||||
|
|
||||||
|
@ -58,16 +57,11 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
it "handles starting at a different point in the set" do
|
it "handles starting at a different point in the set" do
|
||||||
::Stripe::Subscription.expects(:list)
|
::Stripe::Subscription
|
||||||
.with(expand: ['data.plan.product'], limit: 10, starting_after: 'sub_nope')
|
.expects(:list)
|
||||||
.returns(
|
.with(expand: ["data.plan.product"], limit: 10, starting_after: "sub_nope")
|
||||||
has_more: false,
|
.returns(has_more: false, data: [{ id: "sub_77777" }, { id: "sub_yepnoep" }])
|
||||||
data: [
|
get "/s/admin/subscriptions.json", params: { last_record: "sub_nope" }
|
||||||
{ id: "sub_77777" },
|
|
||||||
{ id: "sub_yepnoep" }
|
|
||||||
]
|
|
||||||
)
|
|
||||||
get "/s/admin/subscriptions.json", params: { last_record: 'sub_nope' }
|
|
||||||
subscriptions = response.parsed_body["data"][0]["id"]
|
subscriptions = response.parsed_body["data"][0]["id"]
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
|
@ -76,65 +70,70 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "destroy" do
|
describe "destroy" do
|
||||||
let(:group) { Fabricate(:group, name: 'subscribers') }
|
let(:group) { Fabricate(:group, name: "subscribers") }
|
||||||
|
|
||||||
before do
|
before { group.add(user) }
|
||||||
group.add(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "deletes a customer" do
|
it "deletes a customer" do
|
||||||
::Stripe::Subscription
|
::Stripe::Subscription
|
||||||
.expects(:delete)
|
.expects(:delete)
|
||||||
.with('sub_12345')
|
.with("sub_12345")
|
||||||
.returns(
|
.returns(plan: { product: "pr_34578" }, customer: "c_123")
|
||||||
plan: { product: 'pr_34578' },
|
|
||||||
customer: 'c_123'
|
|
||||||
)
|
|
||||||
|
|
||||||
expect {
|
expect { delete "/s/admin/subscriptions/sub_12345.json" }.to change {
|
||||||
delete "/s/admin/subscriptions/sub_12345.json"
|
DiscourseSubscriptions::Customer.count
|
||||||
}.to change { DiscourseSubscriptions::Customer.count }.by(-1)
|
}.by(-1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "removes the user from the group" do
|
it "removes the user from the group" do
|
||||||
::Stripe::Subscription
|
::Stripe::Subscription
|
||||||
.expects(:delete)
|
.expects(:delete)
|
||||||
.with('sub_12345')
|
.with("sub_12345")
|
||||||
.returns(
|
.returns(
|
||||||
plan: { product: 'pr_34578', metadata: { group_name: 'subscribers' } },
|
plan: {
|
||||||
customer: 'c_123'
|
product: "pr_34578",
|
||||||
|
metadata: {
|
||||||
|
group_name: "subscribers",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
customer: "c_123",
|
||||||
)
|
)
|
||||||
|
|
||||||
expect {
|
expect { delete "/s/admin/subscriptions/sub_12345.json" }.to change {
|
||||||
delete "/s/admin/subscriptions/sub_12345.json"
|
user.groups.count
|
||||||
}.to change { user.groups.count }.by(-1)
|
}.by(-1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not remove the user from the group" do
|
it "does not remove the user from the group" do
|
||||||
::Stripe::Subscription
|
::Stripe::Subscription
|
||||||
.expects(:delete)
|
.expects(:delete)
|
||||||
.with('sub_12345')
|
.with("sub_12345")
|
||||||
.returns(
|
.returns(
|
||||||
plan: { product: 'pr_34578', metadata: { group_name: 'group_does_not_exist' } },
|
plan: {
|
||||||
customer: 'c_123'
|
product: "pr_34578",
|
||||||
|
metadata: {
|
||||||
|
group_name: "group_does_not_exist",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
customer: "c_123",
|
||||||
)
|
)
|
||||||
|
|
||||||
expect {
|
expect { delete "/s/admin/subscriptions/sub_12345.json" }.not_to change {
|
||||||
delete "/s/admin/subscriptions/sub_12345.json"
|
user.groups.count
|
||||||
}.not_to change { user.groups.count }
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it "refunds if params[:refund] present" do
|
it "refunds if params[:refund] present" do
|
||||||
::Stripe::Subscription
|
::Stripe::Subscription
|
||||||
.expects(:delete)
|
.expects(:delete)
|
||||||
.with('sub_12345')
|
.with("sub_12345")
|
||||||
.returns(
|
.returns(plan: { product: "pr_34578" }, customer: "c_123")
|
||||||
plan: { product: 'pr_34578' },
|
::Stripe::Subscription
|
||||||
customer: 'c_123'
|
.expects(:retrieve)
|
||||||
)
|
.with("sub_12345")
|
||||||
::Stripe::Subscription.expects(:retrieve).with('sub_12345').returns(latest_invoice: 'in_123')
|
.returns(latest_invoice: "in_123")
|
||||||
::Stripe::Invoice.expects(:retrieve).with('in_123').returns(payment_intent: 'pi_123')
|
::Stripe::Invoice.expects(:retrieve).with("in_123").returns(payment_intent: "pi_123")
|
||||||
::Stripe::Refund.expects(:create).with({ payment_intent: 'pi_123' })
|
::Stripe::Refund.expects(:create).with({ payment_intent: "pi_123" })
|
||||||
|
|
||||||
delete "/s/admin/subscriptions/sub_12345.json", params: { refund: true }
|
delete "/s/admin/subscriptions/sub_12345.json", params: { refund: true }
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
RSpec.describe AdminController do
|
RSpec.describe AdminController do
|
||||||
|
|
||||||
let(:admin) { Fabricate(:admin) }
|
let(:admin) { Fabricate(:admin) }
|
||||||
|
|
||||||
before { sign_in(admin) }
|
before { sign_in(admin) }
|
||||||
|
|
||||||
it 'is a subclass of AdminController' do
|
it "is a subclass of AdminController" do
|
||||||
expect(DiscourseSubscriptions::AdminController < ::Admin::AdminController).to eq(true)
|
expect(DiscourseSubscriptions::AdminController < ::Admin::AdminController).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
RSpec.describe HooksController do
|
RSpec.describe HooksController do
|
||||||
before do
|
before { SiteSetting.discourse_subscriptions_webhook_secret = "zascharoo" }
|
||||||
SiteSetting.discourse_subscriptions_webhook_secret = 'zascharoo'
|
|
||||||
end
|
|
||||||
|
|
||||||
it "contructs a webhook event" do
|
it "contructs a webhook event" do
|
||||||
payload = 'we-want-a-shrubbery'
|
payload = "we-want-a-shrubbery"
|
||||||
headers = { HTTP_STRIPE_SIGNATURE: 'stripe-webhook-signature' }
|
headers = { HTTP_STRIPE_SIGNATURE: "stripe-webhook-signature" }
|
||||||
|
|
||||||
::Stripe::Webhook
|
::Stripe::Webhook
|
||||||
.expects(:construct_event)
|
.expects(:construct_event)
|
||||||
.with('we-want-a-shrubbery', 'stripe-webhook-signature', 'zascharoo')
|
.with("we-want-a-shrubbery", "stripe-webhook-signature", "zascharoo")
|
||||||
.returns(type: 'something')
|
.returns(type: "something")
|
||||||
|
|
||||||
post "/s/hooks.json", params: payload, headers: headers
|
post "/s/hooks.json", params: payload, headers: headers
|
||||||
|
|
||||||
|
@ -24,65 +22,61 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
describe "event types" do
|
describe "event types" do
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
let(:customer) { Fabricate(:customer, customer_id: 'c_575768', product_id: 'p_8654', user_id: user.id) }
|
let(:customer) do
|
||||||
let(:group) { Fabricate(:group, name: 'subscribers-group') }
|
Fabricate(:customer, customer_id: "c_575768", product_id: "p_8654", user_id: user.id)
|
||||||
|
end
|
||||||
|
let(:group) { Fabricate(:group, name: "subscribers-group") }
|
||||||
|
|
||||||
let(:event_data) do
|
let(:event_data) do
|
||||||
{
|
{
|
||||||
object: {
|
object: {
|
||||||
customer: customer.customer_id,
|
customer: customer.customer_id,
|
||||||
plan: { product: customer.product_id, metadata: { group_name: group.name } }
|
plan: {
|
||||||
}
|
product: customer.product_id,
|
||||||
|
metadata: {
|
||||||
|
group_name: group.name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "customer.subscription.updated" do
|
describe "customer.subscription.updated" do
|
||||||
before do
|
before do
|
||||||
event = {
|
event = { type: "customer.subscription.updated", data: event_data }
|
||||||
type: 'customer.subscription.updated',
|
|
||||||
data: event_data
|
|
||||||
}
|
|
||||||
|
|
||||||
::Stripe::Webhook
|
::Stripe::Webhook.stubs(:construct_event).returns(event)
|
||||||
.stubs(:construct_event)
|
|
||||||
.returns(event)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is successfull' do
|
it "is successfull" do
|
||||||
post "/s/hooks.json"
|
post "/s/hooks.json"
|
||||||
expect(response.status).to eq 200
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'completing the subscription' do
|
describe "completing the subscription" do
|
||||||
it 'does not add the user to the group' do
|
it "does not add the user to the group" do
|
||||||
event_data[:object][:status] = 'incomplete'
|
event_data[:object][:status] = "incomplete"
|
||||||
event_data[:previous_attributes] = { status: 'incomplete' }
|
event_data[:previous_attributes] = { status: "incomplete" }
|
||||||
|
|
||||||
expect {
|
expect { post "/s/hooks.json" }.not_to change { user.groups.count }
|
||||||
post "/s/hooks.json"
|
|
||||||
}.not_to change { user.groups.count }
|
|
||||||
|
|
||||||
expect(response.status).to eq 200
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not add the user to the group' do
|
it "does not add the user to the group" do
|
||||||
event_data[:object][:status] = 'incomplete'
|
event_data[:object][:status] = "incomplete"
|
||||||
event_data[:previous_attributes] = { status: 'something-else' }
|
event_data[:previous_attributes] = { status: "something-else" }
|
||||||
|
|
||||||
expect {
|
expect { post "/s/hooks.json" }.not_to change { user.groups.count }
|
||||||
post "/s/hooks.json"
|
|
||||||
}.not_to change { user.groups.count }
|
|
||||||
|
|
||||||
expect(response.status).to eq 200
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'adds the user to the group when completing the transaction' do
|
it "adds the user to the group when completing the transaction" do
|
||||||
event_data[:object][:status] = 'complete'
|
event_data[:object][:status] = "complete"
|
||||||
event_data[:previous_attributes] = { status: 'incomplete' }
|
event_data[:previous_attributes] = { status: "incomplete" }
|
||||||
|
|
||||||
expect {
|
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(1)
|
||||||
post "/s/hooks.json"
|
|
||||||
}.to change { user.groups.count }.by(1)
|
|
||||||
|
|
||||||
expect(response.status).to eq 200
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
@ -91,30 +85,23 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
describe "customer.subscription.deleted" do
|
describe "customer.subscription.deleted" do
|
||||||
before do
|
before do
|
||||||
event = {
|
event = { type: "customer.subscription.deleted", data: event_data }
|
||||||
type: 'customer.subscription.deleted',
|
|
||||||
data: event_data
|
|
||||||
}
|
|
||||||
|
|
||||||
::Stripe::Webhook
|
::Stripe::Webhook.stubs(:construct_event).returns(event)
|
||||||
.stubs(:construct_event)
|
|
||||||
.returns(event)
|
|
||||||
|
|
||||||
group.add(user)
|
group.add(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "deletes the customer" do
|
it "deletes the customer" do
|
||||||
expect {
|
expect { post "/s/hooks.json" }.to change { DiscourseSubscriptions::Customer.count }.by(
|
||||||
post "/s/hooks.json"
|
-1,
|
||||||
}.to change { DiscourseSubscriptions::Customer.count }.by(-1)
|
)
|
||||||
|
|
||||||
expect(response.status).to eq 200
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
|
||||||
it "removes the user from the group" do
|
it "removes the user from the group" do
|
||||||
expect {
|
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(-1)
|
||||||
post "/s/hooks.json"
|
|
||||||
}.to change { user.groups.count }.by(-1)
|
|
||||||
|
|
||||||
expect(response.status).to eq 200
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
RSpec.describe SubscribeController do
|
RSpec.describe SubscribeController do
|
||||||
let (:user) { Fabricate(:user) }
|
let (:user) {
|
||||||
let (:campaign_user) { Fabricate(:user) }
|
Fabricate(:user)
|
||||||
|
}
|
||||||
|
let (:campaign_user) {
|
||||||
|
Fabricate(:user)
|
||||||
|
}
|
||||||
|
|
||||||
context "when showing products" do
|
context "when showing products" do
|
||||||
let(:product) do
|
let(:product) do
|
||||||
|
@ -13,8 +17,9 @@ module DiscourseSubscriptions
|
||||||
id: "prodct_23456",
|
id: "prodct_23456",
|
||||||
name: "Very Special Product",
|
name: "Very Special Product",
|
||||||
metadata: {
|
metadata: {
|
||||||
description: "Many people listened to my phone call with the Ukrainian President while it was being made",
|
description:
|
||||||
repurchaseable: false
|
"Many people listened to my phone call with the Ukrainian President while it was being made",
|
||||||
|
repurchaseable: false,
|
||||||
},
|
},
|
||||||
otherstuff: true,
|
otherstuff: true,
|
||||||
}
|
}
|
||||||
|
@ -23,10 +28,37 @@ module DiscourseSubscriptions
|
||||||
let(:prices) do
|
let(:prices) do
|
||||||
{
|
{
|
||||||
data: [
|
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_id123",
|
||||||
{ id: 'plan_id678', unit_amount: 1000, currency: 'aud', recurring: { interval: 'week' }, metadata: {} }
|
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
|
end
|
||||||
|
|
||||||
|
@ -40,24 +72,36 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#index" do
|
describe "#index" do
|
||||||
|
|
||||||
it "gets products" do
|
it "gets products" do
|
||||||
::Stripe::Product.expects(:list).with({ ids: product_ids, active: true }).returns(data: [product])
|
::Stripe::Product
|
||||||
|
.expects(:list)
|
||||||
|
.with({ ids: product_ids, active: true })
|
||||||
|
.returns(data: [product])
|
||||||
|
|
||||||
get "/s.json"
|
get "/s.json"
|
||||||
|
|
||||||
expect(response.parsed_body).to eq([{
|
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"),
|
"id" => "prodct_23456",
|
||||||
"subscribed" => false,
|
"name" => "Very Special Product",
|
||||||
"repurchaseable" => false,
|
"description" =>
|
||||||
}])
|
PrettyText.cook(
|
||||||
|
"Many people listened to my phone call with the Ukrainian President while it was being made",
|
||||||
|
),
|
||||||
|
"subscribed" => false,
|
||||||
|
"repurchaseable" => false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is subscribed" do
|
it "is subscribed" do
|
||||||
Fabricate(:customer, product_id: product[:id], user_id: user.id, customer_id: 'x')
|
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])
|
::Stripe::Product
|
||||||
|
.expects(:list)
|
||||||
|
.with({ ids: product_ids, active: true })
|
||||||
|
.returns(data: [product])
|
||||||
|
|
||||||
get "/s.json"
|
get "/s.json"
|
||||||
data = response.parsed_body
|
data = response.parsed_body
|
||||||
|
@ -66,7 +110,10 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
it "is not subscribed" do
|
it "is not subscribed" do
|
||||||
::DiscourseSubscriptions::Customer.delete_all
|
::DiscourseSubscriptions::Customer.delete_all
|
||||||
::Stripe::Product.expects(:list).with({ ids: product_ids, active: true }).returns(data: [product])
|
::Stripe::Product
|
||||||
|
.expects(:list)
|
||||||
|
.with({ ids: product_ids, active: true })
|
||||||
|
.returns(data: [product])
|
||||||
|
|
||||||
get "/s.json"
|
get "/s.json"
|
||||||
data = response.parsed_body
|
data = response.parsed_body
|
||||||
|
@ -77,11 +124,16 @@ module DiscourseSubscriptions
|
||||||
describe "#get_contributors" do
|
describe "#get_contributors" do
|
||||||
before do
|
before do
|
||||||
Fabricate(:product, external_id: "prod_campaign")
|
Fabricate(:product, external_id: "prod_campaign")
|
||||||
Fabricate(:customer, product_id: "prodct_23456", user_id: user.id, customer_id: 'x')
|
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')
|
Fabricate(
|
||||||
|
:customer,
|
||||||
|
product_id: "prod_campaign",
|
||||||
|
user_id: campaign_user.id,
|
||||||
|
customer_id: "y",
|
||||||
|
)
|
||||||
end
|
end
|
||||||
context 'when not showing contributors' do
|
context "when not showing contributors" do
|
||||||
it 'returns nothing if not set to show contributors' do
|
it "returns nothing if not set to show contributors" do
|
||||||
SiteSetting.discourse_subscriptions_campaign_show_contributors = false
|
SiteSetting.discourse_subscriptions_campaign_show_contributors = false
|
||||||
get "/s/contributors.json"
|
get "/s/contributors.json"
|
||||||
|
|
||||||
|
@ -90,12 +142,10 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when showing contributors' do
|
context "when showing contributors" do
|
||||||
before do
|
before { SiteSetting.discourse_subscriptions_campaign_show_contributors = true }
|
||||||
SiteSetting.discourse_subscriptions_campaign_show_contributors = true
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'filters users by campaign product if set' do
|
it "filters users by campaign product if set" do
|
||||||
SiteSetting.discourse_subscriptions_campaign_product = "prod_campaign"
|
SiteSetting.discourse_subscriptions_campaign_product = "prod_campaign"
|
||||||
|
|
||||||
get "/s/contributors.json"
|
get "/s/contributors.json"
|
||||||
|
@ -105,7 +155,7 @@ module DiscourseSubscriptions
|
||||||
expect(data.length).to eq 1
|
expect(data.length).to eq 1
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows all purchases if campaign product not set' do
|
it "shows all purchases if campaign product not set" do
|
||||||
SiteSetting.discourse_subscriptions_campaign_product = nil
|
SiteSetting.discourse_subscriptions_campaign_product = nil
|
||||||
|
|
||||||
get "/s/contributors.json"
|
get "/s/contributors.json"
|
||||||
|
@ -117,25 +167,54 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#show" do
|
describe "#show" do
|
||||||
it 'retrieves the product' do
|
it "retrieves the product" do
|
||||||
::Stripe::Product.expects(:retrieve).with('prod_walterwhite').returns(product)
|
::Stripe::Product.expects(:retrieve).with("prod_walterwhite").returns(product)
|
||||||
::Stripe::Price.expects(:list).with(active: true, product: 'prod_walterwhite').returns(prices)
|
::Stripe::Price
|
||||||
|
.expects(:list)
|
||||||
|
.with(active: true, product: "prod_walterwhite")
|
||||||
|
.returns(prices)
|
||||||
get "/s/prod_walterwhite.json"
|
get "/s/prod_walterwhite.json"
|
||||||
|
|
||||||
expect(response.parsed_body).to eq({
|
expect(response.parsed_body).to eq(
|
||||||
"product" => {
|
{
|
||||||
"id" => "prodct_23456",
|
"product" => {
|
||||||
"name" => "Very Special Product",
|
"id" => "prodct_23456",
|
||||||
"description" => PrettyText.cook("Many people listened to my phone call with the Ukrainian President while it was being made"),
|
"name" => "Very Special Product",
|
||||||
"subscribed" => false,
|
"description" =>
|
||||||
"repurchaseable" => false
|
PrettyText.cook(
|
||||||
},
|
"Many people listened to my phone call with the Ukrainian President while it was being made",
|
||||||
"plans" => [
|
),
|
||||||
{ "currency" => "aud", "id" => "plan_id123", "recurring" => { "interval" => "year" }, "unit_amount" => 1220 },
|
"subscribed" => false,
|
||||||
{ "currency" => "usd", "id" => "plan_id234", "recurring" => { "interval" => "year" }, "unit_amount" => 1399 },
|
"repurchaseable" => false,
|
||||||
{ "currency" => "aud", "id" => "plan_id678", "recurring" => { "interval" => "week" }, "unit_amount" => 1000 }
|
},
|
||||||
]
|
"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
|
end
|
||||||
end
|
end
|
||||||
|
@ -146,81 +225,91 @@ module DiscourseSubscriptions
|
||||||
::Stripe::Customer.expects(:create).never
|
::Stripe::Customer.expects(:create).never
|
||||||
::Stripe::Price.expects(:retrieve).never
|
::Stripe::Price.expects(:retrieve).never
|
||||||
::Stripe::Subscription.expects(:create).never
|
::Stripe::Subscription.expects(:create).never
|
||||||
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when authenticated" do
|
context "when authenticated" do
|
||||||
before do
|
before { sign_in(user) }
|
||||||
sign_in(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#create" do
|
describe "#create" do
|
||||||
before do
|
before { ::Stripe::Customer.expects(:create).returns(id: "cus_1234") }
|
||||||
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
|
|
||||||
end
|
|
||||||
|
|
||||||
it "creates a subscription" do
|
it "creates a subscription" do
|
||||||
::Stripe::Price.expects(:retrieve).returns(
|
::Stripe::Price.expects(:retrieve).returns(
|
||||||
type: 'recurring',
|
type: "recurring",
|
||||||
product: 'product_12345',
|
product: "product_12345",
|
||||||
metadata: {
|
metadata: {
|
||||||
group_name: 'awesome',
|
group_name: "awesome",
|
||||||
trial_period_days: 0
|
trial_period_days: 0,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
::Stripe::Subscription.expects(:create).with(
|
::Stripe::Subscription
|
||||||
customer: 'cus_1234',
|
.expects(:create)
|
||||||
items: [ price: 'plan_1234' ],
|
.with(
|
||||||
metadata: { user_id: user.id, username: user.username_lower },
|
customer: "cus_1234",
|
||||||
trial_period_days: 0,
|
items: [price: "plan_1234"],
|
||||||
promotion_code: nil
|
metadata: {
|
||||||
).returns(status: 'active', customer: 'cus_1234')
|
user_id: user.id,
|
||||||
|
username: user.username_lower,
|
||||||
|
},
|
||||||
|
trial_period_days: 0,
|
||||||
|
promotion_code: nil,
|
||||||
|
)
|
||||||
|
.returns(status: "active", customer: "cus_1234")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||||
}.to change { DiscourseSubscriptions::Customer.count }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a one time payment subscription" do
|
it "creates a one time payment subscription" do
|
||||||
::Stripe::Price.expects(:retrieve).returns(
|
::Stripe::Price.expects(:retrieve).returns(
|
||||||
type: 'one_time',
|
type: "one_time",
|
||||||
product: 'product_12345',
|
product: "product_12345",
|
||||||
metadata: {
|
metadata: {
|
||||||
group_name: 'awesome'
|
group_name: "awesome",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
::Stripe::InvoiceItem.expects(:create)
|
::Stripe::InvoiceItem.expects(:create)
|
||||||
|
|
||||||
::Stripe::Invoice.expects(:create).returns(status: 'open', id: 'in_123')
|
::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(: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::Invoice.expects(:retrieve).returns(
|
||||||
|
id: "in_123",
|
||||||
|
status: "open",
|
||||||
|
payment_intent: "pi_123",
|
||||||
|
)
|
||||||
|
|
||||||
::Stripe::PaymentIntent.expects(:retrieve).returns(status: 'successful')
|
::Stripe::PaymentIntent.expects(:retrieve).returns(status: "successful")
|
||||||
|
|
||||||
::Stripe::Invoice.expects(:pay).returns(status: 'paid', customer: 'cus_1234')
|
::Stripe::Invoice.expects(:pay).returns(status: "paid", customer: "cus_1234")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post '/s/create.json', params: { plan: 'plan_1234', source: 'tok_1234' }
|
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||||
}.to change { DiscourseSubscriptions::Customer.count }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a customer model" do
|
it "creates a customer model" do
|
||||||
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: {}).twice
|
::Stripe::Price.expects(:retrieve).returns(type: "recurring", metadata: {}).twice
|
||||||
::Stripe::Subscription.expects(:create).returns(status: 'active', customer: 'cus_1234')
|
::Stripe::Subscription.expects(:create).returns(status: "active", customer: "cus_1234")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||||
}.to change { DiscourseSubscriptions::Customer.count }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
|
|
||||||
::Stripe::Customer.expects(:retrieve).with('cus_1234')
|
::Stripe::Customer.expects(:retrieve).with("cus_1234")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/create.json", params: { plan: 'plan_5678', source: 'tok_5678' }
|
post "/s/create.json", params: { plan: "plan_5678", source: "tok_5678" }
|
||||||
}.not_to change { DiscourseSubscriptions::Customer.count }
|
}.not_to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -228,19 +317,22 @@ module DiscourseSubscriptions
|
||||||
context "with invalid code" do
|
context "with invalid code" do
|
||||||
it "prevents use of invalid coupon codes" do
|
it "prevents use of invalid coupon codes" do
|
||||||
::Stripe::Price.expects(:retrieve).returns(
|
::Stripe::Price.expects(:retrieve).returns(
|
||||||
type: 'recurring',
|
type: "recurring",
|
||||||
product: 'product_12345',
|
product: "product_12345",
|
||||||
metadata: {
|
metadata: {
|
||||||
group_name: 'awesome',
|
group_name: "awesome",
|
||||||
trial_period_days: 0
|
trial_period_days: 0,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
::Stripe::PromotionCode.expects(:list).with({ code: 'invalid' }).returns(
|
::Stripe::PromotionCode.expects(:list).with({ code: "invalid" }).returns(data: [])
|
||||||
data: []
|
|
||||||
)
|
|
||||||
|
|
||||||
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: 'invalid' }
|
post "/s/create.json",
|
||||||
|
params: {
|
||||||
|
plan: "plan_1234",
|
||||||
|
source: "tok_1234",
|
||||||
|
promo: "invalid",
|
||||||
|
}
|
||||||
|
|
||||||
data = response.parsed_body
|
data = response.parsed_body
|
||||||
expect(data["errors"]).not_to be_blank
|
expect(data["errors"]).not_to be_blank
|
||||||
|
@ -249,61 +341,86 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
context "with valid code" do
|
context "with valid code" do
|
||||||
before do
|
before do
|
||||||
::Stripe::PromotionCode.expects(:list).with({ code: '123' }).returns(
|
::Stripe::PromotionCode
|
||||||
data: [{
|
.expects(:list)
|
||||||
id: 'promo123',
|
.with({ code: "123" })
|
||||||
coupon: { id: 'c123' }
|
.returns(data: [{ id: "promo123", coupon: { id: "c123" } }])
|
||||||
}]
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "applies promo code to recurring subscription" do
|
it "applies promo code to recurring subscription" do
|
||||||
::Stripe::Price.expects(:retrieve).returns(
|
::Stripe::Price.expects(:retrieve).returns(
|
||||||
type: 'recurring',
|
type: "recurring",
|
||||||
product: 'product_12345',
|
product: "product_12345",
|
||||||
metadata: {
|
metadata: {
|
||||||
group_name: 'awesome',
|
group_name: "awesome",
|
||||||
trial_period_days: 0
|
trial_period_days: 0,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
::Stripe::Subscription.expects(:create).with(
|
::Stripe::Subscription
|
||||||
customer: 'cus_1234',
|
.expects(:create)
|
||||||
items: [ price: 'plan_1234' ],
|
.with(
|
||||||
metadata: { user_id: user.id, username: user.username_lower },
|
customer: "cus_1234",
|
||||||
trial_period_days: 0,
|
items: [price: "plan_1234"],
|
||||||
promotion_code: 'promo123'
|
metadata: {
|
||||||
).returns(status: 'active', customer: 'cus_1234')
|
user_id: user.id,
|
||||||
|
username: user.username_lower,
|
||||||
|
},
|
||||||
|
trial_period_days: 0,
|
||||||
|
promotion_code: "promo123",
|
||||||
|
)
|
||||||
|
.returns(status: "active", customer: "cus_1234")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' }
|
post "/s/create.json",
|
||||||
|
params: {
|
||||||
|
plan: "plan_1234",
|
||||||
|
source: "tok_1234",
|
||||||
|
promo: "123",
|
||||||
|
}
|
||||||
}.to change { DiscourseSubscriptions::Customer.count }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "applies promo code to one time purchase" do
|
it "applies promo code to one time purchase" do
|
||||||
::Stripe::Price.expects(:retrieve).returns(
|
::Stripe::Price.expects(:retrieve).returns(
|
||||||
type: 'one_time',
|
type: "one_time",
|
||||||
product: 'product_12345',
|
product: "product_12345",
|
||||||
metadata: {
|
metadata: {
|
||||||
group_name: 'awesome'
|
group_name: "awesome",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
::Stripe::InvoiceItem.expects(:create).with(customer: 'cus_1234', price: 'plan_1234', discounts: [{ coupon: 'c123' }])
|
::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(: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(: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::Invoice.expects(:retrieve).returns(
|
||||||
|
id: "in_123",
|
||||||
|
status: "open",
|
||||||
|
payment_intent: "pi_123",
|
||||||
|
)
|
||||||
|
|
||||||
::Stripe::PaymentIntent.expects(:retrieve).returns(status: 'successful')
|
::Stripe::PaymentIntent.expects(:retrieve).returns(status: "successful")
|
||||||
|
|
||||||
::Stripe::Invoice.expects(:pay).returns(status: 'paid', customer: 'cus_1234')
|
::Stripe::Invoice.expects(:pay).returns(status: "paid", customer: "cus_1234")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post '/s/create.json', params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' }
|
post "/s/create.json",
|
||||||
|
params: {
|
||||||
|
plan: "plan_1234",
|
||||||
|
source: "tok_1234",
|
||||||
|
promo: "123",
|
||||||
|
}
|
||||||
}.to change { DiscourseSubscriptions::Customer.count }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -313,81 +430,114 @@ module DiscourseSubscriptions
|
||||||
describe "#finalize strong customer authenticated transaction" do
|
describe "#finalize strong customer authenticated transaction" do
|
||||||
context "with subscription" do
|
context "with subscription" do
|
||||||
it "finalizes the subscription" do
|
it "finalizes the subscription" do
|
||||||
::Stripe::Price.expects(:retrieve).returns(id: "plan_1234", product: "prod_1234", metadata: {})
|
::Stripe::Price.expects(:retrieve).returns(
|
||||||
::Stripe::Subscription.expects(:retrieve).returns(id: "sub_123", customer: 'cus_1234', status: "active")
|
id: "plan_1234",
|
||||||
|
product: "prod_1234",
|
||||||
|
metadata: {
|
||||||
|
},
|
||||||
|
)
|
||||||
|
::Stripe::Subscription.expects(:retrieve).returns(
|
||||||
|
id: "sub_123",
|
||||||
|
customer: "cus_1234",
|
||||||
|
status: "active",
|
||||||
|
)
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/finalize.json", params: { plan: 'plan_1234', transaction: 'sub_1234' }
|
post "/s/finalize.json", params: { plan: "plan_1234", transaction: "sub_1234" }
|
||||||
}.to change { DiscourseSubscriptions::Customer.count }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with one-time payment" do
|
context "with one-time payment" do
|
||||||
it "finalizes the one-time payment" do
|
it "finalizes the one-time payment" do
|
||||||
::Stripe::Price.expects(:retrieve).returns(id: "plan_1234", product: "prod_1234", metadata: {})
|
::Stripe::Price.expects(:retrieve).returns(
|
||||||
::Stripe::Invoice.expects(:retrieve).returns(id: "in_123", customer: 'cus_1234', status: "paid")
|
id: "plan_1234",
|
||||||
|
product: "prod_1234",
|
||||||
|
metadata: {
|
||||||
|
},
|
||||||
|
)
|
||||||
|
::Stripe::Invoice.expects(:retrieve).returns(
|
||||||
|
id: "in_123",
|
||||||
|
customer: "cus_1234",
|
||||||
|
status: "paid",
|
||||||
|
)
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/finalize.json", params: { plan: 'plan_1234', transaction: 'in_1234' }
|
post "/s/finalize.json", params: { plan: "plan_1234", transaction: "in_1234" }
|
||||||
}.to change { DiscourseSubscriptions::Customer.count }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "user groups" do
|
describe "user groups" do
|
||||||
let(:group_name) { 'group-123' }
|
let(:group_name) { "group-123" }
|
||||||
let(:group) { Fabricate(:group, name: group_name) }
|
let(:group) { Fabricate(:group, name: group_name) }
|
||||||
|
|
||||||
context "with unauthorized group" do
|
context "with unauthorized group" do
|
||||||
before do
|
before do
|
||||||
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
|
::Stripe::Customer.expects(:create).returns(id: "cus_1234")
|
||||||
::Stripe::Subscription.expects(:create).returns(status: 'active')
|
::Stripe::Subscription.expects(:create).returns(status: "active")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not add the user to the admins group" do
|
it "does not add the user to the admins group" do
|
||||||
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: 'admins' })
|
::Stripe::Price.expects(:retrieve).returns(
|
||||||
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
type: "recurring",
|
||||||
|
metadata: {
|
||||||
|
group_name: "admins",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||||
expect(user.admin).to eq false
|
expect(user.admin).to eq false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not add the user to other group" do
|
it "does not add the user to other group" do
|
||||||
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: 'other' })
|
::Stripe::Price.expects(:retrieve).returns(
|
||||||
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
type: "recurring",
|
||||||
|
metadata: {
|
||||||
|
group_name: "other",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||||
expect(user.groups).to be_empty
|
expect(user.groups).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when plan has group in metadata" do
|
context "when plan has group in metadata" do
|
||||||
before do
|
before do
|
||||||
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
|
::Stripe::Customer.expects(:create).returns(id: "cus_1234")
|
||||||
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: group_name })
|
::Stripe::Price.expects(:retrieve).returns(
|
||||||
|
type: "recurring",
|
||||||
|
metadata: {
|
||||||
|
group_name: group_name,
|
||||||
|
},
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not add the user to the group when subscription fails" do
|
it "does not add the user to the group when subscription fails" do
|
||||||
::Stripe::Subscription.expects(:create).returns(status: 'failed')
|
::Stripe::Subscription.expects(:create).returns(status: "failed")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||||
}.not_to change { group.users.count }
|
}.not_to change { group.users.count }
|
||||||
|
|
||||||
expect(user.groups).to be_empty
|
expect(user.groups).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adds the user to the group when the subscription is active" do
|
it "adds the user to the group when the subscription is active" do
|
||||||
::Stripe::Subscription.expects(:create).returns(status: 'active')
|
::Stripe::Subscription.expects(:create).returns(status: "active")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||||
}.to change { group.users.count }
|
}.to change { group.users.count }
|
||||||
|
|
||||||
expect(user.groups).not_to be_empty
|
expect(user.groups).not_to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adds the user to the group when the subscription is trialing" do
|
it "adds the user to the group when the subscription is trialing" do
|
||||||
::Stripe::Subscription.expects(:create).returns(status: 'trialing')
|
::Stripe::Subscription.expects(:create).returns(status: "trialing")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
|
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||||
}.to change { group.users.count }
|
}.to change { group.users.count }
|
||||||
|
|
||||||
expect(user.groups).not_to be_empty
|
expect(user.groups).not_to be_empty
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
RSpec.describe User::PaymentsController do
|
RSpec.describe User::PaymentsController do
|
||||||
it 'is a subclass of ApplicationController' do
|
it "is a subclass of ApplicationController" do
|
||||||
expect(DiscourseSubscriptions::User::PaymentsController < ::ApplicationController).to eq(true)
|
expect(DiscourseSubscriptions::User::PaymentsController < ::ApplicationController).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -17,80 +17,39 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when authenticated" do
|
context "when authenticated" do
|
||||||
let(:user) { Fabricate(:user, email: 'zasch@example.com') }
|
let(:user) { Fabricate(:user, email: "zasch@example.com") }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
Fabricate(:customer, customer_id: 'c_345678', user_id: user.id)
|
Fabricate(:customer, customer_id: "c_345678", user_id: user.id)
|
||||||
Fabricate(:product, external_id: 'prod_8675309')
|
Fabricate(:product, external_id: "prod_8675309")
|
||||||
Fabricate(:product, external_id: 'prod_8675310')
|
Fabricate(:product, external_id: "prod_8675310")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "gets payment intents" do
|
it "gets payment intents" do
|
||||||
created_time = Time.now
|
created_time = Time.now
|
||||||
::Stripe::Invoice.expects(:list).with(
|
::Stripe::Invoice
|
||||||
customer: 'c_345678'
|
.expects(:list)
|
||||||
).returns(
|
.with(customer: "c_345678")
|
||||||
data: [
|
.returns(
|
||||||
{
|
data: [
|
||||||
id: "inv_900007",
|
{ id: "inv_900007", lines: { data: [plan: { product: "prod_8675309" }] } },
|
||||||
lines: {
|
{ id: "inv_900008", lines: { data: [plan: { product: "prod_8675310" }] } },
|
||||||
data: [
|
{ id: "inv_900008", lines: { data: [plan: { product: "prod_8675310" }] } },
|
||||||
plan: {
|
],
|
||||||
product: "prod_8675309"
|
)
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "inv_900008",
|
|
||||||
lines: {
|
|
||||||
data: [
|
|
||||||
plan: {
|
|
||||||
product: "prod_8675310"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "inv_900008",
|
|
||||||
lines: {
|
|
||||||
data: [
|
|
||||||
plan: {
|
|
||||||
product: "prod_8675310"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
::Stripe::PaymentIntent.expects(:list).with(
|
::Stripe::PaymentIntent
|
||||||
customer: 'c_345678',
|
.expects(:list)
|
||||||
).returns(
|
.with(customer: "c_345678")
|
||||||
data: [
|
.returns(
|
||||||
{
|
data: [
|
||||||
id: "pi_900008",
|
{ id: "pi_900008", invoice: "inv_900008", created: created_time },
|
||||||
invoice: "inv_900008",
|
{ id: "pi_900008", invoice: "inv_900008", created: created_time },
|
||||||
created: created_time
|
{ id: "pi_900007", invoice: "inv_900007", created: Time.now },
|
||||||
},
|
{ id: "pi_007", invoice: "inv_007", created: Time.now },
|
||||||
{
|
],
|
||||||
id: "pi_900008",
|
)
|
||||||
invoice: "inv_900008",
|
|
||||||
created: created_time
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "pi_900007",
|
|
||||||
invoice: "inv_900007",
|
|
||||||
created: Time.now
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "pi_007",
|
|
||||||
invoice: "inv_007",
|
|
||||||
created: Time.now
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
get "/s/user/payments.json"
|
get "/s/user/payments.json"
|
||||||
|
|
||||||
|
@ -99,9 +58,7 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
expect(invoice).to eq("inv_900007")
|
expect(invoice).to eq("inv_900007")
|
||||||
expect(parsed_body.count).to eq(2)
|
expect(parsed_body.count).to eq(2)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
module DiscourseSubscriptions
|
module DiscourseSubscriptions
|
||||||
RSpec.describe User::SubscriptionsController do
|
RSpec.describe User::SubscriptionsController do
|
||||||
it 'is a subclass of ApplicationController' do
|
it "is a subclass of ApplicationController" do
|
||||||
expect(DiscourseSubscriptions::User::SubscriptionsController < ::ApplicationController).to eq(true)
|
expect(DiscourseSubscriptions::User::SubscriptionsController < ::ApplicationController).to eq(
|
||||||
|
true,
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when not authenticated" do
|
context "when not authenticated" do
|
||||||
|
@ -27,8 +29,10 @@ module DiscourseSubscriptions
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when authenticated" do
|
context "when authenticated" do
|
||||||
let(:user) { Fabricate(:user, email: 'beanie@example.com') }
|
let(:user) { Fabricate(:user, email: "beanie@example.com") }
|
||||||
let(:customer) { Fabricate(:customer, user_id: user.id, customer_id: "cus_23456", product_id: "prod_123") }
|
let(:customer) do
|
||||||
|
Fabricate(:customer, user_id: user.id, customer_id: "cus_23456", product_id: "prod_123")
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
|
@ -39,42 +43,35 @@ module DiscourseSubscriptions
|
||||||
let(:plans) do
|
let(:plans) do
|
||||||
{
|
{
|
||||||
data: [
|
data: [
|
||||||
{
|
{ id: "plan_1", product: { name: "ACME Subscriptions" } },
|
||||||
id: "plan_1",
|
{ id: "plan_2", product: { name: "ACME Other Subscriptions" } },
|
||||||
product: { name: 'ACME Subscriptions' },
|
],
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "plan_2",
|
|
||||||
product: { name: 'ACME Other Subscriptions' },
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:customers) do
|
let(:customers) do
|
||||||
{
|
{
|
||||||
data: [{
|
data: [
|
||||||
id: "cus_23456",
|
{
|
||||||
subscriptions: {
|
id: "cus_23456",
|
||||||
data: [
|
subscriptions: {
|
||||||
{ id: "sub_1234", items: { data: [price: { id: "plan_1" }] } },
|
data: [
|
||||||
{ id: "sub_4567", items: { data: [price: { id: "plan_2" }] } }
|
{ id: "sub_1234", items: { data: [price: { id: "plan_1" }] } },
|
||||||
]
|
{ id: "sub_4567", items: { data: [price: { id: "plan_2" }] } },
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}]
|
],
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it "gets subscriptions" do
|
it "gets subscriptions" do
|
||||||
::Stripe::Price.expects(:list).with(
|
::Stripe::Price.expects(:list).with(expand: ["data.product"], limit: 100).returns(plans)
|
||||||
expand: ['data.product'],
|
|
||||||
limit: 100
|
|
||||||
).returns(plans)
|
|
||||||
|
|
||||||
::Stripe::Customer.expects(:list).with(
|
::Stripe::Customer
|
||||||
email: user.email,
|
.expects(:list)
|
||||||
expand: ['data.subscriptions']
|
.with(email: user.email, expand: ["data.subscriptions"])
|
||||||
).returns(customers)
|
.returns(customers)
|
||||||
|
|
||||||
get "/s/user/subscriptions.json"
|
get "/s/user/subscriptions.json"
|
||||||
|
|
||||||
|
@ -82,9 +79,18 @@ module DiscourseSubscriptions
|
||||||
|
|
||||||
expect(subscription).to eq(
|
expect(subscription).to eq(
|
||||||
"id" => "sub_1234",
|
"id" => "sub_1234",
|
||||||
"items" => { "data" => [{ "price" => { "id" => "plan_1" } }] },
|
"items" => {
|
||||||
"plan" => { "id" => "plan_1", "product" => { "name" => "ACME Subscriptions" } },
|
"data" => [{ "price" => { "id" => "plan_1" } }],
|
||||||
"product" => { "name" => "ACME Subscriptions" }
|
},
|
||||||
|
"plan" => {
|
||||||
|
"id" => "plan_1",
|
||||||
|
"product" => {
|
||||||
|
"name" => "ACME Subscriptions",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"product" => {
|
||||||
|
"name" => "ACME Subscriptions",
|
||||||
|
},
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
describe SiteSerializer do
|
describe SiteSerializer do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
let(:guardian) { Guardian.new(user) }
|
let(:guardian) { Guardian.new(user) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -11,22 +11,22 @@ describe SiteSerializer do
|
||||||
SiteSetting.discourse_subscriptions_enabled = true
|
SiteSetting.discourse_subscriptions_enabled = true
|
||||||
SiteSetting.discourse_subscriptions_campaign_enabled = true
|
SiteSetting.discourse_subscriptions_campaign_enabled = true
|
||||||
end
|
end
|
||||||
it 'is false if the goal_met date is < 7 days old' do
|
it "is false if the goal_met date is < 7 days old" do
|
||||||
Discourse.redis.set('subscriptions_goal_met_date', 10.days.ago)
|
Discourse.redis.set("subscriptions_goal_met_date", 10.days.ago)
|
||||||
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
|
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
|
||||||
|
|
||||||
expect(data[:show_campaign_banner]).to be false
|
expect(data[:show_campaign_banner]).to be false
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is true if the goal_met date is > 7 days old' do
|
it "is true if the goal_met date is > 7 days old" do
|
||||||
Discourse.redis.set('subscriptions_goal_met_date', 1.days.ago)
|
Discourse.redis.set("subscriptions_goal_met_date", 1.days.ago)
|
||||||
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
|
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
|
||||||
|
|
||||||
expect(data[:show_campaign_banner]).to be true
|
expect(data[:show_campaign_banner]).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'fails gracefully if the goal_met date is invalid' do
|
it "fails gracefully if the goal_met date is invalid" do
|
||||||
Discourse.redis.set('subscriptions_goal_met_date', 'bananas')
|
Discourse.redis.set("subscriptions_goal_met_date", "bananas")
|
||||||
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
|
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
|
||||||
expect(data[:show_campaign_banner]).to be false
|
expect(data[:show_campaign_banner]).to be false
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require "rails_helper"
|
||||||
|
|
||||||
describe DiscourseSubscriptions::Campaign do
|
describe DiscourseSubscriptions::Campaign do
|
||||||
describe 'campaign data is refreshed' do
|
describe "campaign data is refreshed" do
|
||||||
let (:user) { Fabricate(:user) }
|
let (:user) {
|
||||||
let (:user2) { Fabricate(:user) }
|
Fabricate(:user)
|
||||||
|
}
|
||||||
|
let (:user2) {
|
||||||
|
Fabricate(:user)
|
||||||
|
}
|
||||||
let(:subscription) do
|
let(:subscription) do
|
||||||
{
|
{
|
||||||
id: "sub_1234",
|
id: "sub_1234",
|
||||||
|
@ -16,12 +20,12 @@ describe DiscourseSubscriptions::Campaign do
|
||||||
product: "prodct_23456",
|
product: "prodct_23456",
|
||||||
unit_amount: 1000,
|
unit_amount: 1000,
|
||||||
recurring: {
|
recurring: {
|
||||||
interval: "month"
|
interval: "month",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
let(:invoice) do
|
let(:invoice) do
|
||||||
|
@ -37,10 +41,10 @@ describe DiscourseSubscriptions::Campaign do
|
||||||
active: true,
|
active: true,
|
||||||
unit_amount: 1000,
|
unit_amount: 1000,
|
||||||
recurring: nil,
|
recurring: nil,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
let(:invoice2) do
|
let(:invoice2) do
|
||||||
|
@ -56,20 +60,20 @@ describe DiscourseSubscriptions::Campaign do
|
||||||
active: true,
|
active: true,
|
||||||
unit_amount: 600,
|
unit_amount: 600,
|
||||||
recurring: nil,
|
recurring: nil,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Fabricate(:product, external_id: "prodct_23456")
|
Fabricate(:product, external_id: "prodct_23456")
|
||||||
Fabricate(:customer, product_id: "prodct_23456", user_id: user.id, customer_id: 'x')
|
Fabricate(:customer, product_id: "prodct_23456", user_id: user.id, customer_id: "x")
|
||||||
Fabricate(:product, external_id: "prodct_65432")
|
Fabricate(:product, external_id: "prodct_65432")
|
||||||
Fabricate(:customer, product_id: "prodct_65432", user_id: user2.id, customer_id: 'y')
|
Fabricate(:customer, product_id: "prodct_65432", user_id: user2.id, customer_id: "y")
|
||||||
Fabricate(:product, external_id: "prodct_65433")
|
Fabricate(:product, external_id: "prodct_65433")
|
||||||
Fabricate(:customer, product_id: "prodct_65433", user_id: user2.id, customer_id: 'y')
|
Fabricate(:customer, product_id: "prodct_65433", user_id: user2.id, customer_id: "y")
|
||||||
SiteSetting.discourse_subscriptions_public_key = "public-key"
|
SiteSetting.discourse_subscriptions_public_key = "public-key"
|
||||||
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
|
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
|
||||||
end
|
end
|
||||||
|
@ -92,17 +96,17 @@ describe DiscourseSubscriptions::Campaign do
|
||||||
::Stripe::Invoice.expects(:list).returns(data: [invoice], has_more: false)
|
::Stripe::Invoice.expects(:list).returns(data: [invoice], has_more: false)
|
||||||
|
|
||||||
DiscourseSubscriptions::Campaign.new.refresh_data
|
DiscourseSubscriptions::Campaign.new.refresh_data
|
||||||
expect(Discourse.redis.get('subscriptions_goal_met_date')).to be_present
|
expect(Discourse.redis.get("subscriptions_goal_met_date")).to be_present
|
||||||
end
|
end
|
||||||
|
|
||||||
it "checks if goal is < 90% met after being met" do
|
it "checks if goal is < 90% met after being met" do
|
||||||
SiteSetting.discourse_subscriptions_campaign_goal = 25
|
SiteSetting.discourse_subscriptions_campaign_goal = 25
|
||||||
Discourse.redis.set('subscriptions_goal_met_date', 10.days.ago)
|
Discourse.redis.set("subscriptions_goal_met_date", 10.days.ago)
|
||||||
::Stripe::Subscription.expects(:list).returns(data: [subscription], has_more: false)
|
::Stripe::Subscription.expects(:list).returns(data: [subscription], has_more: false)
|
||||||
::Stripe::Invoice.expects(:list).returns(data: [invoice], has_more: false)
|
::Stripe::Invoice.expects(:list).returns(data: [invoice], has_more: false)
|
||||||
|
|
||||||
DiscourseSubscriptions::Campaign.new.refresh_data
|
DiscourseSubscriptions::Campaign.new.refresh_data
|
||||||
expect(Discourse.redis.get('subscriptions_goal_met_date')).to be_blank
|
expect(Discourse.redis.get("subscriptions_goal_met_date")).to be_blank
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -116,25 +120,28 @@ describe DiscourseSubscriptions::Campaign do
|
||||||
{
|
{
|
||||||
price: {
|
price: {
|
||||||
product: "prod_use",
|
product: "prod_use",
|
||||||
unit_amount: 10000,
|
unit_amount: 10_000,
|
||||||
recurring: {
|
recurring: {
|
||||||
interval: "year"
|
interval: "year",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Fabricate(:product, external_id: "prod_use")
|
Fabricate(:product, external_id: "prod_use")
|
||||||
Fabricate(:customer, product_id: "prod_use", user_id: user2.id, customer_id: 'y')
|
Fabricate(:customer, product_id: "prod_use", user_id: user2.id, customer_id: "y")
|
||||||
SiteSetting.discourse_subscriptions_campaign_product = "prod_use"
|
SiteSetting.discourse_subscriptions_campaign_product = "prod_use"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "refreshes campaign data with only the campaign product/subscriptions" do
|
it "refreshes campaign data with only the campaign product/subscriptions" do
|
||||||
::Stripe::Subscription.expects(:list).returns(data: [subscription, campaign_subscription], has_more: false)
|
::Stripe::Subscription.expects(:list).returns(
|
||||||
|
data: [subscription, campaign_subscription],
|
||||||
|
has_more: false,
|
||||||
|
)
|
||||||
::Stripe::Invoice.expects(:list).returns(data: [invoice], has_more: false)
|
::Stripe::Invoice.expects(:list).returns(data: [invoice], has_more: false)
|
||||||
|
|
||||||
DiscourseSubscriptions::Campaign.new.refresh_data
|
DiscourseSubscriptions::Campaign.new.refresh_data
|
||||||
|
|
Loading…
Reference in New Issue