DEV: Introduce syntax_tree for ruby formatting (#144)

This commit is contained in:
David Taylor 2022-12-29 12:35:06 +00:00 committed by GitHub
parent cbbc23fd5a
commit 4e1a17c40c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 980 additions and 844 deletions

View File

@ -55,3 +55,12 @@ jobs:
- name: Rubocop
if: ${{ !cancelled() }}
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

View File

@ -80,7 +80,7 @@ jobs:
- name: Get yarn cache directory
id: yarn-cache-dir
run: echo "::set-output name=dir::$(yarn cache dir)"
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- name: Yarn cache
uses: actions/cache@v3
@ -130,7 +130,7 @@ jobs:
shell: bash
run: |
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
- name: Plugin RSpec
@ -142,7 +142,7 @@ jobs:
shell: bash
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
echo "::set-output name=files_exist::true"
echo "files_exist=true" >> $GITHUB_OUTPUT
fi
- name: Plugin QUnit

View File

@ -1,5 +1,5 @@
inherit_gem:
rubocop-discourse: default.yml
rubocop-discourse: stree-compat.yml
AllCops:
Exclude:
- "gems/**/*"

2
.streerc Normal file
View File

@ -0,0 +1,2 @@
--print-width=100
--plugins=plugin/trailing_comma

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
source 'https://rubygems.org'
source "https://rubygems.org"
group :development do
gem 'translations-manager', git: 'https://github.com/discourse/translations-manager.git'
gem 'rubocop-discourse'
gem "translations-manager", git: "https://github.com/discourse/translations-manager.git"
gem "rubocop-discourse"
gem "syntax_tree"
end

View File

@ -12,6 +12,7 @@ GEM
parallel (1.22.1)
parser (3.1.2.1)
ast (~> 2.4.1)
prettier_print (1.2.0)
rainbow (3.1.1)
regexp_parser (2.6.0)
rexml (3.2.5)
@ -33,6 +34,8 @@ GEM
rubocop-rspec (2.13.2)
rubocop (~> 1.33)
ruby-progressbar (1.11.0)
syntax_tree (5.1.0)
prettier_print (>= 1.2.0)
unicode-display_width (2.3.0)
PLATFORMS
@ -40,6 +43,7 @@ PLATFORMS
DEPENDENCIES
rubocop-discourse
syntax_tree
translations-manager!
BUNDLED WITH

View File

@ -9,7 +9,8 @@ module DiscourseSubscriptions
end
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

View File

@ -18,23 +18,24 @@ module DiscourseSubscriptions
end
def create
params.require([:promo, :discount_type, :discount, :active])
params.require(%i[promo discount_type discount active])
begin
coupon_params = {
duration: 'forever',
}
coupon_params = { duration: "forever" }
case params[:discount_type]
when 'amount'
when "amount"
coupon_params[:amount_off] = params[:discount].to_i * 100
coupon_params[:currency] = SiteSetting.discourse_subscriptions_currency
when 'percent'
when "percent"
coupon_params[:percent_off] = params[:discount]
end
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
rescue ::Stripe::InvalidRequestError => e
@ -43,14 +44,9 @@ module DiscourseSubscriptions
end
def update
params.require([:id, :active])
params.require(%i[id active])
begin
promo_code = ::Stripe::PromotionCode.update(
params[:id],
{
active: params[:active]
}
)
promo_code = ::Stripe::PromotionCode.update(params[:id], { active: params[:active] })
render_json_dump promo_code
rescue ::Stripe::InvalidRequestError => e

View File

@ -27,15 +27,11 @@ module DiscourseSubscriptions
active: params[:active],
metadata: {
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]
}
end
price_object[:recurring] = { interval: params[:interval] } if params[:type] == "recurring"
plan = ::Stripe::Price.create(price_object)
@ -56,14 +52,16 @@ module DiscourseSubscriptions
end
interval = nil
if plan[:recurring] && plan[:recurring][:interval]
interval = plan[:recurring][:interval]
end
interval = plan[:recurring][:interval] if plan[:recurring] && plan[:recurring][:interval]
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
rescue ::Stripe::InvalidRequestError => e
render_json_error e.message
end
@ -71,15 +69,16 @@ module DiscourseSubscriptions
def update
begin
plan = ::Stripe::Price.update(
params[:id],
nickname: params[:nickname],
active: params[:active],
metadata: {
group_name: params[:metadata][:group_name],
trial_period_days: params[:trial_period_days]
}
)
plan =
::Stripe::Price.update(
params[:id],
nickname: params[:nickname],
active: params[:active],
metadata: {
group_name: params[:metadata][:group_name],
trial_period_days: params[:trial_period_days],
},
)
render_json_dump plan
rescue ::Stripe::InvalidRequestError => e

View File

@ -27,20 +27,15 @@ module DiscourseSubscriptions
def create
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)
end
create_params.except!(:statement_descriptor) if params[:statement_descriptor].blank?
product = ::Stripe::Product.create(create_params)
Product.create(
external_id: product[:id]
)
Product.create(external_id: product[:id])
render_json_dump product
rescue ::Stripe::InvalidRequestError => e
render_json_error e.message
end
@ -51,7 +46,6 @@ module DiscourseSubscriptions
product = ::Stripe::Product.retrieve(params[:id])
render_json_dump product
rescue ::Stripe::InvalidRequestError => e
render_json_error e.message
end
@ -59,13 +53,9 @@ module DiscourseSubscriptions
def update
begin
product = ::Stripe::Product.update(
params[:id],
product_params
)
product = ::Stripe::Product.update(params[:id], product_params)
render_json_dump product
rescue ::Stripe::InvalidRequestError => e
render_json_error e.message
end
@ -78,7 +68,6 @@ module DiscourseSubscriptions
Product.delete_by(external_id: params[:id])
render_json_dump product
rescue ::Stripe::InvalidRequestError => e
render_json_error e.message
end
@ -95,8 +84,8 @@ module DiscourseSubscriptions
statement_descriptor: params[:statement_descriptor],
metadata: {
description: params.dig(:metadata, :description),
repurchaseable: params.dig(:metadata, :repurchaseable)
}
repurchaseable: params.dig(:metadata, :repurchaseable),
},
}
end
end

View File

@ -16,20 +16,23 @@ module DiscourseSubscriptions
has_more: false,
data: [],
length: 0,
last_record: params[:last_record]
last_record: params[:last_record],
}
if subscription_ids.present? && is_stripe_configured?
while subscriptions[:length] < PAGE_LIMIT
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)
break if current_set[:has_more] == false
end
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[:has_more] = current_set[:has_more]
break if subscriptions[:has_more] == false
@ -50,10 +53,11 @@ module DiscourseSubscriptions
refund_subscription(params[:id]) if params[:refund]
subscription = ::Stripe::Subscription.delete(params[:id])
customer = Customer.find_by(
product_id: subscription[:plan][:product],
customer_id: subscription[:customer]
)
customer =
Customer.find_by(
product_id: subscription[:plan][:product],
customer_id: subscription[:customer],
)
Subscription.delete_by(external_id: params[:id])
@ -65,7 +69,6 @@ module DiscourseSubscriptions
end
render_json_dump subscription
rescue ::Stripe::InvalidRequestError => e
render_json_error e.message
end
@ -74,7 +77,11 @@ module DiscourseSubscriptions
private
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
def find_valid_subscriptions(data, ids)
@ -85,11 +92,11 @@ module DiscourseSubscriptions
# this will only refund the most recent subscription payment
def refund_subscription(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]
refund = ::Stripe::Refund.create({
payment_intent: payment_intent,
})
refund = ::Stripe::Refund.create({ payment_intent: payment_intent })
end
end
end

View File

@ -14,7 +14,7 @@ module DiscourseSubscriptions
def create
begin
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
event = ::Stripe::Webhook.construct_event(payload, sig_header, webhook_secret)
@ -25,37 +25,39 @@ module DiscourseSubscriptions
end
case event[:type]
when 'customer.subscription.created'
when 'customer.subscription.updated'
customer = Customer.find_by(
customer_id: event[:data][:object][:customer],
product_id: event[:data][:object][:plan][:product],
)
when "customer.subscription.created"
when "customer.subscription.updated"
customer =
Customer.find_by(
customer_id: event[:data][:object][:customer],
product_id: event[:data][:object][:plan][:product],
)
return render_json_error 'customer not found' if !customer
return head 200 if event[:data][:object][:status] != 'complete'
return render_json_error "customer not found" if !customer
return head 200 if event[:data][:object][:status] != "complete"
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])
group.add(user)
end
when 'customer.subscription.deleted'
customer = Customer.find_by(
customer_id: event[:data][:object][:customer],
product_id: event[:data][:object][:plan][:product],
)
when "customer.subscription.deleted"
customer =
Customer.find_by(
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(
customer_id: customer.id,
external_id: event[:data][:object][:id]
external_id: event[:data][:object][:id],
)&.destroy!
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])
group.remove(user)

View File

@ -5,7 +5,7 @@ module DiscourseSubscriptions
include DiscourseSubscriptions::Stripe
include DiscourseSubscriptions::Group
before_action :set_api_key
requires_login except: [:index, :contributors, :show]
requires_login except: %i[index contributors show]
def index
begin
@ -13,19 +13,12 @@ module DiscourseSubscriptions
products = []
if product_ids.present? && is_stripe_configured?
response = ::Stripe::Product.list({
ids: product_ids,
active: true
})
products = response[:data].map do |p|
serialize_product(p)
end
response = ::Stripe::Product.list({ ids: product_ids, active: true })
products = response[:data].map { |p| serialize_product(p) }
end
render_json_dump products
rescue ::Stripe::InvalidRequestError => e
render_json_error e.message
end
@ -36,7 +29,11 @@ module DiscourseSubscriptions
contributor_ids = Set.new
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)
@ -49,10 +46,7 @@ module DiscourseSubscriptions
product = ::Stripe::Product.retrieve(params[:id])
plans = ::Stripe::Price.list(active: true, product: params[:id])
response = {
product: serialize_product(product),
plans: serialize_plans(plans)
}
response = { product: serialize_product(product), plans: serialize_plans(plans) }
render_json_dump response
rescue ::Stripe::InvalidRequestError => e
@ -61,7 +55,7 @@ module DiscourseSubscriptions
end
def create
params.require([:source, :plan])
params.require(%i[source plan])
begin
customer = find_or_create_customer(params[:source])
plan = ::Stripe::Price.retrieve(params[:plan])
@ -70,38 +64,46 @@ module DiscourseSubscriptions
promo_code = ::Stripe::PromotionCode.list({ code: params[:promo] })
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
recurring_plan = plan[:type] == 'recurring'
recurring_plan = plan[:type] == "recurring"
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
transaction = ::Stripe::Subscription.create(
customer: customer[:id],
items: [{ price: params[:plan] }],
metadata: metadata_user,
trial_period_days: trial_days,
promotion_code: promo_code_id
)
transaction =
::Stripe::Subscription.create(
customer: customer[:id],
items: [{ price: params[:plan] }],
metadata: metadata_user,
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
coupon_id = promo_code[:coupon][:id] if promo_code && promo_code[:coupon] && promo_code[:coupon][:id]
invoice_item = ::Stripe::InvoiceItem.create(
customer: customer[:id],
price: params[:plan],
discounts: [{ coupon: coupon_id }]
)
invoice = ::Stripe::Invoice.create(
customer: customer[:id]
)
coupon_id = promo_code[:coupon][:id] if promo_code && promo_code[:coupon] &&
promo_code[:coupon][:id]
invoice_item =
::Stripe::InvoiceItem.create(
customer: customer[:id],
price: params[:plan],
discounts: [{ coupon: coupon_id }],
)
invoice = ::Stripe::Invoice.create(customer: customer[:id])
transaction = ::Stripe::Invoice.finalize_invoice(invoice[:id])
payment_intent = retrieve_payment_intent(transaction[:id]) if transaction[:status] == 'open'
transaction = ::Stripe::Invoice.pay(invoice[:id]) if payment_intent[:status] == 'successful'
payment_intent = retrieve_payment_intent(transaction[:id]) if transaction[:status] ==
"open"
transaction = ::Stripe::Invoice.pay(invoice[:id]) if payment_intent[:status] ==
"successful"
end
finalize_transaction(transaction, plan) if transaction_ok(transaction)
@ -115,7 +117,7 @@ module DiscourseSubscriptions
end
def finalize
params.require([:plan, :transaction])
params.require(%i[plan transaction])
begin
price = ::Stripe::Price.retrieve(params[:plan])
transaction = retrieve_transaction(params[:transaction])
@ -132,17 +134,15 @@ module DiscourseSubscriptions
group.add(current_user) if group
customer = Customer.create(
user_id: current_user.id,
customer_id: transaction[:customer],
product_id: plan[:product]
)
if transaction[:object] == 'subscription'
Subscription.create(
customer_id: customer.id,
external_id: transaction[:id]
customer =
Customer.create(
user_id: current_user.id,
customer_id: transaction[:customer],
product_id: plan[:product],
)
if transaction[:object] == "subscription"
Subscription.create(customer_id: customer.id, external_id: transaction[:id])
end
end
@ -154,23 +154,20 @@ module DiscourseSubscriptions
name: product[:name],
description: PrettyText.cook(product[:metadata][:description]),
subscribed: current_user_products.include?(product[:id]),
repurchaseable: product[:metadata][:repurchaseable]
repurchaseable: product[:metadata][:repurchaseable],
}
end
def current_user_products
return [] if current_user.nil?
Customer
.select(:product_id)
.where(user_id: current_user.id)
.map { |c| c.product_id }.compact
Customer.select(:product_id).where(user_id: current_user.id).map { |c| c.product_id }.compact
end
def serialize_plans(plans)
plans[:data].map do |plan|
plan.to_h.slice(:id, :unit_amount, :currency, :type, :recurring)
end.sort_by { |plan| plan[:amount] }
plans[:data]
.map { |plan| plan.to_h.slice(:id, :unit_amount, :currency, :type, :recurring) }
.sort_by { |plan| plan[:amount] }
end
def find_or_create_customer(source)
@ -179,10 +176,7 @@ module DiscourseSubscriptions
if customer.present?
::Stripe::Customer.retrieve(customer.customer_id)
else
::Stripe::Customer.create(
email: current_user.email,
source: source
)
::Stripe::Customer.create(email: current_user.email, source: source)
end
end

View File

@ -22,7 +22,8 @@ module DiscourseSubscriptions
invoices_with_products = parse_invoices(all_invoices, product_ids)
invoice_ids = invoices_with_products.map { |invoice| invoice[: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
end
end
@ -30,7 +31,6 @@ module DiscourseSubscriptions
data = data.sort_by { |pmt| pmt[:created] }.reverse
render_json_dump data
rescue ::Stripe::InvalidRequestError => e
render_json_error e.message
end
@ -39,16 +39,19 @@ module DiscourseSubscriptions
private
def parse_invoices(all_invoices, product_ids)
invoices_with_products = all_invoices[:data].select do |invoice|
invoice_lines = invoice[:lines][:data][0] if invoice[:lines] && invoice[:lines][:data]
invoice_product_id = parse_invoice_lines(invoice_lines)
product_ids.include?(invoice_product_id)
end
invoices_with_products =
all_invoices[:data].select do |invoice|
invoice_lines = invoice[:lines][:data][0] if invoice[:lines] && invoice[:lines][:data]
invoice_product_id = parse_invoice_lines(invoice_lines)
product_ids.include?(invoice_product_id)
end
end
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[:plan][:product] if invoice_lines[:plan] && invoice_lines[:plan][:product]
invoice_product_id = invoice_lines[:price][:product] if invoice_lines[:price] &&
invoice_lines[:price][:product]
invoice_product_id = invoice_lines[:plan][:product] if invoice_lines[:plan] &&
invoice_lines[:plan][:product]
invoice_product_id
end
end

View File

@ -12,24 +12,21 @@ module DiscourseSubscriptions
begin
customer = Customer.where(user_id: current_user.id)
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 = []
if subscription_ids
plans = ::Stripe::Price.list(
expand: ['data.product'],
limit: 100
)
plans = ::Stripe::Price.list(expand: ["data.product"], limit: 100)
customers = ::Stripe::Customer.list(
email: current_user.email,
expand: ['data.subscriptions']
)
customers =
::Stripe::Customer.list(email: current_user.email, expand: ["data.subscriptions"])
subscriptions = customers[:data].map do |sub_customer|
sub_customer[:subscriptions][:data]
end.flatten(1)
subscriptions =
customers[:data].map { |sub_customer| sub_customer[:subscriptions][:data] }.flatten(1)
subscriptions = subscriptions.select { |sub| subscription_ids.include?(sub[:id]) }
@ -41,7 +38,6 @@ module DiscourseSubscriptions
end
render_json_dump subscriptions
rescue ::Stripe::InvalidRequestError => e
render_json_error e.message
end
@ -51,14 +47,13 @@ module DiscourseSubscriptions
# we cancel but don't remove until the end of the period
# full removal is done via webhooks
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
render_json_dump subscription
else
render_json_error I18n.t('discourse_subscriptions.customer_not_found')
render_json_error I18n.t("discourse_subscriptions.customer_not_found")
end
rescue ::Stripe::InvalidRequestError => e
render_json_error e.message
end
@ -70,7 +65,11 @@ module DiscourseSubscriptions
subscription = Subscription.where(external_id: params[:id]).first
begin
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
rescue ::Stripe::InvalidRequestError
render_json_error I18n.t("discourse_subscriptions.card.invalid")
@ -81,12 +80,7 @@ module DiscourseSubscriptions
def attach_method_to_customer(customer_id, method)
customer = Customer.find(customer_id)
::Stripe::PaymentMethod.attach(
method,
{
customer: customer.customer_id
}
)
::Stripe::PaymentMethod.attach(method, { customer: customer.customer_id })
end
end
end

View File

@ -2,7 +2,6 @@
module ::Jobs
class ManuallyUpdateCampaignData < ::Jobs::Base
def execute(args)
return unless SiteSetting.discourse_subscriptions_campaign_enabled
DiscourseSubscriptions::Campaign.new.refresh_data

View File

@ -2,14 +2,14 @@
module DiscourseSubscriptions
class PaymentSerializer < ApplicationSerializer
attributes :payment_intent_id,
:receipt_email,
:url,
:created_at_age,
:amount,
:amount_currency,
:username,
:user_id
attributes :payment_intent_id,
:receipt_email,
:url,
:created_at_age,
:amount,
:amount_currency,
:username,
:user_id
def created_at_age
Time.now - object.created_at
@ -19,7 +19,7 @@ module DiscourseSubscriptions
ActiveSupport::NumberHelper.number_to_currency(
object.amount / 100,
precision: 2,
unit: currency_unit
unit: currency_unit,
)
end
@ -32,7 +32,7 @@ module DiscourseSubscriptions
def user
begin
User.find(object.user_id)
rescue
rescue StandardError
nil
end
end

View File

@ -23,9 +23,7 @@ module DiscourseSubscriptions
# Fetch product purchases
one_time_payments = get_one_time_payments(product_ids)
one_time_payments.each do |c|
amount += c[:price].to_f / 100.00
end
one_time_payments.each { |c| amount += c[:price].to_f / 100.00 }
# get number of subscribers
SiteSetting.discourse_subscriptions_campaign_subscribers = subscriptions&.length.to_i
@ -57,7 +55,7 @@ module DiscourseSubscriptions
protected
def goal_met_date_key
'subscriptions_goal_met_date'
"subscriptions_goal_met_date"
end
def check_goal_status
@ -91,9 +89,9 @@ module DiscourseSubscriptions
SiteSetting.discourse_subscriptions_campaign_group = group[:id]
params = {
full_name: I18n.t('js.discourse_subscriptions.campaign.supporters'),
title: I18n.t('js.discourse_subscriptions.campaign.supporter'),
flair_icon: "donate"
full_name: I18n.t("js.discourse_subscriptions.campaign.supporters"),
title: I18n.t("js.discourse_subscriptions.campaign.supporter"),
flair_icon: "donate",
}
group.update(params)
@ -104,11 +102,11 @@ module DiscourseSubscriptions
def create_campaign_product
product_params = {
name: I18n.t('js.discourse_subscriptions.campaign.title'),
name: I18n.t("js.discourse_subscriptions.campaign.title"),
active: true,
metadata: {
description: I18n.t('js.discourse_subscriptions.campaign.body'),
}
description: I18n.t("js.discourse_subscriptions.campaign.body"),
},
}
product = ::Stripe::Product.create(product_params)
@ -123,13 +121,9 @@ module DiscourseSubscriptions
monthly_prices = [3, 5, 10, 25]
yearly_prices = [50, 100]
monthly_prices.each do |price|
create_price(product[:id], group, price, "month")
end
monthly_prices.each { |price| create_price(product[:id], group, price, "month") }
yearly_prices.each do |price|
create_price(product[:id], group, price, "year")
end
yearly_prices.each { |price| create_price(product[:id], group, price, "year") }
end
def create_price(product_id, group_name, amount, recurrence)
@ -140,11 +134,11 @@ module DiscourseSubscriptions
currency: SiteSetting.discourse_subscriptions_currency,
active: true,
recurring: {
interval: recurrence
interval: recurrence,
},
metadata: {
group_name: group_name
}
group_name: group_name,
},
}
plan = ::Stripe::Price.create(price_object)
@ -152,18 +146,13 @@ module DiscourseSubscriptions
def get_one_time_payments(product_ids)
one_time_payments = []
current_set = {
has_more: true,
last_record: nil
}
current_set = { has_more: true, last_record: nil }
if product_ids.present?
# 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
all_invoices = ::Stripe::Invoice.list(
limit: 100,
starting_after: current_set[:last_record]
)
all_invoices =
::Stripe::Invoice.list(limit: 100, starting_after: current_set[:last_record])
current_set[:last_record] = all_invoices[:data].last[:id] if all_invoices[:data].present?
current_set[:has_more] = all_invoices[:has_more]
@ -173,11 +162,8 @@ module DiscourseSubscriptions
next if invoice[:paid] != true
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
if line_item[:plan] == nil &&
line_item[:price] &&
line_item[:price][:recurring] == nil &&
line_item[:price][:active] == true
if line_item[:plan] == nil && line_item[:price] &&
line_item[:price][:recurring] == nil && line_item[:price][:active] == true
product_id = line_item[:price][:product]
if product_ids.include? product_id
line_data = {
@ -197,17 +183,15 @@ module DiscourseSubscriptions
def get_subscription_data
subscriptions = []
current_set = {
has_more: true,
last_record: nil
}
current_set = { has_more: true, last_record: nil }
until current_set[:has_more] == false
current_set = ::Stripe::Subscription.list(
expand: ['data.plan.product'],
limit: 100,
starting_after: current_set[:last_record]
)
current_set =
::Stripe::Subscription.list(
expand: ["data.plan.product"],
limit: 100,
starting_after: current_set[:last_record],
)
current_set[:last_record] = current_set[:data].last[:id] if current_set[:data].present?
subscriptions.concat(current_set[:data].to_a)
@ -217,13 +201,14 @@ module DiscourseSubscriptions
end
def filter_to_subscriptions_products(data, ids)
valid = data.select do |sub|
# cannot .dig stripe objects
items = sub[:items][:data][0] if sub[:items] && sub[:items][:data]
product = items[:price][:product] if items[:price] && items[:price][:product]
valid =
data.select do |sub|
# cannot .dig stripe objects
items = sub[:items][:data][0] if sub[:items] && sub[:items][:data]
product = items[:price][:product] if items[:price] && items[:price][:product]
ids.include?(product)
end
ids.include?(product)
end
valid.empty? ? nil : valid
end

View File

@ -2,31 +2,31 @@
require_dependency "subscriptions_user_constraint"
DiscourseSubscriptions::Engine.routes.draw do
scope 'admin' do
get '/' => 'admin#index'
post '/refresh' => 'admin#refresh_campaign'
post '/create-campaign' => 'admin#create_campaign'
scope "admin" do
get "/" => "admin#index"
post "/refresh" => "admin#refresh_campaign"
post "/create-campaign" => "admin#create_campaign"
end
namespace :admin, constraints: AdminConstraint.new do
resources :plans
resources :subscriptions, only: [:index, :destroy]
resources :subscriptions, only: %i[index destroy]
resources :products
resources :coupons, only: [:index, :create]
resource :coupons, only: [:destroy, :update]
resources :coupons, only: %i[index create]
resource :coupons, only: %i[destroy update]
end
namespace :user do
resources :payments, only: [:index]
resources :subscriptions, only: [:index, :update, :destroy]
resources :subscriptions, only: %i[index update destroy]
end
get '/' => 'subscribe#index'
get '.json' => 'subscribe#index'
get '/contributors' => 'subscribe#contributors'
get '/:id' => 'subscribe#show'
post '/create' => 'subscribe#create'
post '/finalize' => 'subscribe#finalize'
get "/" => "subscribe#index"
get ".json" => "subscribe#index"
get "/contributors" => "subscribe#contributors"
get "/:id" => "subscribe#show"
post "/create" => "subscribe#create"
post "/finalize" => "subscribe#finalize"
post '/hooks' => 'hooks#create'
post "/hooks" => "hooks#create"
end

View File

@ -2,7 +2,7 @@
module ::DiscourseSubscriptions
class Engine < ::Rails::Engine
engine_name 'discourse-subscriptions'
engine_name "discourse-subscriptions"
isolate_namespace DiscourseSubscriptions
end
end

View File

@ -1,23 +1,23 @@
# frozen_string_literal: true
require 'stripe'
require 'highline/import'
require "stripe"
require "highline/import"
desc 'Import subscriptions from Stripe'
task 'subscriptions:subscriptions_import' => :environment do
desc "Import subscriptions from Stripe"
task "subscriptions:subscriptions_import" => :environment do
setup_api
products = get_stripe_products
strip_products_to_import = []
procourse_import = false
procourse_import_response = ask("Were the subscriptions you are importing created in Procourse Memberships?: (y/N)")
if procourse_import_response.downcase == 'y'
procourse_import = true
end
procourse_import_response =
ask("Were the subscriptions you are importing created in Procourse Memberships?: (y/N)")
procourse_import = true if procourse_import_response.downcase == "y"
products.each do |product|
confirm_import = ask("Do you wish to import product #{product[:name]} (id: #{product[:id]}): (y/N)")
next if confirm_import.downcase != 'y'
confirm_import =
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
end
@ -26,28 +26,28 @@ task 'subscriptions:subscriptions_import' => :environment do
end
def get_stripe_products(starting_after: nil)
puts 'Getting products from Stripe API'
puts "Getting products from Stripe API"
all_products = []
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]
break if products[:has_more] == false
starting_after = products[:data].last["id"]
end
all_products
end
def get_stripe_subscriptions(starting_after: nil)
puts 'Getting Subscriptions from Stripe API'
puts "Getting Subscriptions from Stripe API"
all_subscriptions = []
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]
break if subscriptions[:has_more] == false
starting_after = subscriptions[:data].last["id"]
@ -57,7 +57,7 @@ def get_stripe_subscriptions(starting_after: nil)
end
def get_stripe_customers(starting_after: nil)
puts 'Getting Customers from Stripe API'
puts "Getting Customers from Stripe API"
all_customers = []
@ -72,7 +72,7 @@ def get_stripe_customers(starting_after: nil)
end
def import_products(products)
puts 'Importing products:'
puts "Importing products:"
products.each do |product|
puts "Looking for external_id #{product[:id]} ..."
@ -86,7 +86,7 @@ def import_products(products)
end
def import_subscriptions(procourse_import)
puts 'Importing subscriptions'
puts "Importing subscriptions"
product_ids = DiscourseSubscriptions::Product.all.pluck(:external_id)
all_customers = get_stripe_customers
@ -95,7 +95,8 @@ def import_subscriptions(procourse_import)
subscriptions = get_stripe_subscriptions
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}"
subscriptions_for_products.each do |subscription|
@ -113,29 +114,38 @@ def import_subscriptions(procourse_import)
end
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
# 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.
user = User.find(user_id)
if procourse_import || (user && (user.username == username))
subscriptions_customer = DiscourseSubscriptions::Customer.create(
user_id: user_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"
subscriptions_customer =
DiscourseSubscriptions::Customer.create(
user_id: user_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"
end
else
puts "Subscriptions Customer user_id: #{user_id}, customer_id: #{customer_id}, product_id: #{product_id}) already exists"
end
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(
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"
else
@ -147,9 +157,11 @@ def import_subscriptions(procourse_import)
discourse_user = User.find(user_id)
puts "Discourse User: #{discourse_user.username_lower} found for Strip metadata update ..."
updated_subscription = Stripe::Subscription.update(subscription_id,
{ metadata: { user_id: user_id,
username: discourse_user.username_lower } })
updated_subscription =
Stripe::Subscription.update(
subscription_id,
{ metadata: { user_id: user_id, username: discourse_user.username_lower } },
)
puts "Stripe Subscription: #{updated_subscription[:id]}, metadata: #{updated_subscription[:metadata]} UPDATED"
updated_customer = Stripe::Customer.update(customer_id, { email: discourse_user.email })
@ -163,6 +175,6 @@ end
private
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
end

View File

@ -9,7 +9,7 @@
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/layout.scss"
@ -18,47 +18,56 @@ register_asset "stylesheets/common/campaign.scss"
register_asset "stylesheets/mobile/main.scss"
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>"
end
extend_content_security_policy(
script_src: ['https://js.stripe.com/v3/', 'https://hooks.stripe.com']
)
extend_content_security_policy(script_src: %w[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
get '/admin/plugins/discourse-subscriptions' => 'admin/plugins#index', constraints: AdminConstraint.new
get '/admin/plugins/discourse-subscriptions/products' => 'admin/plugins#index', constraints: AdminConstraint.new
get '/admin/plugins/discourse-subscriptions/products/:product_id' => 'admin/plugins#index', constraints: AdminConstraint.new
get '/admin/plugins/discourse-subscriptions/products/:product_id/plans' => 'admin/plugins#index', 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/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 }
get "/admin/plugins/discourse-subscriptions" => "admin/plugins#index",
:constraints => AdminConstraint.new
get "/admin/plugins/discourse-subscriptions/products" => "admin/plugins#index",
:constraints => AdminConstraint.new
get "/admin/plugins/discourse-subscriptions/products/:product_id" => "admin/plugins#index",
:constraints => AdminConstraint.new
get "/admin/plugins/discourse-subscriptions/products/:product_id/plans" => "admin/plugins#index",
: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/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
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/group.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/group.rb", __dir__)
after_initialize do
::Stripe.api_version = "2020-08-27"
::Stripe.set_app_info(
'Discourse Subscriptions',
version: '2.8.1',
url: 'https://github.com/discourse/discourse-subscriptions'
"Discourse Subscriptions",
version: "2.8.1",
url: "https://github.com/discourse/discourse-subscriptions",
)
Discourse::Application.routes.append do
mount ::DiscourseSubscriptions::Engine, at: 's'
end
Discourse::Application.routes.append { mount ::DiscourseSubscriptions::Engine, at: "s" }
add_to_serializer(:site, :show_campaign_banner) do
begin
@ -67,7 +76,7 @@ after_initialize do
goal_met = Discourse.redis.get("subscriptions_goal_met_date")
enabled && campaign_enabled && (!goal_met || 7.days.ago <= Date.parse(goal_met))
rescue
rescue StandardError
false
end
end

View File

@ -1,14 +1,11 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
RSpec.describe Jobs::RefreshSubscriptionsCampaignData do
before { SiteSetting.discourse_subscriptions_campaign_enabled = true }
before do
SiteSetting.discourse_subscriptions_campaign_enabled = true
end
it 'should execute the job only if stripe is configured' do
it "should execute the job only if stripe is configured" do
DiscourseSubscriptions::Campaign.any_instance.expects(:refresh_data).once
described_class.new.execute({})
@ -16,5 +13,4 @@ RSpec.describe Jobs::RefreshSubscriptionsCampaignData do
SiteSetting.discourse_subscriptions_secret_key = "SECRET_KEY"
described_class.new.execute({})
end
end

View File

@ -1,11 +1,11 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
module DiscourseSubscriptions
RSpec.describe Customer do
let(:user) { Fabricate(:user) }
let(:stripe_customer) { { id: 'cus_id4567' } }
let(:stripe_customer) { { id: "cus_id4567" } }
it "has a table name" do
expect(described_class.table_name).to eq "discourse_subscriptions_customers"
@ -13,14 +13,14 @@ module DiscourseSubscriptions
it "creates" do
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
end
it "has a user scope" do
described_class.create_customer(user, stripe_customer)
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

View File

@ -1,14 +1,16 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
module DiscourseSubscriptions
RSpec.describe Admin::CouponsController do
it 'is a subclass of AdminController' do
expect(DiscourseSubscriptions::Admin::CouponsController < ::Admin::AdminController).to eq(true)
it "is a subclass of AdminController" do
expect(DiscourseSubscriptions::Admin::CouponsController < ::Admin::AdminController).to eq(
true,
)
end
context 'when unauthenticated' do
context "when unauthenticated" do
it "does nothing" do
::Stripe::PromotionCode.expects(:list).never
get "/s/admin/coupons.json"
@ -16,36 +18,28 @@ module DiscourseSubscriptions
end
end
context 'when authenticated' do
context "when authenticated" do
let(:admin) { Fabricate(:admin) }
before { sign_in(admin) }
describe "#index" do
it "returns a list of promo codes" do
::Stripe::PromotionCode.expects(:list).with({ limit: 100 }).returns({
data: [{
id: 'promo_123',
coupon: {
valid: true
}
}]
})
::Stripe::PromotionCode
.expects(:list)
.with({ limit: 100 })
.returns({ data: [{ id: "promo_123", coupon: { valid: true } }] })
get "/s/admin/coupons.json"
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
it "only returns valid promo codes" do
::Stripe::PromotionCode.expects(:list).with({ limit: 100 }).returns({
data: [{
id: 'promo_123',
coupon: {
valid: false
}
}]
})
::Stripe::PromotionCode
.expects(:list)
.with({ limit: 100 })
.returns({ data: [{ id: "promo_123", coupon: { valid: false } }] })
get "/s/admin/coupons.json"
expect(response.status).to eq(200)
@ -55,43 +49,39 @@ module DiscourseSubscriptions
describe "#create" do
it "creates a coupon with an amount off" do
::Stripe::Coupon.expects(:create).returns(id: 'coup_123')
::Stripe::PromotionCode.expects(:create).returns({
code: 'p123',
coupon: {
amount_off: 2000
}
})
::Stripe::Coupon.expects(:create).returns(id: "coup_123")
::Stripe::PromotionCode.expects(:create).returns(
{ code: "p123", coupon: { amount_off: 2000 } },
)
post "/s/admin/coupons.json", params: {
promo: 'p123',
discount_type: 'amount',
discount: '2000',
active: true,
}
post "/s/admin/coupons.json",
params: {
promo: "p123",
discount_type: "amount",
discount: "2000",
active: true,
}
expect(response.status).to eq(200)
expect(response.parsed_body['code']).to eq('p123')
expect(response.parsed_body['coupon']['amount_off']).to eq(2000)
expect(response.parsed_body["code"]).to eq("p123")
expect(response.parsed_body["coupon"]["amount_off"]).to eq(2000)
end
it "creates a coupon with a percent off" do
::Stripe::Coupon.expects(:create).returns(id: 'coup_123')
::Stripe::PromotionCode.expects(:create).returns({
code: 'p123',
coupon: {
percent_off: 20
}
})
::Stripe::Coupon.expects(:create).returns(id: "coup_123")
::Stripe::PromotionCode.expects(:create).returns(
{ code: "p123", coupon: { percent_off: 20 } },
)
post "/s/admin/coupons.json", params: {
promo: 'p123',
discount_type: 'percent',
discount: '20',
active: true,
}
post "/s/admin/coupons.json",
params: {
promo: "p123",
discount_type: "percent",
discount: "20",
active: true,
}
expect(response.status).to eq(200)
expect(response.parsed_body['code']).to eq('p123')
expect(response.parsed_body['coupon']['percent_off']).to eq(20)
expect(response.parsed_body["code"]).to eq("p123")
expect(response.parsed_body["coupon"]["percent_off"]).to eq(20)
end
end
end

View File

@ -1,15 +1,17 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
module DiscourseSubscriptions
module Admin
RSpec.describe PlansController do
it 'is a subclass of AdminController' do
expect(DiscourseSubscriptions::Admin::PlansController < ::Admin::AdminController).to eq(true)
it "is a subclass of AdminController" do
expect(DiscourseSubscriptions::Admin::PlansController < ::Admin::AdminController).to eq(
true,
)
end
context 'when not authenticated' do
context "when not authenticated" do
describe "index" do
it "does not get the plans" do
::Stripe::Price.expects(:list).never
@ -25,11 +27,11 @@ module DiscourseSubscriptions
describe "create" do
it "does not create a plan" do
::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
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
end
end
@ -54,7 +56,7 @@ module DiscourseSubscriptions
end
end
context 'when authenticated' do
context "when authenticated" do
let(:admin) { Fabricate(:admin) }
before { sign_in(admin) }
@ -66,62 +68,78 @@ module DiscourseSubscriptions
end
it "lists the plans for the product" do
::Stripe::Price.expects(:list).with({ product: 'prod_id123' })
get "/s/admin/plans.json", params: { product_id: 'prod_id123' }
::Stripe::Price.expects(:list).with({ product: "prod_id123" })
get "/s/admin/plans.json", params: { product_id: "prod_id123" }
end
end
describe "show" 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"
expect(response.status).to eq 200
end
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"
plan = response.parsed_body
expect(plan["currency"]).to eq 'AUD'
expect(plan["interval"]).to eq 'year'
expect(plan["currency"]).to eq "AUD"
expect(plan["interval"]).to eq "year"
end
end
describe "create" do
it "creates a plan with a nickname" do
::Stripe::Price.expects(:create).with(has_entry(:nickname, 'Veg'))
post "/s/admin/plans.json", params: { nickname: 'Veg', metadata: { group_name: '' } }
::Stripe::Price.expects(:create).with(has_entry(:nickname, "Veg"))
post "/s/admin/plans.json", params: { nickname: "Veg", metadata: { group_name: "" } }
end
it "creates a plan with a currency" do
::Stripe::Price.expects(:create).with(has_entry(:currency, 'AUD'))
post "/s/admin/plans.json", params: { currency: 'AUD', metadata: { group_name: '' } }
::Stripe::Price.expects(:create).with(has_entry(:currency, "AUD"))
post "/s/admin/plans.json", params: { currency: "AUD", metadata: { group_name: "" } }
end
it "creates a plan with an interval" do
::Stripe::Price.expects(:create).with(has_entry(recurring: { interval: 'week' }))
post "/s/admin/plans.json", params: { type: 'recurring', interval: 'week', metadata: { group_name: '' } }
::Stripe::Price.expects(:create).with(has_entry(recurring: { interval: "week" }))
post "/s/admin/plans.json",
params: {
type: "recurring",
interval: "week",
metadata: {
group_name: "",
},
}
end
it "creates a plan as a one-time purchase" do
::Stripe::Price.expects(:create).with(Not(has_key(:recurring)))
post "/s/admin/plans.json", params: { metadata: { group_name: '' } }
post "/s/admin/plans.json", params: { metadata: { group_name: "" } }
end
it "creates a plan with an amount" do
::Stripe::Price.expects(:create).with(has_entry(:unit_amount, '102'))
post "/s/admin/plans.json", params: { amount: '102', metadata: { group_name: '' } }
::Stripe::Price.expects(:create).with(has_entry(:unit_amount, "102"))
post "/s/admin/plans.json", params: { amount: "102", metadata: { group_name: "" } }
end
it "creates a plan with a product" do
::Stripe::Price.expects(:create).with(has_entry(product: 'prod_walterwhite'))
post "/s/admin/plans.json", params: { product: 'prod_walterwhite', metadata: { group_name: '' } }
::Stripe::Price.expects(:create).with(has_entry(product: "prod_walterwhite"))
post "/s/admin/plans.json",
params: {
product: "prod_walterwhite",
metadata: {
group_name: "",
},
}
end
it "creates a plan with an active status" do
::Stripe::Price.expects(:create).with(has_entry(:active, 'false'))
post "/s/admin/plans.json", params: { active: 'false', metadata: { group_name: '' } }
::Stripe::Price.expects(:create).with(has_entry(:active, "false"))
post "/s/admin/plans.json", params: { active: "false", metadata: { group_name: "" } }
end
# TODO: Need to fix the metadata tests
@ -141,7 +159,13 @@ module DiscourseSubscriptions
describe "update" do
it "updates a plan" do
::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

View File

@ -1,15 +1,17 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
module DiscourseSubscriptions
module Admin
RSpec.describe ProductsController do
it 'is a subclass of AdminController' do
expect(DiscourseSubscriptions::Admin::ProductsController < ::Admin::AdminController).to eq(true)
it "is a subclass of AdminController" do
expect(DiscourseSubscriptions::Admin::ProductsController < ::Admin::AdminController).to eq(
true,
)
end
context 'when unauthenticated' do
context "when unauthenticated" do
it "does not list the products" do
::Stripe::Product.expects(:list).never
get "/s/admin/products.json"
@ -41,12 +43,12 @@ module DiscourseSubscriptions
end
end
context 'when authenticated' do
context "when authenticated" do
let(:admin) { Fabricate(:admin) }
before { sign_in(admin) }
describe 'index' do
describe "index" do
it "gets the empty products" do
SiteSetting.discourse_subscriptions_public_key = "public-key"
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
@ -55,61 +57,74 @@ module DiscourseSubscriptions
end
end
describe 'create' do
it 'is of product type service' do
::Stripe::Product.expects(:create).with(has_entry(:type, 'service'))
describe "create" do
it "is of product type service" do
::Stripe::Product.expects(:create).with(has_entry(:type, "service"))
post "/s/admin/products.json", params: {}
end
it 'has a name' do
::Stripe::Product.expects(:create).with(has_entry(:name, 'Jesse Pinkman'))
post "/s/admin/products.json", params: { name: 'Jesse Pinkman' }
it "has a name" do
::Stripe::Product.expects(:create).with(has_entry(:name, "Jesse Pinkman"))
post "/s/admin/products.json", params: { name: "Jesse Pinkman" }
end
it 'has an active attribute' do
::Stripe::Product.expects(:create).with(has_entry(active: 'false'))
post "/s/admin/products.json", params: { active: 'false' }
it "has an active attribute" do
::Stripe::Product.expects(:create).with(has_entry(active: "false"))
post "/s/admin/products.json", params: { active: "false" }
end
it 'has a statement descriptor' do
::Stripe::Product.expects(:create).with(has_entry(statement_descriptor: 'Blessed are the cheesemakers'))
post "/s/admin/products.json", params: { statement_descriptor: 'Blessed are the cheesemakers' }
it "has a statement descriptor" do
::Stripe::Product.expects(:create).with(
has_entry(statement_descriptor: "Blessed are the cheesemakers"),
)
post "/s/admin/products.json",
params: {
statement_descriptor: "Blessed are the cheesemakers",
}
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
post "/s/admin/products.json", params: { statement_descriptor: '' }
post "/s/admin/products.json", params: { statement_descriptor: "" }
end
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' }))
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",
},
),
)
post "/s/admin/products.json", params: {
metadata: {
description: 'Oi, I think he just said bless be all the bignoses!',
repurchaseable: 'false'
}
}
post "/s/admin/products.json",
params: {
metadata: {
description: "Oi, I think he just said bless be all the bignoses!",
repurchaseable: "false",
},
}
end
end
describe 'show' do
it 'retrieves the product' do
::Stripe::Product.expects(:retrieve).with('prod_walterwhite')
describe "show" do
it "retrieves the product" do
::Stripe::Product.expects(:retrieve).with("prod_walterwhite")
get "/s/admin/products/prod_walterwhite.json"
end
end
describe 'update' do
it 'updates the product' do
describe "update" do
it "updates the product" do
::Stripe::Product.expects(:update)
patch "/s/admin/products/prod_walterwhite.json", params: {}
end
end
describe 'delete' do
it 'deletes the product' do
::Stripe::Product.expects(:delete).with('prod_walterwhite')
describe "delete" do
it "deletes the product" do
::Stripe::Product.expects(:delete).with("prod_walterwhite")
delete "/s/admin/products/prod_walterwhite.json"
end
end

View File

@ -1,22 +1,26 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
module DiscourseSubscriptions
RSpec.describe Admin::SubscriptionsController do
it 'is a subclass of AdminController' do
expect(DiscourseSubscriptions::Admin::SubscriptionsController < ::Admin::AdminController).to eq(true)
it "is a subclass of AdminController" do
expect(
DiscourseSubscriptions::Admin::SubscriptionsController < ::Admin::AdminController,
).to eq(true)
end
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
Fabricate(:subscription, external_id: "sub_12345", customer_id: customer.id)
Fabricate(:subscription, external_id: "sub_77777", customer_id: customer.id)
end
context 'when unauthenticated' do
context "when unauthenticated" do
it "does nothing" do
::Stripe::Subscription.expects(:list).never
get "/s/admin/subscriptions.json"
@ -29,7 +33,7 @@ module DiscourseSubscriptions
end
end
context 'when authenticated' do
context "when authenticated" do
let(:admin) { Fabricate(:admin) }
before { sign_in(admin) }
@ -41,15 +45,10 @@ module DiscourseSubscriptions
end
it "gets the subscriptions and products" do
::Stripe::Subscription.expects(:list)
.with(expand: ['data.plan.product'], limit: 10, starting_after: nil)
.returns(
has_more: false,
data: [
{ id: "sub_12345" },
{ id: "sub_nope" }
]
)
::Stripe::Subscription
.expects(:list)
.with(expand: ["data.plan.product"], limit: 10, starting_after: nil)
.returns(has_more: false, data: [{ id: "sub_12345" }, { id: "sub_nope" }])
get "/s/admin/subscriptions.json"
subscriptions = response.parsed_body["data"][0]["id"]
@ -58,16 +57,11 @@ module DiscourseSubscriptions
end
it "handles starting at a different point in the set" do
::Stripe::Subscription.expects(:list)
.with(expand: ['data.plan.product'], limit: 10, starting_after: 'sub_nope')
.returns(
has_more: false,
data: [
{ id: "sub_77777" },
{ id: "sub_yepnoep" }
]
)
get "/s/admin/subscriptions.json", params: { last_record: 'sub_nope' }
::Stripe::Subscription
.expects(:list)
.with(expand: ["data.plan.product"], limit: 10, starting_after: "sub_nope")
.returns(has_more: false, data: [{ id: "sub_77777" }, { id: "sub_yepnoep" }])
get "/s/admin/subscriptions.json", params: { last_record: "sub_nope" }
subscriptions = response.parsed_body["data"][0]["id"]
expect(response.status).to eq(200)
@ -76,65 +70,70 @@ module DiscourseSubscriptions
end
describe "destroy" do
let(:group) { Fabricate(:group, name: 'subscribers') }
let(:group) { Fabricate(:group, name: "subscribers") }
before do
group.add(user)
end
before { group.add(user) }
it "deletes a customer" do
::Stripe::Subscription
.expects(:delete)
.with('sub_12345')
.returns(
plan: { product: 'pr_34578' },
customer: 'c_123'
)
.with("sub_12345")
.returns(plan: { product: "pr_34578" }, customer: "c_123")
expect {
delete "/s/admin/subscriptions/sub_12345.json"
}.to change { DiscourseSubscriptions::Customer.count }.by(-1)
expect { delete "/s/admin/subscriptions/sub_12345.json" }.to change {
DiscourseSubscriptions::Customer.count
}.by(-1)
end
it "removes the user from the group" do
::Stripe::Subscription
.expects(:delete)
.with('sub_12345')
.with("sub_12345")
.returns(
plan: { product: 'pr_34578', metadata: { group_name: 'subscribers' } },
customer: 'c_123'
plan: {
product: "pr_34578",
metadata: {
group_name: "subscribers",
},
},
customer: "c_123",
)
expect {
delete "/s/admin/subscriptions/sub_12345.json"
}.to change { user.groups.count }.by(-1)
expect { delete "/s/admin/subscriptions/sub_12345.json" }.to change {
user.groups.count
}.by(-1)
end
it "does not remove the user from the group" do
::Stripe::Subscription
.expects(:delete)
.with('sub_12345')
.with("sub_12345")
.returns(
plan: { product: 'pr_34578', metadata: { group_name: 'group_does_not_exist' } },
customer: 'c_123'
plan: {
product: "pr_34578",
metadata: {
group_name: "group_does_not_exist",
},
},
customer: "c_123",
)
expect {
delete "/s/admin/subscriptions/sub_12345.json"
}.not_to change { user.groups.count }
expect { delete "/s/admin/subscriptions/sub_12345.json" }.not_to change {
user.groups.count
}
end
it "refunds if params[:refund] present" do
::Stripe::Subscription
.expects(:delete)
.with('sub_12345')
.returns(
plan: { product: 'pr_34578' },
customer: 'c_123'
)
::Stripe::Subscription.expects(:retrieve).with('sub_12345').returns(latest_invoice: 'in_123')
::Stripe::Invoice.expects(:retrieve).with('in_123').returns(payment_intent: 'pi_123')
::Stripe::Refund.expects(:create).with({ payment_intent: 'pi_123' })
.with("sub_12345")
.returns(plan: { product: "pr_34578" }, customer: "c_123")
::Stripe::Subscription
.expects(:retrieve)
.with("sub_12345")
.returns(latest_invoice: "in_123")
::Stripe::Invoice.expects(:retrieve).with("in_123").returns(payment_intent: "pi_123")
::Stripe::Refund.expects(:create).with({ payment_intent: "pi_123" })
delete "/s/admin/subscriptions/sub_12345.json", params: { refund: true }
end

View File

@ -1,15 +1,14 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
module DiscourseSubscriptions
RSpec.describe AdminController do
let(:admin) { Fabricate(: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)
end

View File

@ -1,21 +1,19 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
module DiscourseSubscriptions
RSpec.describe HooksController do
before do
SiteSetting.discourse_subscriptions_webhook_secret = 'zascharoo'
end
before { SiteSetting.discourse_subscriptions_webhook_secret = "zascharoo" }
it "contructs a webhook event" do
payload = 'we-want-a-shrubbery'
headers = { HTTP_STRIPE_SIGNATURE: 'stripe-webhook-signature' }
payload = "we-want-a-shrubbery"
headers = { HTTP_STRIPE_SIGNATURE: "stripe-webhook-signature" }
::Stripe::Webhook
.expects(:construct_event)
.with('we-want-a-shrubbery', 'stripe-webhook-signature', 'zascharoo')
.returns(type: 'something')
.with("we-want-a-shrubbery", "stripe-webhook-signature", "zascharoo")
.returns(type: "something")
post "/s/hooks.json", params: payload, headers: headers
@ -24,65 +22,61 @@ module DiscourseSubscriptions
describe "event types" do
let(:user) { Fabricate(:user) }
let(:customer) { Fabricate(:customer, customer_id: 'c_575768', product_id: 'p_8654', user_id: user.id) }
let(:group) { Fabricate(:group, name: 'subscribers-group') }
let(:customer) do
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
{
object: {
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
describe "customer.subscription.updated" do
before do
event = {
type: 'customer.subscription.updated',
data: event_data
}
event = { type: "customer.subscription.updated", data: event_data }
::Stripe::Webhook
.stubs(:construct_event)
.returns(event)
::Stripe::Webhook.stubs(:construct_event).returns(event)
end
it 'is successfull' do
it "is successfull" do
post "/s/hooks.json"
expect(response.status).to eq 200
end
describe 'completing the subscription' do
it 'does not add the user to the group' do
event_data[:object][:status] = 'incomplete'
event_data[:previous_attributes] = { status: 'incomplete' }
describe "completing the subscription" do
it "does not add the user to the group" do
event_data[:object][:status] = "incomplete"
event_data[:previous_attributes] = { status: "incomplete" }
expect {
post "/s/hooks.json"
}.not_to change { user.groups.count }
expect { post "/s/hooks.json" }.not_to change { user.groups.count }
expect(response.status).to eq 200
end
it 'does not add the user to the group' do
event_data[:object][:status] = 'incomplete'
event_data[:previous_attributes] = { status: 'something-else' }
it "does not add the user to the group" do
event_data[:object][:status] = "incomplete"
event_data[:previous_attributes] = { status: "something-else" }
expect {
post "/s/hooks.json"
}.not_to change { user.groups.count }
expect { post "/s/hooks.json" }.not_to change { user.groups.count }
expect(response.status).to eq 200
end
it 'adds the user to the group when completing the transaction' do
event_data[:object][:status] = 'complete'
event_data[:previous_attributes] = { status: 'incomplete' }
it "adds the user to the group when completing the transaction" do
event_data[:object][:status] = "complete"
event_data[:previous_attributes] = { status: "incomplete" }
expect {
post "/s/hooks.json"
}.to change { user.groups.count }.by(1)
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(1)
expect(response.status).to eq 200
end
@ -91,30 +85,23 @@ module DiscourseSubscriptions
describe "customer.subscription.deleted" do
before do
event = {
type: 'customer.subscription.deleted',
data: event_data
}
event = { type: "customer.subscription.deleted", data: event_data }
::Stripe::Webhook
.stubs(:construct_event)
.returns(event)
::Stripe::Webhook.stubs(:construct_event).returns(event)
group.add(user)
end
it "deletes the customer" do
expect {
post "/s/hooks.json"
}.to change { DiscourseSubscriptions::Customer.count }.by(-1)
expect { post "/s/hooks.json" }.to change { DiscourseSubscriptions::Customer.count }.by(
-1,
)
expect(response.status).to eq 200
end
it "removes the user from the group" do
expect {
post "/s/hooks.json"
}.to change { user.groups.count }.by(-1)
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(-1)
expect(response.status).to eq 200
end

View File

@ -1,11 +1,15 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
module DiscourseSubscriptions
RSpec.describe SubscribeController do
let (:user) { Fabricate(:user) }
let (:campaign_user) { Fabricate(:user) }
let (:user) {
Fabricate(:user)
}
let (:campaign_user) {
Fabricate(:user)
}
context "when showing products" do
let(:product) do
@ -13,8 +17,9 @@ module DiscourseSubscriptions
id: "prodct_23456",
name: "Very Special Product",
metadata: {
description: "Many people listened to my phone call with the Ukrainian President while it was being made",
repurchaseable: false
description:
"Many people listened to my phone call with the Ukrainian President while it was being made",
repurchaseable: false,
},
otherstuff: true,
}
@ -23,10 +28,37 @@ module DiscourseSubscriptions
let(:prices) do
{
data: [
{ id: 'plan_id123', unit_amount: 1220, currency: 'aud', recurring: { interval: 'year' }, metadata: {} },
{ id: 'plan_id234', unit_amount: 1399, currency: 'usd', recurring: { interval: 'year' }, metadata: {} },
{ id: 'plan_id678', unit_amount: 1000, currency: 'aud', recurring: { interval: 'week' }, metadata: {} }
]
{
id: "plan_id123",
unit_amount: 1220,
currency: "aud",
recurring: {
interval: "year",
},
metadata: {
},
},
{
id: "plan_id234",
unit_amount: 1399,
currency: "usd",
recurring: {
interval: "year",
},
metadata: {
},
},
{
id: "plan_id678",
unit_amount: 1000,
currency: "aud",
recurring: {
interval: "week",
},
metadata: {
},
},
],
}
end
@ -40,24 +72,36 @@ module DiscourseSubscriptions
end
describe "#index" 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"
expect(response.parsed_body).to eq([{
"id" => "prodct_23456",
"name" => "Very Special Product",
"description" => PrettyText.cook("Many people listened to my phone call with the Ukrainian President while it was being made"),
"subscribed" => false,
"repurchaseable" => false,
}])
expect(response.parsed_body).to eq(
[
{
"id" => "prodct_23456",
"name" => "Very Special Product",
"description" =>
PrettyText.cook(
"Many people listened to my phone call with the Ukrainian President while it was being made",
),
"subscribed" => false,
"repurchaseable" => false,
},
],
)
end
it "is subscribed" do
Fabricate(:customer, product_id: product[:id], user_id: user.id, customer_id: 'x')
::Stripe::Product.expects(:list).with({ ids: product_ids, active: true }).returns(data: [product])
Fabricate(:customer, product_id: product[:id], user_id: user.id, customer_id: "x")
::Stripe::Product
.expects(:list)
.with({ ids: product_ids, active: true })
.returns(data: [product])
get "/s.json"
data = response.parsed_body
@ -66,7 +110,10 @@ module DiscourseSubscriptions
it "is not subscribed" do
::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"
data = response.parsed_body
@ -77,11 +124,16 @@ module DiscourseSubscriptions
describe "#get_contributors" do
before do
Fabricate(:product, external_id: "prod_campaign")
Fabricate(:customer, product_id: "prodct_23456", user_id: user.id, customer_id: 'x')
Fabricate(:customer, product_id: "prod_campaign", user_id: campaign_user.id, customer_id: 'y')
Fabricate(:customer, product_id: "prodct_23456", user_id: user.id, customer_id: "x")
Fabricate(
:customer,
product_id: "prod_campaign",
user_id: campaign_user.id,
customer_id: "y",
)
end
context 'when not showing contributors' do
it 'returns nothing if not set to show contributors' do
context "when not showing contributors" do
it "returns nothing if not set to show contributors" do
SiteSetting.discourse_subscriptions_campaign_show_contributors = false
get "/s/contributors.json"
@ -90,12 +142,10 @@ module DiscourseSubscriptions
end
end
context 'when showing contributors' do
before do
SiteSetting.discourse_subscriptions_campaign_show_contributors = true
end
context "when showing contributors" do
before { SiteSetting.discourse_subscriptions_campaign_show_contributors = true }
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"
get "/s/contributors.json"
@ -105,7 +155,7 @@ module DiscourseSubscriptions
expect(data.length).to eq 1
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
get "/s/contributors.json"
@ -117,25 +167,54 @@ module DiscourseSubscriptions
end
describe "#show" do
it 'retrieves the product' do
::Stripe::Product.expects(:retrieve).with('prod_walterwhite').returns(product)
::Stripe::Price.expects(:list).with(active: true, product: 'prod_walterwhite').returns(prices)
it "retrieves the product" do
::Stripe::Product.expects(:retrieve).with("prod_walterwhite").returns(product)
::Stripe::Price
.expects(:list)
.with(active: true, product: "prod_walterwhite")
.returns(prices)
get "/s/prod_walterwhite.json"
expect(response.parsed_body).to eq({
"product" => {
"id" => "prodct_23456",
"name" => "Very Special Product",
"description" => PrettyText.cook("Many people listened to my phone call with the Ukrainian President while it was being made"),
"subscribed" => false,
"repurchaseable" => false
},
"plans" => [
{ "currency" => "aud", "id" => "plan_id123", "recurring" => { "interval" => "year" }, "unit_amount" => 1220 },
{ "currency" => "usd", "id" => "plan_id234", "recurring" => { "interval" => "year" }, "unit_amount" => 1399 },
{ "currency" => "aud", "id" => "plan_id678", "recurring" => { "interval" => "week" }, "unit_amount" => 1000 }
]
})
expect(response.parsed_body).to eq(
{
"product" => {
"id" => "prodct_23456",
"name" => "Very Special Product",
"description" =>
PrettyText.cook(
"Many people listened to my phone call with the Ukrainian President while it was being made",
),
"subscribed" => false,
"repurchaseable" => false,
},
"plans" => [
{
"currency" => "aud",
"id" => "plan_id123",
"recurring" => {
"interval" => "year",
},
"unit_amount" => 1220,
},
{
"currency" => "usd",
"id" => "plan_id234",
"recurring" => {
"interval" => "year",
},
"unit_amount" => 1399,
},
{
"currency" => "aud",
"id" => "plan_id678",
"recurring" => {
"interval" => "week",
},
"unit_amount" => 1000,
},
],
},
)
end
end
end
@ -146,81 +225,91 @@ module DiscourseSubscriptions
::Stripe::Customer.expects(:create).never
::Stripe::Price.expects(:retrieve).never
::Stripe::Subscription.expects(:create).never
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
end
end
context "when authenticated" do
before do
sign_in(user)
end
before { sign_in(user) }
describe "#create" do
before do
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
end
before { ::Stripe::Customer.expects(:create).returns(id: "cus_1234") }
it "creates a subscription" do
::Stripe::Price.expects(:retrieve).returns(
type: 'recurring',
product: 'product_12345',
type: "recurring",
product: "product_12345",
metadata: {
group_name: 'awesome',
trial_period_days: 0
}
group_name: "awesome",
trial_period_days: 0,
},
)
::Stripe::Subscription.expects(:create).with(
customer: 'cus_1234',
items: [ price: 'plan_1234' ],
metadata: { user_id: user.id, username: user.username_lower },
trial_period_days: 0,
promotion_code: nil
).returns(status: 'active', customer: 'cus_1234')
::Stripe::Subscription
.expects(:create)
.with(
customer: "cus_1234",
items: [price: "plan_1234"],
metadata: {
user_id: user.id,
username: user.username_lower,
},
trial_period_days: 0,
promotion_code: nil,
)
.returns(status: "active", customer: "cus_1234")
expect {
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
}.to change { DiscourseSubscriptions::Customer.count }
end
it "creates a one time payment subscription" do
::Stripe::Price.expects(:retrieve).returns(
type: 'one_time',
product: 'product_12345',
type: "one_time",
product: "product_12345",
metadata: {
group_name: 'awesome'
}
group_name: "awesome",
},
)
::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 {
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 }
end
it "creates a customer model" do
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: {}).twice
::Stripe::Subscription.expects(:create).returns(status: 'active', customer: 'cus_1234')
::Stripe::Price.expects(:retrieve).returns(type: "recurring", metadata: {}).twice
::Stripe::Subscription.expects(:create).returns(status: "active", customer: "cus_1234")
expect {
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
}.to change { DiscourseSubscriptions::Customer.count }
::Stripe::Customer.expects(:retrieve).with('cus_1234')
::Stripe::Customer.expects(:retrieve).with("cus_1234")
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 }
end
@ -228,19 +317,22 @@ module DiscourseSubscriptions
context "with invalid code" do
it "prevents use of invalid coupon codes" do
::Stripe::Price.expects(:retrieve).returns(
type: 'recurring',
product: 'product_12345',
type: "recurring",
product: "product_12345",
metadata: {
group_name: 'awesome',
trial_period_days: 0
}
group_name: "awesome",
trial_period_days: 0,
},
)
::Stripe::PromotionCode.expects(:list).with({ code: 'invalid' }).returns(
data: []
)
::Stripe::PromotionCode.expects(:list).with({ code: "invalid" }).returns(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
expect(data["errors"]).not_to be_blank
@ -249,61 +341,86 @@ module DiscourseSubscriptions
context "with valid code" do
before do
::Stripe::PromotionCode.expects(:list).with({ code: '123' }).returns(
data: [{
id: 'promo123',
coupon: { id: 'c123' }
}]
)
::Stripe::PromotionCode
.expects(:list)
.with({ code: "123" })
.returns(data: [{ id: "promo123", coupon: { id: "c123" } }])
end
it "applies promo code to recurring subscription" do
::Stripe::Price.expects(:retrieve).returns(
type: 'recurring',
product: 'product_12345',
type: "recurring",
product: "product_12345",
metadata: {
group_name: 'awesome',
trial_period_days: 0
}
group_name: "awesome",
trial_period_days: 0,
},
)
::Stripe::Subscription.expects(:create).with(
customer: 'cus_1234',
items: [ price: 'plan_1234' ],
metadata: { user_id: user.id, username: user.username_lower },
trial_period_days: 0,
promotion_code: 'promo123'
).returns(status: 'active', customer: 'cus_1234')
::Stripe::Subscription
.expects(:create)
.with(
customer: "cus_1234",
items: [price: "plan_1234"],
metadata: {
user_id: user.id,
username: user.username_lower,
},
trial_period_days: 0,
promotion_code: "promo123",
)
.returns(status: "active", customer: "cus_1234")
expect {
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234', promo: '123' }
post "/s/create.json",
params: {
plan: "plan_1234",
source: "tok_1234",
promo: "123",
}
}.to change { DiscourseSubscriptions::Customer.count }
end
it "applies promo code to one time purchase" do
::Stripe::Price.expects(:retrieve).returns(
type: 'one_time',
product: 'product_12345',
type: "one_time",
product: "product_12345",
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 {
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 }
end
end
@ -313,81 +430,114 @@ module DiscourseSubscriptions
describe "#finalize strong customer authenticated transaction" do
context "with subscription" do
it "finalizes the subscription" do
::Stripe::Price.expects(:retrieve).returns(id: "plan_1234", product: "prod_1234", metadata: {})
::Stripe::Subscription.expects(:retrieve).returns(id: "sub_123", customer: 'cus_1234', status: "active")
::Stripe::Price.expects(:retrieve).returns(
id: "plan_1234",
product: "prod_1234",
metadata: {
},
)
::Stripe::Subscription.expects(:retrieve).returns(
id: "sub_123",
customer: "cus_1234",
status: "active",
)
expect {
post "/s/finalize.json", params: { plan: 'plan_1234', transaction: 'sub_1234' }
post "/s/finalize.json", params: { plan: "plan_1234", transaction: "sub_1234" }
}.to change { DiscourseSubscriptions::Customer.count }
end
end
context "with one-time payment" do
it "finalizes the one-time payment" do
::Stripe::Price.expects(:retrieve).returns(id: "plan_1234", product: "prod_1234", metadata: {})
::Stripe::Invoice.expects(:retrieve).returns(id: "in_123", customer: 'cus_1234', status: "paid")
::Stripe::Price.expects(:retrieve).returns(
id: "plan_1234",
product: "prod_1234",
metadata: {
},
)
::Stripe::Invoice.expects(:retrieve).returns(
id: "in_123",
customer: "cus_1234",
status: "paid",
)
expect {
post "/s/finalize.json", params: { plan: 'plan_1234', transaction: 'in_1234' }
post "/s/finalize.json", params: { plan: "plan_1234", transaction: "in_1234" }
}.to change { DiscourseSubscriptions::Customer.count }
end
end
end
describe "user groups" do
let(:group_name) { 'group-123' }
let(:group_name) { "group-123" }
let(:group) { Fabricate(:group, name: group_name) }
context "with unauthorized group" do
before do
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
::Stripe::Subscription.expects(:create).returns(status: 'active')
::Stripe::Customer.expects(:create).returns(id: "cus_1234")
::Stripe::Subscription.expects(:create).returns(status: "active")
end
it "does not add the user to the admins group" do
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: 'admins' })
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
::Stripe::Price.expects(:retrieve).returns(
type: "recurring",
metadata: {
group_name: "admins",
},
)
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
expect(user.admin).to eq false
end
it "does not add the user to other group" do
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: 'other' })
post "/s/create.json", params: { plan: 'plan_1234', source: 'tok_1234' }
::Stripe::Price.expects(:retrieve).returns(
type: "recurring",
metadata: {
group_name: "other",
},
)
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
expect(user.groups).to be_empty
end
end
context "when plan has group in metadata" do
before do
::Stripe::Customer.expects(:create).returns(id: 'cus_1234')
::Stripe::Price.expects(:retrieve).returns(type: 'recurring', metadata: { group_name: group_name })
::Stripe::Customer.expects(:create).returns(id: "cus_1234")
::Stripe::Price.expects(:retrieve).returns(
type: "recurring",
metadata: {
group_name: group_name,
},
)
end
it "does not add the user to the group when subscription fails" do
::Stripe::Subscription.expects(:create).returns(status: 'failed')
::Stripe::Subscription.expects(:create).returns(status: "failed")
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 }
expect(user.groups).to be_empty
end
it "adds the user to the group when the subscription is active" do
::Stripe::Subscription.expects(:create).returns(status: 'active')
::Stripe::Subscription.expects(:create).returns(status: "active")
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 }
expect(user.groups).not_to be_empty
end
it "adds the user to the group when the subscription is trialing" do
::Stripe::Subscription.expects(:create).returns(status: 'trialing')
::Stripe::Subscription.expects(:create).returns(status: "trialing")
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 }
expect(user.groups).not_to be_empty

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
module DiscourseSubscriptions
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)
end
@ -17,80 +17,39 @@ module DiscourseSubscriptions
end
context "when authenticated" do
let(:user) { Fabricate(:user, email: 'zasch@example.com') }
let(:user) { Fabricate(:user, email: "zasch@example.com") }
before do
sign_in(user)
Fabricate(:customer, customer_id: 'c_345678', user_id: user.id)
Fabricate(:product, external_id: 'prod_8675309')
Fabricate(:product, external_id: 'prod_8675310')
Fabricate(:customer, customer_id: "c_345678", user_id: user.id)
Fabricate(:product, external_id: "prod_8675309")
Fabricate(:product, external_id: "prod_8675310")
end
it "gets payment intents" do
created_time = Time.now
::Stripe::Invoice.expects(:list).with(
customer: 'c_345678'
).returns(
data: [
{
id: "inv_900007",
lines: {
data: [
plan: {
product: "prod_8675309"
}
]
}
},
{
id: "inv_900008",
lines: {
data: [
plan: {
product: "prod_8675310"
}
]
}
},
{
id: "inv_900008",
lines: {
data: [
plan: {
product: "prod_8675310"
}
]
}
},
]
)
::Stripe::Invoice
.expects(:list)
.with(customer: "c_345678")
.returns(
data: [
{ id: "inv_900007", lines: { data: [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(
customer: 'c_345678',
).returns(
data: [
{
id: "pi_900008",
invoice: "inv_900008",
created: created_time
},
{
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
}
]
)
::Stripe::PaymentIntent
.expects(:list)
.with(customer: "c_345678")
.returns(
data: [
{ id: "pi_900008", invoice: "inv_900008", created: created_time },
{ 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"
@ -99,9 +58,7 @@ module DiscourseSubscriptions
expect(invoice).to eq("inv_900007")
expect(parsed_body.count).to eq(2)
end
end
end
end

View File

@ -1,11 +1,13 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
module DiscourseSubscriptions
RSpec.describe User::SubscriptionsController do
it 'is a subclass of ApplicationController' do
expect(DiscourseSubscriptions::User::SubscriptionsController < ::ApplicationController).to eq(true)
it "is a subclass of ApplicationController" do
expect(DiscourseSubscriptions::User::SubscriptionsController < ::ApplicationController).to eq(
true,
)
end
context "when not authenticated" do
@ -27,8 +29,10 @@ module DiscourseSubscriptions
end
context "when authenticated" do
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(:user) { Fabricate(:user, email: "beanie@example.com") }
let(:customer) do
Fabricate(:customer, user_id: user.id, customer_id: "cus_23456", product_id: "prod_123")
end
before do
sign_in(user)
@ -39,42 +43,35 @@ module DiscourseSubscriptions
let(:plans) do
{
data: [
{
id: "plan_1",
product: { name: 'ACME Subscriptions' },
},
{
id: "plan_2",
product: { name: 'ACME Other Subscriptions' },
}
]
{ id: "plan_1", product: { name: "ACME Subscriptions" } },
{ id: "plan_2", product: { name: "ACME Other Subscriptions" } },
],
}
end
let(:customers) do
{
data: [{
id: "cus_23456",
subscriptions: {
data: [
{ id: "sub_1234", items: { data: [price: { id: "plan_1" }] } },
{ id: "sub_4567", items: { data: [price: { id: "plan_2" }] } }
]
data: [
{
id: "cus_23456",
subscriptions: {
data: [
{ id: "sub_1234", items: { data: [price: { id: "plan_1" }] } },
{ id: "sub_4567", items: { data: [price: { id: "plan_2" }] } },
],
},
},
}]
],
}
end
it "gets subscriptions" do
::Stripe::Price.expects(:list).with(
expand: ['data.product'],
limit: 100
).returns(plans)
::Stripe::Price.expects(:list).with(expand: ["data.product"], limit: 100).returns(plans)
::Stripe::Customer.expects(:list).with(
email: user.email,
expand: ['data.subscriptions']
).returns(customers)
::Stripe::Customer
.expects(:list)
.with(email: user.email, expand: ["data.subscriptions"])
.returns(customers)
get "/s/user/subscriptions.json"
@ -82,9 +79,18 @@ module DiscourseSubscriptions
expect(subscription).to eq(
"id" => "sub_1234",
"items" => { "data" => [{ "price" => { "id" => "plan_1" } }] },
"plan" => { "id" => "plan_1", "product" => { "name" => "ACME Subscriptions" } },
"product" => { "name" => "ACME Subscriptions" }
"items" => {
"data" => [{ "price" => { "id" => "plan_1" } }],
},
"plan" => {
"id" => "plan_1",
"product" => {
"name" => "ACME Subscriptions",
},
},
"product" => {
"name" => "ACME Subscriptions",
},
)
end
end

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
describe SiteSerializer do
fab!(:user) { Fabricate(:user) }
fab!(:user) { Fabricate(:user) }
let(:guardian) { Guardian.new(user) }
before do
@ -11,22 +11,22 @@ describe SiteSerializer do
SiteSetting.discourse_subscriptions_enabled = true
SiteSetting.discourse_subscriptions_campaign_enabled = true
end
it 'is false if the goal_met date is < 7 days old' do
Discourse.redis.set('subscriptions_goal_met_date', 10.days.ago)
it "is false if the goal_met date is < 7 days old" do
Discourse.redis.set("subscriptions_goal_met_date", 10.days.ago)
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(data[:show_campaign_banner]).to be false
end
it 'is true if the goal_met date is > 7 days old' do
Discourse.redis.set('subscriptions_goal_met_date', 1.days.ago)
it "is true if the goal_met date is > 7 days old" do
Discourse.redis.set("subscriptions_goal_met_date", 1.days.ago)
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(data[:show_campaign_banner]).to be true
end
it 'fails gracefully if the goal_met date is invalid' do
Discourse.redis.set('subscriptions_goal_met_date', 'bananas')
it "fails gracefully if the goal_met date is invalid" do
Discourse.redis.set("subscriptions_goal_met_date", "bananas")
data = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(data[:show_campaign_banner]).to be false
end

View File

@ -1,11 +1,15 @@
# frozen_string_literal: true
require 'rails_helper'
require "rails_helper"
describe DiscourseSubscriptions::Campaign do
describe 'campaign data is refreshed' do
let (:user) { Fabricate(:user) }
let (:user2) { Fabricate(:user) }
describe "campaign data is refreshed" do
let (:user) {
Fabricate(:user)
}
let (:user2) {
Fabricate(:user)
}
let(:subscription) do
{
id: "sub_1234",
@ -16,12 +20,12 @@ describe DiscourseSubscriptions::Campaign do
product: "prodct_23456",
unit_amount: 1000,
recurring: {
interval: "month"
}
}
}
]
}
interval: "month",
},
},
},
],
},
}
end
let(:invoice) do
@ -37,10 +41,10 @@ describe DiscourseSubscriptions::Campaign do
active: true,
unit_amount: 1000,
recurring: nil,
}
}
]
}
},
},
],
},
}
end
let(:invoice2) do
@ -56,20 +60,20 @@ describe DiscourseSubscriptions::Campaign do
active: true,
unit_amount: 600,
recurring: nil,
}
}
]
}
},
},
],
},
}
end
before do
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(: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(: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_secret_key = "secret-key"
end
@ -92,17 +96,17 @@ describe DiscourseSubscriptions::Campaign do
::Stripe::Invoice.expects(:list).returns(data: [invoice], has_more: false)
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
it "checks if goal is < 90% met after being met" do
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::Invoice.expects(:list).returns(data: [invoice], has_more: false)
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
@ -116,25 +120,28 @@ describe DiscourseSubscriptions::Campaign do
{
price: {
product: "prod_use",
unit_amount: 10000,
unit_amount: 10_000,
recurring: {
interval: "year"
}
}
}
]
}
interval: "year",
},
},
},
],
},
}
end
before do
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"
end
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)
DiscourseSubscriptions::Campaign.new.refresh_data