effective_orders 4.0.0beta5 → 4.0.0beta6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bd54f1217fe33988f924bf40803efd702916d971
4
- data.tar.gz: 291f290fd3cf4b8636ce5103a86b976760e12122
3
+ metadata.gz: 12e3f1de057495a5b6c3dc1b6cbc8127ef8736bf
4
+ data.tar.gz: d30298b8aac6de0afee57cc5e9af2552b01d5519
5
5
  SHA512:
6
- metadata.gz: 546166ac0b6f8948af732a82bdd2ba8b2e59f11ce6f734d10b1d6dd49350926d764331fe179d71f01a3a9d4510786254dfd6bbfeac0cffb992b821d03ea70c6c
7
- data.tar.gz: 1d1602f8456cbf830c82ca6f298b85ca465b384240a5867479df1280a7384c1693e5b1970ff21e9b353bba3371268da37fb21ae4fb17a82bef993be0c74c5418
6
+ metadata.gz: 9524eb918036d200c9d51f5c383e37a05afd43448dffb67e58d25bb43770a20f01e99ff4e09093f86d25d6506c28f7b859848d2c5bef6fe4ca8211b00d6f3b63
7
+ data.tar.gz: 020f1ae55841895de717445760e905c5e8640101d47ea05e3bc8327a805c5544cb844a02c70402a0d2e1144551de15e55b82edb2666190ababe141e253e0b1db
@@ -1,31 +1,29 @@
1
1
  stripeCustomerChangeCardHandler = (key, form) ->
2
2
  StripeCheckout.configure
3
3
  key: key
4
- closed: -> EffectiveBootstrap.enable(form) unless form.hasClass('stripe-success')
4
+ closed: -> EffectiveForm.reset(form) unless form.hasClass('stripe-success')
5
5
  token: (token, args) ->
6
6
  if token.error
7
- message = "An error ocurred when contacting Stripe. Your card has not been charged. Your subscription has not changed. Please refresh the page and try again. #{token.error.message}"
7
+ message = "An error ocurred when contacting Stripe. Your card has not been charged. Please refresh the page and try again. #{token.error.message}"
8
8
 
9
9
  form.removeClass('stripe-success')
10
- form.find('.effective-orders-customer').find('.invalid-feedback').html(message).show()
10
+ form.find('.invalid-feedback').html(message).show()
11
11
  alert(message)
12
12
  else
13
13
  form.find("input[name$='[stripe_token]']").val('' + token['id'])
14
-
15
- $customer = form.find('.effective-orders-customer')
16
- $customer.find('.payment-status').html("**** **** **** #{token.card.last4} #{token.card.brand} #{token.card.exp_month}/#{token.card.exp_year}")
17
-
18
- if $customer.data('submit')
19
- form.addClass('stripe-success').submit()
14
+ form.addClass('stripe-success').submit() # Submits the form. As this is a remote form, submits via JS
20
15
 
21
16
  # When we click 'Change credit card', make sure the form collects a credit card
22
- $(document).on 'click', '.effective-orders-customer .btn-change-card', (event) ->
23
- event.preventDefault()
24
-
17
+ $(document).on 'click', ".effective-orders-stripe-update-card[type='submit']", (event) ->
25
18
  $form = $(event.currentTarget).closest('form')
26
- stripe = $(event.currentTarget).closest('.effective-orders-customer').data('stripe')
27
19
 
28
- EffectiveBootstrap.submitting($form)
20
+ # Get stripe data payload
21
+ stripe = $form.data('stripe')
22
+ return unless stripe?
23
+
24
+ # Okay, we're good to call stripe
25
+ event.preventDefault()
26
+ EffectiveForm.submitting($form) # Disable and spin while we popup stripe
29
27
 
30
28
  stripeCustomerChangeCardHandler(stripe.key, $form).open
31
29
  image: stripe.image
@@ -1,7 +1,7 @@
1
1
  stripeCheckoutHandler = (key, form) ->
2
2
  StripeCheckout.configure
3
3
  key: key
4
- closed: -> EffectiveBootstrap.enable(form) unless form.hasClass('stripe-success')
4
+ closed: -> EffectiveBootstrap.reset(form) unless form.hasClass('stripe-success')
5
5
  token: (token, args) ->
6
6
  if token.error
7
7
  alert("An error ocurred when contacting Stripe. Your card has not been charged. Please refresh the page and try again. #{token.error.message}")
@@ -1,56 +1,42 @@
1
1
  stripeSubscriptionHandler = (key, form) ->
2
2
  StripeCheckout.configure
3
3
  key: key
4
- closed: -> EffectiveBootstrap.enable(form) unless form.hasClass('stripe-success')
4
+ closed: -> EffectiveForm.reset(form) unless form.hasClass('stripe-success')
5
5
  token: (token, args) ->
6
6
  if token.error
7
- message = "An error ocurred when contacting Stripe. Your card has not been charged. Your subscription has not changed. Please refresh the page and try again. #{token.error.message}"
7
+ message = "An error ocurred when contacting Stripe. Your card has not been charged. Your plan has not changed. Please refresh the page and try again. #{token.error.message}"
8
8
 
9
9
  form.removeClass('stripe-success')
10
- form.find('.effective-orders-stripe-plans').find('.invalid-feedback').html(message).show()
10
+ form.find('.invalid-feedback').html(message).show()
11
11
  alert(message)
12
12
  else
13
13
  form.find("input[name$='[stripe_token]']").val('' + token['id'])
14
- form.addClass('stripe-success').submit()
14
+ form.addClass('stripe-success').submit() # Submits the form. As this is a remote form, submits via JS
15
15
 
16
- # When I submit a for that needs a subscripter token, do the stripe thing.
17
- $(document).on 'click', ".effective-orders-subscripter-token-required[type='submit']", (event) ->
18
- event.preventDefault()
16
+ # Hijack submit and get a stripe token
17
+ $(document).on 'click', ".effective-orders-stripe-token-required[type='submit']", (event) ->
19
18
  $form = $(event.currentTarget).closest('form')
20
19
 
21
- # Get the stripe data
22
- $plans = $form.find('.effective-orders-stripe-plans').first()
23
- selected_plan_id = $plans.find("input[name$='[subscripter][stripe_plan_id]']:checked").val()
24
- return unless $plans.length > 0 && selected_plan_id.length > 0
20
+ # Get stripe data payload
21
+ stripe = $form.data('stripe')
22
+ return unless stripe?
25
23
 
26
- EffectiveBootstrap.submitting($form)
24
+ # Make sure there is a plan selected
25
+ selected_plan_id = $form.find("input[name$='[stripe_plan_id]']:checked").val() || ''
26
+ return unless selected_plan_id.length > 0
27
27
 
28
- stripe = $plans.data('stripe')
28
+ # Match plan
29
29
  plan = stripe.plans.find (plan, _) => plan.id == selected_plan_id
30
+ return unless plan?
31
+
32
+ # Okay, we're good to call stripe
33
+ event.preventDefault()
34
+ EffectiveForm.submitting($form) # Disable and spin while we popup stripe
30
35
 
31
36
  stripeSubscriptionHandler(stripe.key, $form).open
32
37
  image: stripe.image
33
38
  name: stripe.name
34
- description: plan.name
35
39
  email: stripe.email
40
+ description: plan.name
36
41
  amount: plan.amount
37
- panelLabel: "{{amount}}#{plan.occurrence} Go!"
38
-
39
- # When I click on a stripe plan ID radio button, add .effective-orders-subscripter-token-required to the form if required
40
- $(document).on 'change', "input[name$='[subscripter][stripe_plan_id]']", (event) ->
41
- $plan = $(event.currentTarget)
42
- return unless $plan.is(':checked')
43
-
44
- selected_plan_id = $plan.val()
45
-
46
- $plans = $plan.closest('.effective-orders-stripe-plans').first()
47
- plan = $plans.data('stripe').plans.find (plan, _) => plan.id == selected_plan_id
48
-
49
- token_required = $plans.data('stripe').token_required
50
-
51
- if (plan.amount || 0) > 0 && token_required
52
- $plans.closest('form').find("input[type='submit'],button[type='submit']").addClass('effective-orders-subscripter-token-required')
53
- else
54
- $plans.closest('form').find("input[type='submit'],button[type='submit']").removeClass('effective-orders-subscripter-token-required')
55
-
56
- true
42
+ panelLabel: "{{amount}}/#{plan.interval} Go!"
@@ -2,42 +2,24 @@ module Effective
2
2
  class CustomersController < ApplicationController
3
3
  layout (EffectiveOrders.layout.kind_of?(Hash) ? EffectiveOrders.layout[:customers] : EffectiveOrders.layout)
4
4
 
5
- before_action :authenticate_user!
5
+ include Effective::CrudController
6
6
 
7
- # Get here by visiting /customer/settings
8
- def edit
9
- @customer = Effective::Customer.where(user: current_user).first!
10
- EffectiveOrders.authorize!(self, :edit, @customer)
7
+ submit :save, 'Save', redirect: :back, success: -> { 'Successfully updated card.' }
8
+ page_title 'Customer Settings'
11
9
 
12
- @subscripter = Effective::Subscripter.new(customer: @customer, user: @customer.user)
13
-
14
- @page_title ||= "Customer #{current_user.to_s}"
10
+ def resource
11
+ @customer ||= Effective::Customer.where(user: current_user).first!
12
+ @subscripter ||= Effective::Subscripter.new(customer: @customer, user: @customer.user)
15
13
  end
16
14
 
17
- def update
18
- @customer = Effective::Customer.where(user: current_user).first!
19
- EffectiveOrders.authorize!(self, :update, @customer)
20
-
21
- @subscripter = Effective::Subscripter.new(customer: @customer, user: @customer.user)
22
- @subscripter.assign_attributes(subscripter_params)
23
-
24
- @page_title ||= "Customer #{current_user.to_s}"
25
-
26
- if (@subscripter.save! rescue false)
27
- flash[:success] = "Successfully updated customer settings"
28
- redirect_to(effective_orders.customer_settings_path)
29
- else
30
- flash.now[:danger] = "Unable to update customer settings: #{@subscripter.errors.full_messages.to_sentence}"
31
- render :edit
32
- end
15
+ # I don't want save_resource to wrap my save in a transaction
16
+ def save_resource(resource, action)
17
+ resource.save!
33
18
  end
34
19
 
35
- private
36
-
37
20
  # StrongParameters
38
- def subscripter_params
21
+ def customer_params
39
22
  params.require(:effective_subscripter).permit(:stripe_token)
40
23
  end
41
-
42
24
  end
43
25
  end
@@ -0,0 +1,23 @@
1
+ module Effective
2
+ class SubscripterController < ApplicationController
3
+ layout (EffectiveOrders.layout.kind_of?(Hash) ? EffectiveOrders.layout[:subscriptions] : EffectiveOrders.layout)
4
+
5
+ include Effective::CrudController
6
+
7
+ submit :save, 'Save', redirect: :back, success: -> { 'Successfully updated plan.' }
8
+
9
+ def resource
10
+ @subscripter ||= Effective::Subscripter.new(user: current_user)
11
+ end
12
+
13
+ # I don't want save_resource to wrap my save in a transaction
14
+ def save_resource(resource, action)
15
+ resource.save!
16
+ end
17
+
18
+ # StrongParameters
19
+ def subscripter_params
20
+ params.require(:effective_subscripter).permit!
21
+ end
22
+ end
23
+ end
@@ -26,18 +26,19 @@ module Effective
26
26
 
27
27
  when 'invoice.payment_succeeded'
28
28
  customer = Effective::Customer.where(stripe_customer_id: @event.data.object.customer).first!
29
- customer.update_attributes!(status: 'active')
29
+ customer.update_attributes!(status: EffectiveOrders::ACTIVE)
30
30
 
31
31
  send_email(:subscription_payment_succeeded, customer)
32
32
  when 'invoice.payment_failed'
33
33
  customer = Effective::Customer.where(stripe_customer_id: @event.data.object.customer).first!
34
- customer.update_attributes!(status: 'past_due')
34
+ customer.update_attributes!(status: EffectiveOrders::PAST_DUE)
35
35
 
36
36
  send_email(:subscription_payment_failed, customer)
37
37
  when 'customer.subscription.deleted'
38
38
  customer = Effective::Customer.where(stripe_customer_id: @event.data.object.customer).first!
39
39
  Effective::Subscription.where(customer: customer).destroy_all
40
40
  customer.update_attributes!(stripe_subscription_id: nil, status: nil, active_card: nil)
41
+ customer.subscriptions.delete_all
41
42
 
42
43
  send_email(:subscription_canceled, customer)
43
44
  else
@@ -1,32 +1,19 @@
1
1
  module EffectiveSubscriptionsHelper
2
2
 
3
- def effective_customer_fields(form, submit: true)
3
+ def stripe_plans_collection(form)
4
4
  raise 'expected an Effective::FormBuilder object' unless form.class.name == 'Effective::FormBuilder'
5
- raise 'form object must be an Effective::Subscripter object' unless form.object.class.name == 'Effective::Subscripter'
6
5
 
7
- render(
8
- partial: 'effective/customers/fields',
9
- locals: {
10
- f: form,
11
- submit: submit,
12
- stripe: {
13
- email: form.object.customer.user.email,
14
- image: stripe_site_image_url,
15
- key: EffectiveOrders.stripe[:publishable_key],
16
- name: EffectiveOrders.stripe[:site_title],
17
- }
18
- }
19
- )
20
- end
6
+ subscripter = form.object
7
+ raise 'form object must be a subscripter object' unless subscripter.class.name == 'Effective::Subscripter'
21
8
 
22
- def stripe_plans_collection(form, include_trial: nil)
23
- raise 'expected an Effective::FormBuilder object' unless form.class.name == 'Effective::FormBuilder'
24
- raise 'form object must be an acts_as_subscribable object' unless form.object.subscribable.subscripter.present?
25
-
26
- include_trial = form.object.subscribable.trialing? if include_trial.nil?
9
+ plans = EffectiveOrders.stripe_plans.values.sort do |x, y|
10
+ amount = (x[:amount] <=> y[:amount])
11
+ (amount != 0) ? amount : x[:name] <=> y[:name]
12
+ end
27
13
 
28
- plans = include_trial ? EffectiveOrders.stripe_plans : EffectiveOrders.stripe_plans.except('trial')
29
- plans = plans.values.sort { |x, y| (amount = x[:amount] <=> y[:amount]) != 0 ? amount : x[:name] <=> y[:name] }
14
+ if (existing = subscripter.customer.stripe_subscription_interval).present?
15
+ plans.select! { |plan| plan[:interval] == existing }
16
+ end
30
17
 
31
18
  plans.map do |plan|
32
19
  partial = (
@@ -49,27 +36,34 @@ module EffectiveSubscriptionsHelper
49
36
  end
50
37
  end
51
38
 
52
- def effective_subscription_fields(form, label: false, required: true, include_trial: nil)
53
- raise 'expected an Effective::FormBuilder object' unless form.class.name == 'Effective::FormBuilder'
54
- raise 'form object must be an acts_as_subscribable object' unless form.object.subscripter.present?
55
-
56
- render(
57
- partial: 'effective/subscriptions/fields',
58
- locals: {
59
- form: form,
60
- label: label,
61
- required: required,
62
- include_trial: include_trial,
63
- stripe: {
64
- email: form.object.subscribable_buyer.email,
65
- image: stripe_site_image_url,
66
- key: EffectiveOrders.stripe[:publishable_key],
67
- name: EffectiveOrders.stripe[:site_title],
68
- plans: EffectiveOrders.stripe_plans.values,
69
- token_required: form.object.subscripter.token_required?
70
- },
71
- }
72
- )
39
+ def subscribable_form_with(subscribable)
40
+ raise 'form object must be an acts_as_subscribable object' unless subscribable.respond_to?(:subscripter)
41
+
42
+ subscripter = subscribable.subscripter
43
+ raise 'subscribable.subscribable_buyer must match current_user' unless subscripter.user == current_user
44
+
45
+ render('effective/subscripter/form', subscripter: subscripter)
73
46
  end
74
47
 
48
+ def customer_form_with(customer)
49
+ raise 'form object must be an Effective::Customer object' unless customer.kind_of?(Effective::Customer)
50
+ raise 'expected customer user to match current user' if customer.user != current_user
51
+
52
+ subscripter = Effective::Subscripter.new(customer: customer, user: customer.user)
53
+
54
+ render('effective/customers/form', subscripter: subscripter)
55
+ end
56
+
57
+ def subscripter_stripe_data(subscripter)
58
+ {
59
+ email: current_user.email,
60
+ image: stripe_site_image_url,
61
+ key: EffectiveOrders.stripe[:publishable_key],
62
+ name: EffectiveOrders.stripe[:site_title],
63
+ plans: EffectiveOrders.stripe_plans.values
64
+ }
65
+ end
66
+
67
+
68
+
75
69
  end
@@ -27,8 +27,6 @@ module ActsAsSubscribable
27
27
  validates :trialing_until, presence: true, if: -> { EffectiveOrders.trial? }
28
28
  validates :subscription_status, inclusion: { allow_nil: true, in: EffectiveOrders::STATUSES.keys }
29
29
 
30
- validates :subscripter, associated: true
31
-
32
30
  scope :trialing, -> { where(subscription_status: nil).where('trialing_until > ?', Time.zone.now) }
33
31
  scope :trial_past_due, -> { where(subscription_status: nil).where('trialing_until < ?', Time.zone.now) }
34
32
  scope :not_trialing, -> { where.not(subscription_status: nil) }
@@ -45,10 +43,6 @@ module ActsAsSubscribable
45
43
  @_effective_subscripter ||= Effective::Subscripter.new(subscribable: self, user: subscribable_buyer)
46
44
  end
47
45
 
48
- def subscripter=(atts)
49
- subscripter.assign_attributes(atts)
50
- end
51
-
52
46
  def subscribed?(stripe_plan_id = nil)
53
47
  return false if subscription_status.blank?
54
48
  stripe_plan_id ? (subscription&.stripe_plan_id == stripe_plan_id) : true
@@ -5,26 +5,23 @@ module Effective
5
5
  attr_accessor :stripe_customer, :stripe_subscription
6
6
 
7
7
  belongs_to :user
8
- has_many :subscribables, as: :subscribable
9
-
10
- has_many :subscriptions, class_name: 'Effective::Subscription', foreign_key: 'customer_id'
11
- has_many :subscribables, through: :subscriptions, source: :subscribable
12
-
13
- #accepts_nested_attributes_for :subscriptions
8
+ has_many :subscriptions, -> { includes(:subscribable) }, class_name: 'Effective::Subscription', foreign_key: 'customer_id'
9
+ accepts_nested_attributes_for :subscriptions
14
10
 
15
11
  # Attributes
16
12
  # stripe_customer_id :string # cus_xja7acoa03
17
13
  # active_card :string # **** **** **** 4242 Visa 05/12
18
14
 
19
15
  # stripe_subscription_id :string # Each user gets one stripe subscription object, which can contain many items
16
+ # stripe_subscription_interval :string
20
17
  # status :string
21
18
 
22
19
  # timestamps
23
20
 
24
21
  scope :deep, -> { includes(subscriptions: :subscribable) }
25
22
 
26
- before_validation do
27
- subscriptions.each { |subscription| subscription.status = status }
23
+ after_commit(if: -> { stripe_subscription_id.present? }) do
24
+ subscriptions.each { |subscription| subscription.subscribable.update_column(:subscription_status, status) }
28
25
  end
29
26
 
30
27
  validates :user, presence: true
@@ -67,14 +64,13 @@ module Effective
67
64
  def payment_status
68
65
  if status == 'past_due'
69
66
  'We ran into an error processing your last payment. Please update or confirm your card details to continue.'
70
- elsif active_card.present? && token_required?
71
- 'Please update or confirm your card details to continue.'
72
- elsif active_card.present?
73
- 'Thanks for your support! The card we have on file is'
74
- else
67
+ elsif status == 'active'
68
+ "Your payment is in good standing. Thanks so much for your support!"
69
+ elsif active_card.blank?
75
70
  'No credit card on file. Please add a card.'
71
+ else
72
+ 'Please update or confirm your card details to continue.'
76
73
  end.html_safe
77
74
  end
78
-
79
75
  end
80
76
  end
@@ -5,36 +5,46 @@ module Effective
5
5
  include ActiveModel::Model
6
6
 
7
7
  attr_accessor :user, :subscribable, :customer
8
- attr_accessor :stripe_plan_id, :stripe_token
8
+ attr_accessor :subscribable_global_id, :stripe_token, :stripe_plan_id, :include_trial
9
9
 
10
10
  validates :user, presence: true
11
- validates :subscribable, presence: true, if: -> { stripe_plan_id }
12
- validates :stripe_plan_id, inclusion: { allow_blank: true, in: EffectiveOrders.stripe_plans.keys, message: 'unknown plan' }
11
+ validates :subscribable, presence: true, if: -> { stripe_plan_id.present? }
12
+ validates :customer, presence: true
13
13
 
14
- validate(if: -> { stripe_plan_id && plan && subscribable }) do
15
- if plan[:amount] > 0 && stripe_token.blank? && token_required?
16
- self.errors.add(:stripe_token, 'updated payment card required')
17
- customer.errors.add(:stripe_token, 'updated payment card required')
18
- end
19
- end
14
+ validates :stripe_plan_id, inclusion: { allow_blank: true, in: EffectiveOrders.stripe_plans.keys, message: 'unknown plan' }
20
15
 
21
- validate(if: -> { subscribable }) do
22
- subscribable.errors.add(:subscripter, errors.messages.values.flatten.to_sentence) if self.errors.present?
16
+ validate(if: -> { stripe_plan_id && plan && plan[:amount] > 0 }) do
17
+ self.errors.add(:stripe_token, 'updated payment card required') if stripe_token.blank? && token_required?
23
18
  end
24
19
 
25
20
  def customer
26
21
  @customer ||= Effective::Customer.deep.where(user: user).first_or_initialize
27
22
  end
28
23
 
24
+ def subscribable_global_id
25
+ subscribable&.to_global_id
26
+ end
27
+
28
+ def subscribable_global_id=(global_id)
29
+ @subscribable = GlobalID::Locator.locate(global_id)
30
+ end
31
+
32
+ def user_id=(id)
33
+ @user = User.find(id)
34
+ end
35
+
29
36
  def current_plan
30
- return nil unless subscribable
31
- subscribable.subscription.blank? ? EffectiveOrders.stripe_plans['trial'] : subscribable.subscription.plan
37
+ subscribable&.subscription&.plan
32
38
  end
33
39
 
34
40
  def plan
35
41
  EffectiveOrders.stripe_plans[stripe_plan_id]
36
42
  end
37
43
 
44
+ def stripe_plan_id
45
+ @stripe_plan_id || (current_plan[:id] if current_plan)
46
+ end
47
+
38
48
  def token_required?
39
49
  customer.token_required?
40
50
  end
@@ -44,71 +54,27 @@ module Effective
44
54
 
45
55
  raise 'is invalid' unless valid?
46
56
 
47
- begin
48
- build! && sync! && customer.save!
49
- rescue => e
50
- reload!
51
-
52
- self.errors.add(:base, e.message)
53
- raise e
54
- end
55
- end
56
-
57
- def subscribe!(stripe_plan_id)
58
- self.stripe_plan_id = stripe_plan_id
59
- save!
60
- end
61
-
62
- def destroy!
63
- return true unless subscription && subscription.persisted? && customer.stripe_subscription.present?
64
-
65
- raise 'is invalid' unless valid?
66
-
67
- subscription.destroy!
68
- customer.subscriptions.reload
69
-
70
- sync! && customer.save!
71
- end
72
-
73
- def reload!
74
- @stripe_token = nil
75
- @stripe_plan_id = nil
76
- @customer = nil
77
- @subscription = nil
78
- end
79
-
80
- private
81
-
82
- def subscription
83
- return nil unless subscribable
84
- @subscription ||= (
85
- customer.subscriptions.find { |sub| sub.subscribable == subscribable } ||
86
- customer.subscriptions.build(subscribable: subscribable, customer: customer)
87
- )
57
+ create_customer!
58
+ create_stripe_token!
59
+ build_subscription!
60
+ sync_subscription!
61
+ true
88
62
  end
89
63
 
90
- def build!
91
- # Check for an existing customer created within the last hour with this email
92
- # This catches an edge case in which a stripe customer is created twice when a first time customer is using a declined card
93
- if customer.stripe_customer.blank?
94
- Rails.logger.info "STRIPE CUSTOMER CHECK FOR EXISTING: #{user.email}"
95
-
96
- customers = Stripe::Customer.list(created: { gt: (user.created_at - 1.hour).to_i } ).data
97
-
98
- if (existing = customers.find { |cus| cus.email == user.email && (cus.metadata || {})[:user_id] == user.id.to_s })
99
- customer.stripe_customer = existing
100
- customer.stripe_customer_id = existing.id
101
- end
102
- end
64
+ protected
103
65
 
104
- # Create customer
66
+ # This should work even if the rest of the form doesn't. Careful with our transactions...
67
+ def create_customer!
105
68
  if customer.stripe_customer.blank?
106
69
  Rails.logger.info "STRIPE CUSTOMER CREATE: #{user.email}"
107
70
  customer.stripe_customer = Stripe::Customer.create(email: user.email, description: user.to_s, metadata: { user_id: user.id })
108
71
  customer.stripe_customer_id = customer.stripe_customer.id
72
+ customer.save!
109
73
  end
74
+ end
110
75
 
111
- # Update stripe customer card
76
+ # Update stripe customer card
77
+ def create_stripe_token!
112
78
  if stripe_token.present?
113
79
  Rails.logger.info "STRIPE CUSTOMER SOURCE UPDATE #{stripe_token}"
114
80
  customer.stripe_customer.source = stripe_token
@@ -117,34 +83,46 @@ module Effective
117
83
  if customer.stripe_customer.default_source.present?
118
84
  card = customer.stripe_customer.sources.retrieve(customer.stripe_customer.default_source)
119
85
  customer.active_card = "**** **** **** #{card.last4} #{card.brand} #{card.exp_month}/#{card.exp_year}"
86
+ customer.save!
120
87
  end
121
88
  end
89
+ end
122
90
 
123
- # Assign stripe plan
124
- if plan
125
- subscription.stripe_plan_id = plan[:id]
91
+ def build_subscription!
92
+ return unless plan.present?
93
+ subscription.stripe_plan_id = plan[:id]
94
+ end
126
95
 
127
- # Ensure stripe subscription exists
128
- if customer.stripe_subscription.blank?
129
- Rails.logger.info "STRIPE SUBSCRIPTION CREATE: #{items(metadata: false)}"
130
- customer.stripe_subscription = Stripe::Subscription.create(customer: customer.stripe_customer_id, items: items(metadata: false), metadata: metadata)
131
- customer.stripe_subscription_id = customer.stripe_subscription.id
132
- end
133
- end
96
+ def sync_subscription!
97
+ return unless plan.present?
98
+ customer.stripe_subscription.blank? ? create_subscription! : update_subscription!
134
99
 
135
- true
100
+ customer.save!
101
+ end
102
+
103
+ def create_subscription!
104
+ return unless plan.present?
105
+ return if customer.stripe_subscription.present?
106
+
107
+ Rails.logger.info "STRIPE SUBSCRIPTION CREATE: #{items(metadata: false)}"
108
+ customer.stripe_subscription = Stripe::Subscription.create(customer: customer.stripe_customer_id, items: items(metadata: false), metadata: metadata)
109
+ customer.stripe_subscription_id = customer.stripe_subscription.id
110
+
111
+ customer.status = customer.stripe_subscription.status
112
+ customer.stripe_subscription_interval = customer.stripe_subscription.plan.interval
136
113
  end
137
114
 
138
- def sync!
139
- return true unless plan && customer.stripe_subscription
115
+ def update_subscription!
116
+ return unless plan.present?
117
+ return if customer.stripe_subscription.blank?
140
118
 
141
119
  Rails.logger.info "STRIPE SUBSCRIPTION SYNC: #{customer.stripe_subscription_id} #{items}"
142
120
 
143
121
  if items.length == 0
144
122
  customer.stripe_subscription.delete
145
123
  customer.stripe_subscription_id = nil
146
- customer.status = nil
147
- return true
124
+ customer.status = EffectiveOrders::CANCELED
125
+ return
148
126
  end
149
127
 
150
128
  # Update stripe subscription items
@@ -189,14 +167,32 @@ module Effective
189
167
  # Stripe::Invoice.create(customer: customer.stripe_customer_id).pay rescue false
190
168
  # end
191
169
 
192
- # Sync status
193
170
  customer.status = customer.stripe_subscription.status
171
+ end
194
172
 
195
- true
173
+ def subscribe!(stripe_plan_id)
174
+ self.stripe_plan_id = stripe_plan_id
175
+ save!
196
176
  end
197
177
 
178
+ # def destroy!
179
+ # return true unless subscription && subscription.persisted? && customer.stripe_subscription.present?
180
+
181
+ # raise 'is invalid' unless valid?
182
+
183
+ # subscription.destroy!
184
+ # customer.subscriptions.reload
185
+
186
+ # sync! && customer.save!
187
+ # end
188
+
198
189
  private
199
190
 
191
+ def subscription
192
+ return nil unless subscribable
193
+ customer.subscriptions.find { |sub| sub.subscribable == subscribable } || customer.subscriptions.build(subscribable: subscribable, customer: customer)
194
+ end
195
+
200
196
  def items(metadata: true)
201
197
  customer.subscriptions.group_by { |sub| sub.stripe_plan_id }.map do |plan, subscriptions|
202
198
  if metadata
@@ -20,7 +20,7 @@ module Effective
20
20
  validates :customer, presence: true
21
21
  validates :subscribable, presence: true
22
22
 
23
- validates :stripe_plan_id, presence: true, inclusion: { in: EffectiveOrders.stripe_plans.except('trial').keys }
23
+ validates :stripe_plan_id, presence: true, inclusion: { in: EffectiveOrders.stripe_plans.keys }
24
24
  validates :name, presence: true
25
25
 
26
26
  def to_s
@@ -1,145 +1,134 @@
1
- %h3.effective-heading Customer
2
-
3
- %table.table
4
- %tbody
5
- %tr
6
- %th Id
7
- %td= customer.stripe_customer.id
8
- %tr
9
- %th Email
10
- %td= customer.stripe_customer.email
11
- %tr
12
- %th Card
13
- %td
14
- - if customer.stripe_customer.default_source.present?
15
- - card = customer.stripe_customer.sources.retrieve(customer.stripe_customer.default_source)
16
- = "**** **** **** #{card.last4} #{card.brand} #{card.exp_month}/#{card.exp_year}"
17
- - else
18
- None
19
-
20
- - if customer.stripe_customer.currency.present?
21
- %tr
22
- %th Currency
23
- %td= customer.stripe_customer.currency.to_s.upcase
24
-
25
- - if customer.stripe_customer.account_balance.to_i > 0
26
- %tr
27
- %th Balance
28
- %td= price_to_currency(customer.stripe_customer.account_balance.to_i)
29
-
30
- = yield if block_given?
31
-
32
1
  - if customer.stripe_subscription.present?
33
- %h3.effective-heading Subscription
34
-
35
- %table.table
36
- %tbody
37
- %tr
38
- %th Status
39
- %td= customer.stripe_subscription.status.presence || 'unknown'
40
-
41
- - if customer.stripe_subscription.discount.present?
42
- %tr
43
- %th Coupon
44
- %td= stripe_coupon_description(customer.stripe_subscription.discount.coupon)
45
-
46
- - if customer.stripe_subscription.start.present?
47
- %tr
48
- %th Started
49
- %td= Time.zone.at(customer.stripe_subscription.start).strftime('%F')
50
-
51
- - if customer.stripe_subscription.ended_at.present?
52
- %tr
53
- %th Ended
54
- %td= Time.zone.at(customer.stripe_subscription.ended_at).strftime('%F')
55
-
56
- - if customer.stripe_subscription.canceled_at.present?
57
- %tr
58
- %th Cancelled
59
- %td= Time.zone.at(customer.stripe_subscription.canceled_at).strftime('%F')
60
-
61
- - if customer.stripe_subscription.current_period_start.present?
62
- %tr
63
- %th Current Period Start
64
- %td= Time.zone.at(customer.stripe_subscription.current_period_start).strftime('%F')
65
-
66
- - if customer.stripe_subscription.current_period_end.present?
67
- %tr
68
- %th Current Period End
69
- %td= Time.zone.at(customer.stripe_subscription.current_period_end).strftime('%F')
70
-
71
- - if customer.stripe_subscription.metadata.present? && false
72
- %tr
73
- %th Metadata
74
- %td= tableize_hash(customer.stripe_subscription.metadata.to_h, th: false)
75
-
76
- - if customer.stripe_subscription.items.present?
77
- %tr
78
- %th Plans
79
- %td= tableize_hash(customer.stripe_subscription.items.inject({}) { |h, item| h[item.plan.nickname] = item.quantity; h }, th: false)
80
-
81
- - if customer.subscriptions.present?
82
- %table.table
83
- %thead
84
- %tr
85
- %th Subscribed
86
- %th Plan
87
- %th
88
- %tbody
89
- - customer.subscriptions.each do |sub|
2
+ .card.my-4
3
+ .card-header Subscription
4
+ .card-body
5
+ %table.table
6
+ %tbody
7
+ %tr
8
+ %th Status
9
+ %td= customer.stripe_subscription.status.presence || 'unknown'
10
+
90
11
  %tr
91
- %td= sub.subscribable
92
- %td= sub
93
- %td= link_to 'change', edit_polymorphic_path(sub.subscribable)
12
+ %th Email
13
+ %td= customer.stripe_customer.email
94
14
 
95
- - if customer.stripe_subscription.blank?
96
- %h3.effective-heading Subscription
97
- %p No current subscriptions
15
+ %tr
16
+ %th Card
17
+ %td
18
+ - if customer.stripe_customer.default_source.present?
19
+ - card = customer.stripe_customer.sources.retrieve(customer.stripe_customer.default_source)
20
+ = "**** **** **** #{card.last4} #{card.brand} #{card.exp_month}/#{card.exp_year}"
21
+ - else
22
+ None
23
+
24
+ %tr
25
+ %th Currency
26
+ %td= customer.stripe_customer.currency.to_s.upcase
27
+
28
+ - if customer.stripe_subscription.discount.present?
29
+ %tr
30
+ %th Coupon
31
+ %td= stripe_coupon_description(customer.stripe_subscription.discount.coupon)
32
+
33
+ - if customer.stripe_subscription.start.present?
34
+ %tr
35
+ %th Started
36
+ %td= Time.zone.at(customer.stripe_subscription.start).strftime('%F')
37
+
38
+ - if customer.stripe_subscription.ended_at.present?
39
+ %tr
40
+ %th Ended
41
+ %td= Time.zone.at(customer.stripe_subscription.ended_at).strftime('%F')
42
+
43
+ - if customer.stripe_subscription.canceled_at.present?
44
+ %tr
45
+ %th Cancelled
46
+ %td= Time.zone.at(customer.stripe_subscription.canceled_at).strftime('%F')
47
+
48
+ - if customer.stripe_subscription.current_period_start.present?
49
+ %tr
50
+ %th Current Period Start
51
+ %td= Time.zone.at(customer.stripe_subscription.current_period_start).strftime('%F')
52
+
53
+ - if customer.stripe_subscription.current_period_end.present?
54
+ %tr
55
+ %th Current Period End
56
+ %td= Time.zone.at(customer.stripe_subscription.current_period_end).strftime('%F')
57
+
58
+ - if customer.stripe_subscription.metadata.present? && false
59
+ %tr
60
+ %th Metadata
61
+ %td= tableize_hash(customer.stripe_subscription.metadata.to_h, th: false)
62
+
63
+ - if customer.stripe_subscription.items.present?
64
+ %tr
65
+ %th Plans
66
+ %td= tableize_hash(customer.stripe_subscription.items.inject({}) { |h, item| h[item.plan.nickname] = item.quantity; h }, th: false)
67
+
68
+ - if customer.subscriptions.present?
69
+ .card.my-4
70
+ .card-header Subscribed
71
+ .card-body
72
+ %table.table
73
+ %thead
74
+ %tr
75
+ %th Name
76
+ %th Plan
77
+ %th
78
+ %tbody
79
+ - customer.subscriptions.each do |sub|
80
+ %tr
81
+ %td= sub.subscribable
82
+ %td= sub
98
83
 
99
84
  - if customer.stripe_customer.invoices.present?
100
- %h3.effective-heading Invoices
101
-
102
- %table.table
103
- %thead
104
- %tr
105
- %th Date
106
- %th Number
107
- %th Period
108
- %th Items
109
- %th Total
110
- %tbody
111
- - customer.stripe_customer.invoices.each do |invoice|
112
- %tr
113
- %td= Time.zone.at(invoice.date).strftime('%F')
114
- %td= invoice.id
115
- %td
116
- = Time.zone.at(invoice.lines.first.period.start).strftime('%F')
117
- to
118
- = Time.zone.at(invoice.lines.first.period.end).strftime('%F')
119
- %td
120
- - invoice.lines.each do |line|
121
- %p= line.description
122
-
123
- %td= price_to_currency(invoice.total)
85
+ .card.my-4
86
+ .card-header Invoices
87
+ .card-body
88
+ %table.table
89
+ %thead
90
+ %tr
91
+ %th Date
92
+ %th Invoice
93
+ %th Total
94
+ %tbody
95
+ - customer.stripe_customer.invoices.each do |invoice|
96
+ %tr
97
+ %td= Time.zone.at(invoice.date).strftime('%F')
98
+ %td
99
+ %p
100
+ = invoice.id
101
+ %br
102
+ = Time.zone.at(invoice.lines.first.period.start).strftime('%F')
103
+ to
104
+ = Time.zone.at(invoice.lines.first.period.end).strftime('%F')
105
+
106
+ %p
107
+ - invoice.lines.each do |line|
108
+ = line.description
109
+ %br
110
+
111
+ %td= price_to_currency(invoice.total)
124
112
 
125
113
  - if customer.upcoming_invoice.present?
126
- %p Upcoming Invoice:
127
-
128
- %table.table
129
- %tbody
130
- %tr
131
- %th Date
132
- %td= Time.zone.at(customer.upcoming_invoice.date).strftime('%F')
133
- %tr
134
- %th Items
135
- %td
136
- %table.table
137
- %tbody
138
- - customer.upcoming_invoice.lines.each do |line|
139
- %tr
140
- %td #{Time.zone.at(line.period.start).strftime('%F')} to #{Time.zone.at(line.period.end).strftime('%F')}
141
- %td= line.description
142
- %td= price_to_currency(line.amount)
143
- %tr
144
- %th Total
145
- %td= price_to_currency(customer.upcoming_invoice.total)
114
+ .card.my-4
115
+ .card-header Upcoming Invoice
116
+ .card-body
117
+ %table.table
118
+ %tbody
119
+ %tr
120
+ %th Date
121
+ %td= Time.zone.at(customer.upcoming_invoice.date).strftime('%F')
122
+ %tr
123
+ %th Items
124
+ %td
125
+ %table.table
126
+ %tbody
127
+ - customer.upcoming_invoice.lines.each do |line|
128
+ %tr
129
+ %td #{Time.zone.at(line.period.start).strftime('%F')} to #{Time.zone.at(line.period.end).strftime('%F')}
130
+ %td= line.description
131
+ %td= price_to_currency(line.amount)
132
+ %tr
133
+ %th Total
134
+ %td= price_to_currency(customer.upcoming_invoice.total)
@@ -1,12 +1,21 @@
1
1
  = javascript_include_tag 'https://checkout.stripe.com/checkout.js'
2
2
 
3
- = effective_form_with(model: subscripter, url: effective_orders.customer_settings_path, method: :put) do |f|
4
- = f.hidden_field :stripe_token, value: nil
3
+ .card
4
+ .card-header Customer Summary
5
+ .card-body
6
+ = effective_form_with(model: subscripter, url: effective_orders.customer_settings_path, remote: true, data: { stripe: subscripter_stripe_data(subscripter) }) do |f|
7
+ = f.hidden_field :stripe_token, value: nil
8
+ = f.error :stripe_token
5
9
 
6
- = render(f.object.customer) do
7
- %h3.effective-heading Card
8
- = effective_customer_fields(f)
10
+ %p
11
+ All subscription and billing notifications are sent to:
12
+ %strong= f.object.user.email
9
13
 
10
- = f.submit
14
+ - if f.object.customer.active_card.present?
15
+ %p
16
+ All charges are made to
17
+ %strong= f.object.customer.active_card
11
18
 
19
+ %p= f.object.customer.payment_status
12
20
 
21
+ = f.submit 'Update Card', border: false, left: true, class: 'effective-orders-stripe-update-card'
@@ -1,3 +1,4 @@
1
1
  %h1.effective-heading= @page_title
2
2
 
3
3
  = render 'effective/customers/form', subscripter: @subscripter
4
+ = render 'effective/customers/customer', customer: @customer
@@ -0,0 +1,5 @@
1
+ <% resource = (@_effective_resource || Effective::Resource.new(controller_path)) %>
2
+ <% @resource = instance_variable_get('@' + resource.name) if resource.name %>
3
+
4
+ EffectiveForm.remote_form_payload = $("<div><%= j render_resource_form(resource, subscripter: @subscripter) %></div>");
5
+ EffectiveForm.remote_form_flash = <%= raw flash.to_json %>;
@@ -0,0 +1,11 @@
1
+ = javascript_include_tag 'https://checkout.stripe.com/checkout.js'
2
+
3
+ = effective_form_with(model: subscripter, url: effective_orders.subscripter_path, remote: true, data: { stripe: subscripter_stripe_data(subscripter) }) do |f|
4
+ = f.hidden_field :user_id, value: current_user.id
5
+ = f.hidden_field :subscribable_global_id
6
+ = f.hidden_field :stripe_token, value: nil
7
+ = f.error :stripe_token
8
+
9
+ = f.radios :stripe_plan_id, stripe_plans_collection(f), cards: true, label: false, required: true
10
+
11
+ = f.submit 'Choose this Plan', center: true, class: ('effective-orders-stripe-token-required' if f.object.token_required?)
@@ -0,0 +1,3 @@
1
+ .effective-radios.card-deck
2
+ .card.active
3
+ = render 'effective/subscriptions/plan', plan: subscription.plan, subscribed: true
data/config/routes.rb CHANGED
@@ -25,8 +25,10 @@ EffectiveOrders::Engine.routes.draw do
25
25
  post 'orders/:id', to: 'orders#update'
26
26
 
27
27
  if EffectiveOrders.subscriptions?
28
+ match 'subscribe', to: 'subscripter#update', via: :post, as: :subscripter
29
+
28
30
  match 'customer/settings', to: 'customers#edit', as: :customer_settings, via: [:get]
29
- match 'customer/settings', to: 'customers#update', via: [:patch, :put]
31
+ match 'customer/settings', to: 'customers#update', via: [:patch, :put, :post]
30
32
  match 'webhooks/stripe', to: 'webhooks#stripe', via: [:post, :put]
31
33
  end
32
34
 
@@ -75,6 +75,7 @@ class CreateEffectiveOrders < ActiveRecord::Migration[4.2]
75
75
  t.string :active_card
76
76
 
77
77
  t.string :stripe_subscription_id
78
+ t.string :stripe_subscription_interval
78
79
  t.string :status
79
80
 
80
81
  t.integer :subscriptions_count, :default => 0
@@ -13,8 +13,9 @@ module EffectiveOrders
13
13
  # Subscription statuses (as per stripe)
14
14
  ACTIVE = 'active'.freeze
15
15
  PAST_DUE = 'past_due'.freeze
16
+ CANCELED = 'canceled'.freeze
16
17
 
17
- STATUSES = { ACTIVE => ACTIVE, PAST_DUE => PAST_DUE }
18
+ STATUSES = { ACTIVE => ACTIVE, PAST_DUE => PAST_DUE, CANCELED => CANCELED }
18
19
 
19
20
  # The following are all valid config keys
20
21
  mattr_accessor :orders_table_name
@@ -83,7 +84,7 @@ module EffectiveOrders
83
84
  end
84
85
 
85
86
  def self.authorize!(controller, action, resource)
86
- raise Effective::AccessDenied unless authorized?(controller, action, resource)
87
+ raise Effective::AccessDenied.new('Access Denied', action, resource) unless authorized?(controller, action, resource)
87
88
  end
88
89
 
89
90
  def self.permitted_params
@@ -175,35 +176,18 @@ module EffectiveOrders
175
176
  #{ }"tiers":null,"tiers_mode":null,"transform_usage":null,"trial_period_days":null,"usage_type":"licensed"},
176
177
 
177
178
  plans = Stripe::Plan.all.inject({}) do |h, plan|
178
- occurrence = case plan.interval
179
- when 'daily' ; '/day'
180
- when 'weekly' ; '/week'
181
- when 'monthly' ; '/month'
182
- when 'yearly' ; '/year'
183
- when 'day' ; plan.interval_count == 1 ? '/day' : " every #{plan.interval_count} days"
184
- when 'week' ; plan.interval_count == 1 ? '/week' : " every #{plan.interval_count} weeks"
185
- when 'month' ; plan.interval_count == 1 ? '/month' : " every #{plan.interval_count} months"
186
- when 'year' ; plan.interval_count == 1 ? '/year' : " every #{plan.interval_count} years"
187
- else ; plan.interval
188
- end
189
-
190
179
  h[plan.id] = {
191
180
  id: plan.id,
192
181
  product_id: plan.product,
193
182
  name: plan.nickname,
194
183
  amount: plan.amount,
195
184
  currency: plan.currency,
196
- description: "$#{'%0.2f' % (plan.amount / 100.0)} #{plan.currency.upcase}#{occurrence}",
197
- occurrence: "#{occurrence}",
185
+ description: "$#{'%0.2f' % (plan.amount / 100.0)} #{plan.currency.upcase}/#{plan.interval}",
198
186
  interval: plan.interval,
199
187
  interval_count: plan.interval_count
200
188
  }; h
201
189
  end
202
190
 
203
- if trial?
204
- plans['trial'] = { id: 'trial', amount: 0, name: trial.fetch(:name), description: trial.fetch(:description) }
205
- end
206
-
207
191
  plans
208
192
  )
209
193
  end
@@ -1,3 +1,3 @@
1
1
  module EffectiveOrders
2
- VERSION = '4.0.0beta5'.freeze
2
+ VERSION = '4.0.0beta6'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_orders
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0beta5
4
+ version: 4.0.0beta6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-19 00:00:00.000000000 Z
11
+ date: 2018-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -140,6 +140,7 @@ files:
140
140
  - app/controllers/effective/providers/pretend.rb
141
141
  - app/controllers/effective/providers/refund.rb
142
142
  - app/controllers/effective/providers/stripe.rb
143
+ - app/controllers/effective/subscripter_controller.rb
143
144
  - app/controllers/effective/webhooks_controller.rb
144
145
  - app/datatables/effective_customers_datatable.rb
145
146
  - app/datatables/effective_order_items_datatable.rb
@@ -183,9 +184,9 @@ files:
183
184
  - app/views/effective/carts/_cart_actions.html.haml
184
185
  - app/views/effective/carts/show.html.haml
185
186
  - app/views/effective/customers/_customer.html.haml
186
- - app/views/effective/customers/_fields.html.haml
187
187
  - app/views/effective/customers/_form.html.haml
188
188
  - app/views/effective/customers/edit.html.haml
189
+ - app/views/effective/customers/update.js.erb
189
190
  - app/views/effective/orders/_checkout_actions.html.haml
190
191
  - app/views/effective/orders/_checkout_step1.html.haml
191
192
  - app/views/effective/orders/_checkout_step2.html.haml
@@ -226,8 +227,9 @@ files:
226
227
  - app/views/effective/orders_mailer/subscription_payment_succeeded.html.haml
227
228
  - app/views/effective/orders_mailer/subscription_trial_expired.html.haml
228
229
  - app/views/effective/orders_mailer/subscription_trial_expiring.html.haml
229
- - app/views/effective/subscriptions/_fields.html.haml
230
+ - app/views/effective/subscripter/_form.html.haml
230
231
  - app/views/effective/subscriptions/_plan.html.haml
232
+ - app/views/effective/subscriptions/_subscription.html.haml
231
233
  - app/views/layouts/effective_orders_mailer_layout.html.haml
232
234
  - config/effective_orders.rb
233
235
  - config/routes.rb
@@ -1,9 +0,0 @@
1
- .effective-orders-customer{ data: { stripe: stripe.to_json, submit: submit.to_json } }
2
- .card
3
- .card-header Credit Card
4
- .card-body
5
- = f.static_field :stripe_token, label: false, class: 'payment-status', value: f.object.customer.payment_status
6
-
7
- %p= link_to 'Update Card Details', '#', class: 'btn btn-primary btn-change-card'
8
-
9
- %p.invalid-feedback
@@ -1,12 +0,0 @@
1
- = javascript_include_tag 'https://checkout.stripe.com/checkout.js'
2
-
3
- = form.fields_for :subscripter, form.object.subscripter do |fs|
4
- = fs.hidden_field :stripe_token, value: nil
5
-
6
- - fs.object.stripe_plan_id ||= (fs.object.current_plan || {})[:id]
7
-
8
- = fs.radios :stripe_plan_id, stripe_plans_collection(fs, include_trial: include_trial),
9
- label: label,
10
- required: required,
11
- cards: true,
12
- wrapper: { class: 'effective-orders-stripe-plans', data: { stripe: stripe } }