effective_orders 4.1.5 → 4.2.0

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
  SHA256:
3
- metadata.gz: 1cbc4c38cb22371fa03bfa9319d76cbf3e45ac1a3c75edfedb6486d36bd91d7b
4
- data.tar.gz: ec41a7da268206d32b25cb8cbf4cf6cd3de2c552159cc9f823e730c02a6e06b0
3
+ metadata.gz: cba395b26b2db05cfcbfd3340db1c83318f97a190130b7f009363314a45b2a51
4
+ data.tar.gz: 5e9e3a2de5aee44d4fbde7374dee306ad9acffa30513f97e073050d04acb2955
5
5
  SHA512:
6
- metadata.gz: 6f983b6121c2842fbe5ac6a05d105d088d085f05ee42e2fbafd92e8dc99850e511b2696d8a962df8a73604dbb2a830c7343c606f94859471c3fce88aa3ed70ed
7
- data.tar.gz: e155ef077626ed3f479f7a11fbc6c1f83475e01352e54d8b0e3aef781675e07013799092c8ae3a16f63a8863dbbc3a95d84d10750d3c8386b23d6fac151ef204
6
+ metadata.gz: 0c4bbcc96e0ba2ace04bb7779b4c56aaa2578fb3b7c05ecfb2979b94c4fd8a12581fc3d9a77de1f267cf3ff1e00104f122b49dc29354ea7b95e5c91c2b2c5f1e
7
+ data.tar.gz: b48693aa3680d77555a459366c7379ba96b6b2894c40dbe01bd1a630440843a414d393a2cc84946130c1a59ae5290d5576f15d0cd16145ad2df31ee22e01f7a7
@@ -20,7 +20,9 @@ $(document).on 'change keyup', '.effective-orders-subscripter-plan-quantity', (e
20
20
  return unless $plan.length == 1
21
21
 
22
22
  # Assign the quantity to each quantity field
23
- $plan.closest('form').find(".effective-orders-stripe-plan:not([data-plan-id='#{$plan.data('id')}'])").find("input[name$='[quantity]']").val($obj.val())
23
+ $plan.closest('form')
24
+ .find(".effective-orders-stripe-plan:not([data-plan-id='#{$plan.data('id')}'])")
25
+ .find("input[name$='[quantity]']").val($obj.val())
24
26
 
25
27
  quantity = $obj.val() || 0
26
28
 
@@ -28,11 +30,9 @@ $(document).on 'change keyup', '.effective-orders-subscripter-plan-quantity', (e
28
30
  # Assign all totals
29
31
  plan = $(this)
30
32
  amount = parseInt(plan.data('amount'))
31
- interval = plan.data('plan-interval')
33
+ interval = plan.data('interval')
32
34
 
33
35
  total = (quantity * amount)
34
- total = (total / 12) if interval == 'year'
35
-
36
36
  total = '$' + (total / 100.0).toFixed(2)
37
37
 
38
38
  plan.find('#effective_subscripter_total_amount').text(total)
@@ -53,6 +53,9 @@ $(document).on 'click', ".effective-orders-stripe-token-required[type='submit'],
53
53
  stripe = $form.data('stripe')
54
54
  return unless stripe?
55
55
 
56
+ plans = $form.data('plans')
57
+ return unless plans?
58
+
56
59
  # If we're doing choose button mode
57
60
  if $obj.data('choose-stripe-plan-id')
58
61
  $form.find("input[name$='[stripe_plan_id]']").val($obj.data('choose-stripe-plan-id'))
@@ -63,7 +66,7 @@ $(document).on 'click', ".effective-orders-stripe-token-required[type='submit'],
63
66
  return unless selected_plan_id.length > 0
64
67
 
65
68
  # Match plan
66
- plan = stripe.plans.find (plan, _) => plan.id == selected_plan_id
69
+ plan = plans.find (plan, _) => plan.id == selected_plan_id
67
70
  return unless plan?
68
71
 
69
72
  # Okay, we're good to call stripe
@@ -4,7 +4,7 @@ module EffectiveStripeHelper
4
4
  plan = (
5
5
  case obj
6
6
  when Hash ; obj
7
- when ::Stripe::Plan ; EffectiveOrders.stripe_plans.find { |plan| plan.id == obj.id }
7
+ when ::Stripe::Plan ; EffectiveOrders.stripe_plans.find { |plan| plan[:id] == obj.id }
8
8
  else ; raise 'unexpected object'
9
9
  end
10
10
  )
@@ -1,10 +1,16 @@
1
1
  module EffectiveSubscriptionsHelper
2
2
 
3
- def stripe_plans_collection(subscripter = nil)
4
- EffectiveOrders.stripe_plans.values.sort do |x, y|
5
- amount = (x[:amount] <=> y[:amount])
6
- (amount != 0) ? amount : x[:name] <=> y[:name]
7
- end
3
+ def subscripter_stripe_data(subscripter)
4
+ {
5
+ email: current_user.email,
6
+ image: stripe_site_image_url,
7
+ key: EffectiveOrders.stripe[:publishable_key],
8
+ name: EffectiveOrders.stripe[:site_title],
9
+ }
10
+ end
11
+
12
+ def subscripter_stripe_plans(subscripter)
13
+ EffectiveOrders.stripe_plans
8
14
  end
9
15
 
10
16
  def subscribable_form_with(subscribable)
@@ -25,14 +31,6 @@ module EffectiveSubscriptionsHelper
25
31
  render('effective/customers/form', subscripter: subscripter)
26
32
  end
27
33
 
28
- def subscripter_stripe_data(subscripter)
29
- {
30
- email: current_user.email,
31
- image: stripe_site_image_url,
32
- key: EffectiveOrders.stripe[:publishable_key],
33
- name: EffectiveOrders.stripe[:site_title],
34
- plans: EffectiveOrders.stripe_plans.values
35
- }
36
- end
34
+
37
35
 
38
36
  end
@@ -11,7 +11,11 @@ module Effective
11
11
  validates :subscribable, presence: true, if: -> { stripe_plan_id.present? }
12
12
  validates :customer, presence: true
13
13
 
14
- validates :stripe_plan_id, inclusion: { allow_blank: true, in: EffectiveOrders.stripe_plans.keys, message: 'unknown plan' }
14
+ validates :stripe_plan_id, inclusion: {
15
+ allow_blank: true,
16
+ in: EffectiveOrders.stripe_plans.map { |plan| plan[:id] },
17
+ message: 'unknown plan'
18
+ }
15
19
 
16
20
  validate(if: -> { stripe_plan_id && plan && plan[:amount] > 0 }) do
17
21
  self.errors.add(:stripe_token, 'updated payment card required') if stripe_token.blank? && token_required?
@@ -43,7 +47,7 @@ module Effective
43
47
  end
44
48
 
45
49
  def plan
46
- EffectiveOrders.stripe_plans[stripe_plan_id]
50
+ EffectiveOrders.stripe_plans.find { |plan| plan[:id] == stripe_plan_id }
47
51
  end
48
52
 
49
53
  def quantity=(value)
@@ -45,7 +45,9 @@ module Effective
45
45
  validates :customer, presence: true
46
46
  validates :subscribable, presence: true
47
47
 
48
- validates :stripe_plan_id, presence: true, inclusion: { in: EffectiveOrders.stripe_plans.keys }
48
+ validates :stripe_plan_id, presence: true
49
+ validates :stripe_plan_id, inclusion: { in: EffectiveOrders.stripe_plans.map { |plan| plan[:id] } }
50
+
49
51
  validates :stripe_subscription_id, presence: true
50
52
 
51
53
  validates :name, presence: true
@@ -59,7 +61,7 @@ module Effective
59
61
  end
60
62
 
61
63
  def plan
62
- EffectiveOrders.stripe_plans[stripe_plan_id]
64
+ EffectiveOrders.stripe_plans.find { |plan| plan[:id] == stripe_plan_id }
63
65
  end
64
66
 
65
67
  def stripe_subscription
@@ -6,14 +6,12 @@
6
6
  %thead
7
7
  %tr
8
8
  %th Subscribed
9
- %th Plan
10
9
  %th Quantity
11
10
  %th Interval
12
11
  %tbody
13
12
  - customer.subscriptions.each do |sub|
14
13
  %tr
15
14
  %td= sub.subscribable
16
- %td= sub
17
15
  %td= sub.quantity
18
16
  %td= sub.interval
19
17
 
@@ -1,23 +1,23 @@
1
1
  = javascript_include_tag 'https://checkout.stripe.com/checkout.js'
2
2
 
3
- = effective_form_with(model: subscripter, url: effective_orders.subscripter_path, remote: true, data: { stripe: subscripter_stripe_data(subscripter) }) do |f|
3
+ - stripe = subscripter_stripe_data(subscripter)
4
+ - plans = subscripter_stripe_plans(subscripter)
5
+
6
+ - subscripter.quantity ||= subscripter.subscribable.subscribable_quantity_used
7
+ - subscripter.stripe_plan_id ||= Hash(plans.first)[:id]
8
+
9
+ = effective_form_with(model: subscripter, url: effective_orders.subscripter_path, remote: true, data: { stripe: stripe, plans: plans }) do |f|
4
10
  = f.hidden_field :subscribable_global_id
5
11
  = f.hidden_field :stripe_token, value: nil
6
- = f.error :stripe_token
7
-
8
12
  = f.hidden_field :stripe_plan_id
9
-
10
- - stripe_plans = stripe_plans_collection(f.object)
11
- - stripe_plans = stripe_plans.select { |plan| plan[:name].include?('per User') }
12
-
13
- - f.object.stripe_plan_id ||= (stripe_plans.first || {})[:id]
13
+ = f.error :stripe_token
14
14
 
15
15
  - if f.object.subscribable.subscribed?
16
16
  - quantity_used = f.object.subscribable.subscribable_quantity_used.to_i
17
17
  - quantity_purchased = f.object.subscribable.subscription.quantity
18
18
 
19
19
  .text-center
20
- %p
20
+ %p
21
21
  You currently have <strong>#{pluralize(quantity_used, 'member')}</strong> in your team
22
22
  and have space for <strong>#{pluralize(quantity_purchased, 'member')}</strong>.
23
23
 
@@ -26,39 +26,28 @@
26
26
  - else
27
27
  %p To add more members you will need to update your plan.
28
28
 
29
- %p To pay for less than #{pluralize(quantity_used, 'member')} you'll have to remove some first.
29
+ %p To pay for less than #{pluralize(quantity_used, 'member')}, remove some team members first.
30
30
 
31
- .card.mb-4
32
- .card-body.text-center
33
- %h5.card-title Billing Cycle
31
+ - else
32
+ .text-center
33
+ %p
34
+ You are not currently subscribed to any plan.
35
+ %br
36
+ For full access, upgrade to a paid plan below.
37
+ %br
38
+ To upgrade with fewer people, remove some team members first.
34
39
 
35
- = f.radios :stripe_plan_id, stripe_plans.map { |plan| [plan[:name], plan[:id]] }, label: false, buttons: true
40
+ .card.mb-4
41
+ .card-body.card-subscripter
42
+ %h5.card-title.subscripter-title Billing Cycle
36
43
 
37
- %hr
44
+ = f.radios :stripe_plan_id, plans.map { |plan| [plan[:name], plan[:id]] }, label: false, buttons: true
38
45
 
39
- - stripe_plans.select { |plan| plan[:interval] == 'month' }.each do |plan|
40
- = f.show_if(:stripe_plan_id, plan[:id]) do
41
- .effective-orders-stripe-plan{'data-id': plan[:id], 'data-amount': plan[:amount], 'data-interval': plan[:interval]}
42
- .d-flex.justify-content-around.align-items-center
43
- = f.number_field :quantity, class: 'effective-orders-subscripter-plan-quantity form-control-lg', autocomplete: 'off', required: true
44
- %div= 'x'
45
- = f.static_field :price_per_person do
46
- = price_to_currency(plan[:amount])
47
- %div= '='
48
- = f.static_field :total_amount do
49
- = price_to_currency(plan[:amount] * f.object.quantity.to_i)
46
+ %hr.mt-4.mb-4
50
47
 
51
- - stripe_plans.select { |plan| plan[:interval] == 'year' }.each do |plan|
48
+ - plans.each do |plan|
52
49
  = f.show_if(:stripe_plan_id, plan[:id]) do
53
- .effective-orders-stripe-plan{'data-id': plan[:id], 'data-amount': plan[:amount], 'data-interval': plan[:interval]}
54
- .d-flex.justify-content-around.align-items-center
55
- = f.number_field :quantity, class: 'effective-orders-subscripter-plan-quantity form-control-lg', autocomplete: 'off', required: true
56
- %div= 'x'
57
- = f.static_field :price_per_person do
58
- = price_to_currency(plan[:amount] / 12)
59
- %div= '='
60
- = f.static_field :total_amount do
61
- = price_to_currency(plan[:amount] * f.object.quantity.to_i)
50
+ = render 'effective/subscripter/plan', plan: plan, f: f
62
51
 
63
52
  = f.submit(border: false, center: true) do
64
- = f.save('Update Plan', class: ('effective-orders-stripe-token-required' if f.object.token_required?))
53
+ = f.save('Continue to Billing', class: ('effective-orders-stripe-token-required' if f.object.token_required?))
@@ -0,0 +1,23 @@
1
+ .effective-orders-stripe-plan{data: plan}
2
+ .d-flex.justify-content-around.align-top
3
+ = f.integer_field :quantity, autocomplete: 'off', required: true, label: 'Total People', maxlength: 3,
4
+ class: 'effective-orders-subscripter-plan-quantity form-control-lg'
5
+
6
+ .subscripter-math-symbol= 'x'
7
+
8
+ = f.static_field :price_per_person, label: 'Price Per Person' do
9
+ = price_to_currency(plan[:amount])
10
+
11
+ - if plan[:savings]
12
+ .subscripter-savings.text-danger
13
+ Save #{price_to_currency(plan[:savings])}/person
14
+
15
+ .subscripter-math-symbol= '='
16
+
17
+ = f.static_field :total_amount, label: 'Total Amount' do
18
+ = price_to_currency(plan[:amount] * f.object.quantity.to_i)
19
+
20
+ - if plan[:savings]
21
+ .subscripter-total-savings.text-danger
22
+ Save
23
+ %span #{price_to_currency(f.object.quantity.to_i * plan[:savings])}
@@ -166,7 +166,7 @@ module EffectiveOrders
166
166
  end
167
167
 
168
168
  def self.stripe_plans
169
- return {} unless (stripe? && subscriptions?)
169
+ return [] unless (stripe? && subscriptions?)
170
170
 
171
171
  @stripe_plans ||= (
172
172
  Rails.logger.info '[STRIPE] index plans'
@@ -177,24 +177,53 @@ module EffectiveOrders
177
177
  raise e if Rails.env.production?
178
178
  Rails.logger.info "[STRIPE ERROR]: #{e.message}"
179
179
  Rails.logger.info "[STRIPE ERROR]: effective_orders continuing with empty stripe plans. This would fail loudly in Rails.env.production."
180
- {}
180
+ []
181
181
  end
182
182
 
183
- plans.inject({}) do |h, plan|
184
- h[plan.id] = {
183
+ plans = plans.map do |plan|
184
+ {
185
185
  id: plan.id,
186
186
  product_id: plan.product,
187
187
  name: plan.nickname,
188
188
  amount: plan.amount,
189
189
  currency: plan.currency,
190
- description: "$#{'%0.2f' % (plan.amount / 100.0)} #{plan.currency.upcase}/#{plan.interval}",
190
+ description: ("$#{'%0.2f' % (plan.amount / 100.0)}" + ' ' + plan.currency.upcase + '/' + plan.interval.to_s),
191
191
  interval: plan.interval,
192
192
  interval_count: plan.interval_count
193
- }; h
193
+ }
194
+ end.sort do |x, y|
195
+ val ||= (x[:interval] <=> y[:interval])
196
+ val = nil if val == 0
197
+
198
+ val ||= (x[:amount] <=> y[:amount])
199
+ val = nil if val == 0
200
+
201
+ val ||= (x[:name] <=> y[:name])
202
+ val = nil if val == 0
203
+
204
+ val || (x[:id] <=> y[:id])
205
+ end
206
+
207
+ # Calculate savings for any yearly per user plans, based on their matching monthly plans
208
+ plans.select { |plan| plan[:interval] == 'year' && plan[:name].downcase.include?('per') }.each do |yearly|
209
+ monthly_name = yearly[:name].downcase.gsub('year', 'month')
210
+ monthly = plans.find { |plan| plan[:interval] == 'month' && plan[:name].downcase == monthly_name }
211
+ next unless monthly
212
+
213
+ savings = (monthly[:amount].to_i * 12) - yearly[:amount].to_i
214
+ next unless savings > 0
215
+
216
+ yearly[:savings] = savings
194
217
  end
218
+
219
+ plans
195
220
  )
196
221
  end
197
222
 
223
+ def self.stripe_plans_collection
224
+ stripe_plans.map { |plan| [plan[:name], plan[:id]] }
225
+ end
226
+
198
227
  class SoldOutException < Exception; end
199
228
  class AlreadyPurchasedException < Exception; end
200
229
  end
@@ -1,3 +1,3 @@
1
1
  module EffectiveOrders
2
- VERSION = '4.1.5'.freeze
2
+ VERSION = '4.2.0'.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.1.5
4
+ version: 4.2.0
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: 2019-08-15 00:00:00.000000000 Z
11
+ date: 2019-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -231,6 +231,7 @@ files:
231
231
  - app/views/effective/orders_mailer/subscription_trialing.html.haml
232
232
  - app/views/effective/orders_mailer/subscription_updated.html.haml
233
233
  - app/views/effective/subscripter/_form.html.haml
234
+ - app/views/effective/subscripter/_plan.html.haml
234
235
  - app/views/layouts/effective_orders_mailer_layout.html.haml
235
236
  - config/effective_orders.rb
236
237
  - config/routes.rb