diff --git a/app/controllers/alaveteli_pro/subscriptions_controller.rb b/app/controllers/alaveteli_pro/subscriptions_controller.rb
index 794bbe7ead..2334b1beae 100644
--- a/app/controllers/alaveteli_pro/subscriptions_controller.rb
+++ b/app/controllers/alaveteli_pro/subscriptions_controller.rb
@@ -1,13 +1,11 @@
class AlaveteliPro::SubscriptionsController < AlaveteliPro::BaseController
- include AlaveteliPro::StripeNamespace
-
skip_before_action :html_response, only: [:create, :authorise]
skip_before_action :pro_user_authenticated?, only: [:create, :authorise]
before_action :authenticate, only: [:create, :authorise]
before_action :check_allowed_to_subscribe_to_pro, only: [:create]
before_action :prevent_duplicate_submission, only: [:create]
- before_action :load_plan, only: [:create]
+ before_action :load_plan, :load_coupon, only: [:create]
before_action :check_has_current_subscription, only: [:index]
def index
@@ -19,11 +17,6 @@ def index
@customer.
sources.select { |card| card.id == @customer.default_source }.first
end
-
- if referral_coupon
- @discount_code = remove_stripe_namespace(referral_coupon.id)
- @discount_terms = referral_coupon.metadata.humanized_terms
- end
end
# TODO: remove reminder of Stripe params once shipped
@@ -53,7 +46,7 @@ def create
tax_percent: @plan.tax_percent,
payment_behavior: 'allow_incomplete'
}
- attributes[:coupon] = coupon_code if coupon_code?
+ attributes[:coupon] = @coupon.id if @coupon
@subscription = @pro_account.subscriptions.create(attributes)
@@ -222,6 +215,10 @@ def load_plan
@plan || redirect_to(pro_plans_path)
end
+ def load_coupon
+ @coupon = AlaveteliPro::Coupon.retrieve(params[:coupon_code])
+ end
+
def prevent_duplicate_submission
# TODO: This doesn't take the plan in to account
return unless @user.pro_account.try(:subscription?)
diff --git a/app/models/alaveteli_pro/coupon.rb b/app/models/alaveteli_pro/coupon.rb
new file mode 100644
index 0000000000..e6a0dacfee
--- /dev/null
+++ b/app/models/alaveteli_pro/coupon.rb
@@ -0,0 +1,26 @@
+##
+# A wrapper for a Stripe::Coupon
+#
+class AlaveteliPro::Coupon < SimpleDelegator
+ extend AlaveteliPro::StripeNamespace
+ include AlaveteliPro::StripeNamespace
+
+ def self.referral
+ id = add_stripe_namespace(AlaveteliConfiguration.pro_referral_coupon)
+ retrieve(id) if id
+ end
+
+ def self.retrieve(id)
+ new(Stripe::Coupon.retrieve(add_stripe_namespace(id)))
+ rescue Stripe::InvalidRequestError
+ nil
+ end
+
+ def to_param
+ remove_stripe_namespace(id)
+ end
+
+ def terms
+ metadata.humanized_terms || name
+ end
+end
diff --git a/app/views/alaveteli_pro/subscriptions/index.html.erb b/app/views/alaveteli_pro/subscriptions/index.html.erb
index e6c434d774..21a382f72c 100644
--- a/app/views/alaveteli_pro/subscriptions/index.html.erb
+++ b/app/views/alaveteli_pro/subscriptions/index.html.erb
@@ -42,14 +42,14 @@
<% end %>
- <% if @discount_code && @discount_terms %>
+ <% if @referral = AlaveteliPro::Coupon.referral %>
<%= _('Refer a friend') %>
<%= _('Share the code {{discount_code}} with a friend to give ' \
'them {{discount_terms}} on signup.',
- discount_code: content_tag(:strong, @discount_code),
- discount_terms: @discount_terms) %>
+ discount_code: content_tag(:strong, @referral.to_param),
+ discount_terms: @referral.terms) %>
<% end %>
diff --git a/spec/controllers/alaveteli_pro/subscriptions_controller_spec.rb b/spec/controllers/alaveteli_pro/subscriptions_controller_spec.rb
index 9c1b51a6ed..dad74b45bb 100644
--- a/spec/controllers/alaveteli_pro/subscriptions_controller_spec.rb
+++ b/spec/controllers/alaveteli_pro/subscriptions_controller_spec.rb
@@ -16,7 +16,7 @@
before do
stripe_helper.create_coupon(
- id: 'COUPON_CODE',
+ id: 'coupon_code',
amount_off: 1000,
currency: 'gbp'
)
@@ -156,7 +156,7 @@
include_examples 'successful example'
it 'uses coupon code' do
- expect(assigns(:subscription).discount.coupon.id).to eq('COUPON_CODE')
+ expect(assigns(:subscription).discount.coupon.id).to eq('coupon_code')
end
end
@@ -172,7 +172,7 @@
and_return('alaveteli')
stripe_helper.create_coupon(
- id: 'ALAVETELI-COUPON_CODE',
+ id: 'alaveteli-coupon_code',
amount_off: 1000,
currency: 'gbp'
)
@@ -187,8 +187,8 @@
include_examples 'successful example'
it 'uses namespaced coupon code' do
- expect(assigns(:subscription).discount.coupon.id).to eq(
- 'ALAVETELI-COUPON_CODE')
+ expect(assigns(:subscription).discount.coupon.id).
+ to eq('alaveteli-coupon_code')
end
end
@@ -777,54 +777,6 @@
get :index
expect(assigns[:card].id).to eq(customer.default_source)
end
-
- context 'if a PRO_REFERRAL_COUPON is blank' do
- it 'does not assign the discount code' do
- get :index
- expect(assigns[:discount_code]).to be_nil
- end
-
- it 'does not assign the discount terms' do
- get :index
- expect(assigns[:discount_terms]).to be_nil
- end
- end
-
- context 'if a PRO_REFERRAL_COUPON is set' do
- before do
- allow(AlaveteliConfiguration).
- to receive(:pro_referral_coupon).and_return('PROREFERRAL')
- allow(AlaveteliConfiguration).
- to receive(:stripe_namespace).and_return('ALAVETELI')
- end
-
- let!(:coupon) do
- stripe_helper.create_coupon(
- percent_off: 50,
- duration: 'repeating',
- duration_in_months: 1,
- id: 'ALAVETELI-PROREFERRAL',
- metadata: { humanized_terms: '50% off for 1 month' }
- )
- end
-
- it 'assigns the discount code, stripping the stripe namespace' do
- get :index
- expect(assigns[:discount_code]).to eq('PROREFERRAL')
- end
-
- it 'assigns the discount terms' do
- get :index
- expect(assigns[:discount_terms]).to eq('50% off for 1 month')
- end
-
- it 'rescues from any stripe error' do
- error = Stripe::InvalidRequestError.new('Coupon expired', 'param')
- StripeMock.prepare_error(error, :get_coupon)
- get :index
- expect(assigns[:discount_code]).to be_nil
- end
- end
end
end
diff --git a/spec/models/alaveteli_pro/coupon_spec.rb b/spec/models/alaveteli_pro/coupon_spec.rb
new file mode 100644
index 0000000000..658b6ae4df
--- /dev/null
+++ b/spec/models/alaveteli_pro/coupon_spec.rb
@@ -0,0 +1,81 @@
+require 'spec_helper'
+
+RSpec.describe AlaveteliPro::Coupon do
+ describe '.referral' do
+ before { described_class.instance_variable_set(:@referral, nil) }
+
+ it 'returns a coupon for the referral configuration' do
+ stripe_coupon = double('Stripe::Coupon')
+ allow(AlaveteliConfiguration).to receive(:pro_referral_coupon).
+ and_return('REFERRAL')
+ allow(described_class).to receive(:add_stripe_namespace).
+ and_return('namespace_REFERRAL')
+ allow(Stripe::Coupon).to receive(:retrieve).with('namespace_REFERRAL').
+ and_return(stripe_coupon)
+
+ expect(described_class.referral).to be_an_instance_of(described_class)
+ expect(described_class.referral).to eq(stripe_coupon)
+ end
+
+ it 'returns nil if no referral coupon is configured' do
+ allow(AlaveteliConfiguration).to receive(:pro_referral_coupon).
+ and_return(nil)
+
+ expect(described_class.referral).to be_nil
+ end
+ end
+
+ describe '.retrieve' do
+ it 'retrieves a Stripe coupon and wraps it' do
+ stripe_coupon = double('Stripe::Coupon')
+ allow(Stripe::Coupon).to receive(:retrieve).and_return(stripe_coupon)
+ allow(described_class).to receive(:add_stripe_namespace).
+ and_return('namespace_ID')
+
+ coupon = described_class.retrieve('ID')
+ expect(coupon).to be_a(described_class)
+ expect(coupon.__getobj__).to eq(stripe_coupon)
+ end
+
+ it 'returns nil if the coupon is not found' do
+ allow(Stripe::Coupon).to receive(:retrieve).
+ and_raise(Stripe::InvalidRequestError.new('', ''))
+
+ expect(described_class.retrieve('NONEXISTENT')).to be_nil
+ end
+ end
+
+ describe '#to_param' do
+ it 'removes the stripe namespace from the id' do
+ coupon = described_class.new(double('Stripe::Coupon', id: 'namespace_ID'))
+ allow(coupon).to receive(:remove_stripe_namespace).and_return('ID')
+
+ expect(coupon.to_param).to eq('ID')
+ end
+ end
+
+ describe '#terms' do
+ it 'returns humanized terms from metadata if present' do
+ coupon = described_class.new(
+ double(
+ 'Stripe::Coupon',
+ metadata: double(humanized_terms: 'Human readable terms')
+ )
+ )
+
+ expect(coupon.terms).to eq('Human readable terms')
+ end
+
+ it 'returns name if humanized terms are not present' do
+ coupon = described_class.new(
+ double(
+ 'Stripe::Coupon',
+ metadata: double(humanized_terms: nil),
+ name: 'Coupon Name'
+ )
+ )
+
+ expect(coupon.terms).to eq('Coupon Name')
+ end
+ end
+end