app/controllers/alaveteli_pro/subscriptions_controller.rb
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 :check_plan_exists, only: [:create]
before_action :check_has_current_subscription, only: [:index]
def index
@customer = current_user.pro_account.try(:stripe_customer)
@subscriptions = @customer.subscriptions.map do |subscription|
AlaveteliPro::SubscriptionWithDiscount.new(subscription)
end
if @customer.default_source
@card =
@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
#
# params =>
# {"utf8"=>"✓",
# "authenticity_token"=>"Ono2YgLcl1eC1gGzyd7Vf5HJJhOek31yFpT+8z+tKoo=",
# "stripe_token"=>"tok_s3kr3t…",
# "controller"=>"alaveteli_pro/subscriptions",
# "action"=>"create",
# "plan_id"=>"WDTK-pro"}
def create
begin
@pro_account = current_user.pro_account ||= current_user.build_pro_account
# Ensure previous incomplete subscriptions are cancelled to prevent them
# from using the new card
@pro_account.subscriptions.incomplete.map(&:delete)
@token = Stripe::Token.retrieve(params[:stripe_token])
@pro_account.token = @token
@pro_account.update_stripe_customer
@subscription = @pro_account.subscriptions.build
@subscription.update_attributes(
plan: params.require(:plan_id),
tax_percent: tax_percent,
payment_behavior: 'allow_incomplete'
)
@subscription.coupon = coupon_code if coupon_code?
@subscription.save
rescue ProAccount::CardError,
Stripe::CardError => e
flash[:error] = e.message
rescue Stripe::RateLimitError,
Stripe::InvalidRequestError,
Stripe::AuthenticationError,
Stripe::APIConnectionError,
Stripe::StripeError => e
flash[:error] =
case e.message
when /No such coupon/
_('Coupon code is invalid.')
when /Coupon expired/
_('Coupon code has expired.')
else
if send_exception_notifications?
ExceptionNotifier.notify_exception(e, env: request.env)
end
_('There was a problem submitting your payment. You ' \
'have not been charged. Please try again later.')
end
end
if flash[:error]
json_redirect_to plan_path(non_namespaced_plan_id)
else
redirect_to authorise_subscription_path(@subscription.id)
end
end
def authorise
@subscription = current_user.pro_account.subscriptions.
retrieve(params.require(:id))
if !@subscription
head :not_found
elsif @subscription.require_authorisation?
respond_to do |format|
format.json do
render json: {
payment_intent: @subscription.payment_intent.client_secret,
callback_url: authorise_subscription_path(@subscription.id)
}
end
end
elsif @subscription.invoice_open?
flash[:error] = _('There was a problem authorising your payment. You ' \
'have not been charged. Please try again.')
json_redirect_to plan_path(
remove_stripe_namespace(@subscription.plan.id)
)
elsif @subscription.active?
current_user.add_role(:pro)
flash[:notice] = {
partial: 'alaveteli_pro/subscriptions/signup_message'
}
flash[:new_pro_user] = true
json_redirect_to alaveteli_pro_dashboard_path
else
head :ok
end
rescue Stripe::RateLimitError,
Stripe::InvalidRequestError,
Stripe::AuthenticationError,
Stripe::APIConnectionError,
Stripe::StripeError => e
if send_exception_notifications?
ExceptionNotifier.notify_exception(e, env: request.env)
end
flash[:error] = _('There was a problem submitting your payment. You ' \
'have not been charged. Please try again later.')
json_redirect_to plan_path('pro')
end
def destroy
begin
@customer = current_user.pro_account.try(:stripe_customer)
raise ActiveRecord::RecordNotFound unless @customer
@subscription = Stripe::Subscription.retrieve(params[:id])
unless @subscription.customer == @customer.id
raise ActiveRecord::RecordNotFound
end
@subscription.delete(at_period_end: true)
flash[:notice] = _('You have successfully cancelled your subscription ' \
'to {{pro_site_name}}',
pro_site_name: pro_site_name)
rescue Stripe::RateLimitError,
Stripe::InvalidRequestError,
Stripe::AuthenticationError,
Stripe::APIConnectionError,
Stripe::StripeError => e
if send_exception_notifications?
ExceptionNotifier.notify_exception(e, env: request.env)
end
flash[:error] = _('There was a problem cancelling your account. Please ' \
'try again later.')
end
redirect_to subscriptions_path
end
private
def authenticate
authenticated? || ask_to_login(
web: _('To upgrade your account'),
email: _('Then you can upgrade your account'),
email_subject: _('To upgrade your account')
)
end
def check_allowed_to_subscribe_to_pro
return if current_user.active?
flash[:error] = _("Sorry, you can't sign up to {{pro_site_name}} at this " \
"time.", pro_site_name: pro_site_name)
json_redirect_to pro_plans_path
end
def check_has_current_subscription
# TODO: This doesn't take the plan in to account
return if @user.pro_account.try(:subscription?)
flash[:notice] = _("You don't currently have a Pro subscription")
redirect_to pro_plans_path
end
def non_namespaced_plan_id
remove_stripe_namespace(params[:plan_id]) if params[:plan_id]
end
def coupon_code?
params[:coupon_code].present?
end
def coupon_code
add_stripe_namespace(params.require(:coupon_code)).upcase
end
def referral_coupon
coupon_code =
add_stripe_namespace(AlaveteliConfiguration.pro_referral_coupon)
@referral_coupon ||=
unless coupon_code.blank?
begin
Stripe::Coupon.retrieve(coupon_code)
rescue Stripe::StripeError
end
end
end
def tax_percent
(BigDecimal(AlaveteliConfiguration.stripe_tax_rate).to_f * 100).to_f
end
def check_plan_exists
redirect_to(pro_plans_path) unless non_namespaced_plan_id
end
def prevent_duplicate_submission
# TODO: This doesn't take the plan in to account
return unless @user.pro_account.try(:subscription?)
json_redirect_to alaveteli_pro_dashboard_path
end
def json_redirect_to(url)
respond_to do |format|
format.html { redirect_to url }
format.json { render json: { url: url } }
end
end
end