spree_stripe_subscriptions 0.0.1
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 +7 -0
- data/.gitignore +91 -0
- data/.rubocop.yml +26 -0
- data/.travis.yml +37 -0
- data/Gemfile +12 -0
- data/LICENSE +26 -0
- data/README.md +72 -0
- data/Rakefile +21 -0
- data/app/controllers/spree/admin/stripe_configurations_controller.rb +6 -0
- data/app/controllers/spree/admin/stripe_customers_controller.rb +6 -0
- data/app/controllers/spree/admin/stripe_plans_controller.rb +36 -0
- data/app/controllers/spree/admin/stripe_subscription_events_controller.rb +6 -0
- data/app/controllers/spree/admin/stripe_subscriptions_controller.rb +6 -0
- data/app/controllers/spree/stripe_plans_controller.rb +20 -0
- data/app/controllers/spree/stripe_subscriptions_controller.rb +166 -0
- data/app/controllers/spree/stripe_webhooks_controller.rb +56 -0
- data/app/models/spree/stripe_configuration.rb +28 -0
- data/app/models/spree/stripe_customer.rb +30 -0
- data/app/models/spree/stripe_invoice.rb +21 -0
- data/app/models/spree/stripe_plan.rb +104 -0
- data/app/models/spree/stripe_subscription.rb +167 -0
- data/app/models/spree/stripe_subscription_event.rb +10 -0
- data/app/models/spree_stripe_subscriptions/configuration.rb +15 -0
- data/app/models/spree_stripe_subscriptions/user_decorator.rb +50 -0
- data/app/overrides/spree/admin/shared/_main_menu.rb +13 -0
- data/app/serializers/.gitkeep +0 -0
- data/app/services/.gitkeep +0 -0
- data/app/views/spree/admin/shared/sub_menu/_stripe_subscriptions.html.erb +8 -0
- data/app/views/spree/admin/stripe_configurations/_form.html.erb +42 -0
- data/app/views/spree/admin/stripe_configurations/edit.html.erb +17 -0
- data/app/views/spree/admin/stripe_configurations/index.html.erb +44 -0
- data/app/views/spree/admin/stripe_configurations/new.html.erb +13 -0
- data/app/views/spree/admin/stripe_customers/index.html.erb +36 -0
- data/app/views/spree/admin/stripe_plans/_form.html.erb +50 -0
- data/app/views/spree/admin/stripe_plans/edit.html.erb +15 -0
- data/app/views/spree/admin/stripe_plans/index.html.erb +59 -0
- data/app/views/spree/admin/stripe_plans/new.html.erb +15 -0
- data/app/views/spree/admin/stripe_subscription_events/index.html.erb +36 -0
- data/app/views/spree/admin/stripe_subscriptions/index.html.erb +40 -0
- data/app/views/spree/stripe_plans/index.html.erb +77 -0
- data/bin/rails +8 -0
- data/config/initializers/stripe.rb +11 -0
- data/config/locales/en.yml +80 -0
- data/config/routes.rb +27 -0
- data/db/migrate/20221130094411_add_spree_stripe_configuration_model.rb +14 -0
- data/db/migrate/20221130095015_add_spree_stripe_plan_model.rb +23 -0
- data/db/migrate/20221130100526_add_spree_stripe_customer.rb +11 -0
- data/db/migrate/20221130100903_add_spree_stripe_subscription_model.rb +23 -0
- data/db/migrate/20221130102650_add_spree_stripe_subscription_events_model.rb +16 -0
- data/db/migrate/20221202111450_add_weightage_to_stripe_plan.rb +10 -0
- data/db/migrate/20221209065244_add_schedules_to_subscription.rb +6 -0
- data/db/migrate/20221209094013_add_stripe_invoices.rb +33 -0
- data/db/migrate/20221209131817_add_user_to_invoice.rb +5 -0
- data/db/migrate/20221221080141_add_extra_plan_fields.rb +8 -0
- data/lib/generators/spree_stripe_subscriptions/install/install_generator.rb +20 -0
- data/lib/spree_stripe_subscriptions/engine.rb +24 -0
- data/lib/spree_stripe_subscriptions/factories.rb +6 -0
- data/lib/spree_stripe_subscriptions/version.rb +11 -0
- data/lib/spree_stripe_subscriptions.rb +4 -0
- data/spree_stripe_subscriptions.gemspec +34 -0
- metadata +207 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
module Spree
|
2
|
+
class StripeInvoice < Spree::Base
|
3
|
+
acts_as_paranoid
|
4
|
+
|
5
|
+
STATUS_OPTIONS = {
|
6
|
+
'draft' => 'Draft',
|
7
|
+
'open' => 'Open',
|
8
|
+
'paid' => 'Paid',
|
9
|
+
'uncollectible' => 'Uncollectible',
|
10
|
+
'void' => 'Void'
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
validates :status, inclusion: { in: STATUS_OPTIONS.keys }
|
14
|
+
|
15
|
+
scope :paid, -> { where(status: 'paid') }
|
16
|
+
|
17
|
+
belongs_to :customer, class_name: 'Spree::StripeCustomer'
|
18
|
+
belongs_to :user, class_name: Spree.user_class.to_s
|
19
|
+
belongs_to :subscription, class_name: 'Spree::StripeSubscription'
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Spree
|
2
|
+
class StripePlan < Spree::Base
|
3
|
+
acts_as_paranoid
|
4
|
+
|
5
|
+
acts_as_list column: :weightage
|
6
|
+
|
7
|
+
INTERVAL = { day: 'Daily', week: 'Weekly', month: 'Monthly', year: 'Annually' }.freeze
|
8
|
+
CURRENCY = { usd: 'USD', gbp: 'GBP', jpy: 'JPY', eur: 'EUR', aud: 'AUD', hkd: 'HKD', sek: 'SEK', nok: 'NOK', dkk: 'DKK', pen: 'PEN',
|
9
|
+
cad: 'CAD' }.freeze
|
10
|
+
|
11
|
+
TAX_BEHAVIOUR_OPTIONS = {
|
12
|
+
'inclusive' => 'inclusive',
|
13
|
+
'exclusive' => 'exclusive',
|
14
|
+
'unspecified' => 'unspecified'
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
validates :tax_behavior, inclusion: { in: TAX_BEHAVIOUR_OPTIONS.keys }
|
18
|
+
validates :configuration, presence: true
|
19
|
+
|
20
|
+
belongs_to :configuration, class_name: 'Spree::StripeConfiguration'
|
21
|
+
|
22
|
+
has_many :stripe_subscriptions,
|
23
|
+
class_name: 'Spree::StripeSubscription',
|
24
|
+
foreign_key: :plan_id,
|
25
|
+
inverse_of: :plan,
|
26
|
+
dependent: :restrict_with_error
|
27
|
+
|
28
|
+
before_validation :set_stripe_plan_id, on: :create
|
29
|
+
|
30
|
+
after_create :create_plan
|
31
|
+
after_update :update_plan
|
32
|
+
after_destroy :delete_plan
|
33
|
+
|
34
|
+
after_initialize :set_api_key
|
35
|
+
|
36
|
+
scope :active, -> { where(active: true) }
|
37
|
+
|
38
|
+
def find_or_create_stripe_plan
|
39
|
+
stripe_plan = nil
|
40
|
+
return stripe_plan unless active
|
41
|
+
|
42
|
+
stripe_plan = Stripe::Plan.retrieve(stripe_plan_id)
|
43
|
+
rescue StandardError
|
44
|
+
stripe_plan = create_plan
|
45
|
+
ensure
|
46
|
+
stripe_plan
|
47
|
+
end
|
48
|
+
|
49
|
+
def update_price_tax_behavior
|
50
|
+
Stripe::Price.update(stripe_plan_id, { tax_behavior: tax_behavior })
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_plan
|
54
|
+
plan = Stripe::Plan.create(
|
55
|
+
id: stripe_plan_id,
|
56
|
+
product: {
|
57
|
+
name: name
|
58
|
+
},
|
59
|
+
currency: currency,
|
60
|
+
amount: stripe_amount(amount),
|
61
|
+
interval: interval,
|
62
|
+
interval_count: interval_count,
|
63
|
+
trial_period_days: trial_period_days
|
64
|
+
)
|
65
|
+
if plan.present?
|
66
|
+
update_price_tax_behavior
|
67
|
+
end
|
68
|
+
rescue StandardError
|
69
|
+
plan = nil
|
70
|
+
ensure
|
71
|
+
plan
|
72
|
+
end
|
73
|
+
|
74
|
+
def update_plan
|
75
|
+
update_price_tax_behavior if tax_behavior_previously_changed?
|
76
|
+
return unless name_previously_changed?
|
77
|
+
|
78
|
+
stripe_plan = find_or_create_stripe_plan
|
79
|
+
return unless stripe_plan
|
80
|
+
|
81
|
+
stripe_plan.name = name
|
82
|
+
stripe_plan.save
|
83
|
+
end
|
84
|
+
|
85
|
+
def delete_plan
|
86
|
+
stripe_plan = find_or_create_stripe_plan
|
87
|
+
return unless stripe_plan
|
88
|
+
|
89
|
+
stripe_plan.delete
|
90
|
+
end
|
91
|
+
|
92
|
+
def stripe_amount(amount)
|
93
|
+
(amount * 100).to_i
|
94
|
+
end
|
95
|
+
|
96
|
+
def set_api_key
|
97
|
+
Stripe.api_key = configuration.preferred_secret_key if configuration
|
98
|
+
end
|
99
|
+
|
100
|
+
def set_stripe_plan_id
|
101
|
+
self.stripe_plan_id = "VP-Plan-#{Time.current.to_i}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Spree
|
2
|
+
class StripeSubscription < Spree::Base
|
3
|
+
acts_as_paranoid
|
4
|
+
|
5
|
+
belongs_to :plan, class_name: 'Spree::StripePlan'
|
6
|
+
belongs_to :next_plan, class_name: 'Spree::StripePlan'
|
7
|
+
belongs_to :customer, class_name: 'Spree::StripeCustomer'
|
8
|
+
belongs_to :user, class_name: Spree.user_class.to_s
|
9
|
+
|
10
|
+
has_many :stripe_subscription_events,
|
11
|
+
class_name: 'Spree::StripeSubscriptionEvent',
|
12
|
+
foreign_key: :subscription_id,
|
13
|
+
inverse_of: :subscription,
|
14
|
+
dependent: :restrict_with_error
|
15
|
+
has_many :stripe_invoices,
|
16
|
+
class_name: 'Spree::StripeInvoice',
|
17
|
+
foreign_key: :subscription_id,
|
18
|
+
inverse_of: :subscription,
|
19
|
+
dependent: :restrict_with_error
|
20
|
+
|
21
|
+
STATUS_OPTIONS = {
|
22
|
+
'incomplete' => 'Incomplete',
|
23
|
+
'incomplete_expired' => 'Incomplete Expired',
|
24
|
+
'trialing' => 'Trialing',
|
25
|
+
'active' => 'Active',
|
26
|
+
'past_due' => 'Past Due',
|
27
|
+
'canceled' => 'Canceled',
|
28
|
+
'unpaid' => 'Unpaid'
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
validates :status, inclusion: { in: STATUS_OPTIONS.keys }
|
32
|
+
|
33
|
+
scope :active, -> { where(status: 'active') }
|
34
|
+
|
35
|
+
def self.create_or_update_subscription(event)
|
36
|
+
event_data = event.data.object
|
37
|
+
customer = Spree::StripeCustomer.find_by!(stripe_customer_id: event_data.customer)
|
38
|
+
plan = Spree::StripePlan.find_by!(stripe_plan_id: event_data.plan.id)
|
39
|
+
|
40
|
+
stripe_subscription_id = event_data.id
|
41
|
+
|
42
|
+
webhook_subscription = Spree::StripeSubscription.where(stripe_subscription_id: stripe_subscription_id).first_or_initialize
|
43
|
+
|
44
|
+
webhook_subscription.update(
|
45
|
+
customer: customer, user: customer.user, plan: plan, status: event_data.status,
|
46
|
+
current_period_start: event_data.current_period_start ? Time.at(event_data.current_period_start).utc.to_datetime : nil,
|
47
|
+
current_period_end: event_data.current_period_end ? Time.at(event_data.current_period_end).utc.to_datetime : nil,
|
48
|
+
billing_cycle_anchor: event_data.billing_cycle_anchor ? Time.at(event_data.billing_cycle_anchor).utc.to_datetime : nil,
|
49
|
+
cancel_at_period_end: event_data.cancel_at_period_end,
|
50
|
+
cancel_at: event_data.cancel_at ? Time.at(event_data.cancel_at).utc.to_datetime : nil,
|
51
|
+
canceled_at: event_data.canceled_at ? Time.at(event_data.canceled_at).utc.to_datetime : nil,
|
52
|
+
ended_at: event_data.ended_at ? Time.at(event_data.ended_at).utc.to_datetime : nil,
|
53
|
+
schedule: event_data.schedule
|
54
|
+
)
|
55
|
+
|
56
|
+
active_subscription = user.stripe_subscriptions.active.last
|
57
|
+
if active_subscription.present?
|
58
|
+
# Checking if customer upgraded to other plan
|
59
|
+
old_subscriptions = user.stripe_subscriptions.active.where.not(id: [active_subscription.id, webhook_subscription.id].uniq)
|
60
|
+
old_subscriptions.each do |old_subscription|
|
61
|
+
# Unsubscribe from old subscription
|
62
|
+
old_subscription.unsubscribe
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
webhook_subscription
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.update_subscription_schedule(event)
|
70
|
+
event_data = event.data.object
|
71
|
+
stripe_subscription_id = event_data.subscription
|
72
|
+
|
73
|
+
webhook_subscription = Spree::StripeSubscription.find_by(stripe_subscription_id: stripe_subscription_id)
|
74
|
+
if webhook_subscription.present?
|
75
|
+
if event_data.phases.count > 1
|
76
|
+
last_phase = event_data.phases.last
|
77
|
+
next_plan_id = last_phase.plans.first.plan
|
78
|
+
next_plan = Spree::StripePlan.find_by(stripe_plan_id: next_plan_id)
|
79
|
+
if next_plan.present?
|
80
|
+
webhook_subscription.update(next_plan_id: next_plan.id)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
webhook_subscription
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.create_or_update_invoice(event)
|
88
|
+
event_data = event.data.object
|
89
|
+
stripe_subscription_id = event_data.subscription
|
90
|
+
|
91
|
+
webhook_subscription = Spree::StripeSubscription.find_by(stripe_subscription_id: stripe_subscription_id)
|
92
|
+
|
93
|
+
if webhook_subscription.present?
|
94
|
+
stripe_invoice_id = event_data.id
|
95
|
+
customer = Spree::StripeCustomer.find_by(stripe_customer_id: event_data.customer)
|
96
|
+
stripe_invoice = webhook_subscription.stripe_invoices.where(stripe_invoice_id: stripe_invoice_id).first_or_initialize
|
97
|
+
|
98
|
+
period_start, period_end = if (line = event_data.lines.first)
|
99
|
+
[line.period.start, line.period.end]
|
100
|
+
end
|
101
|
+
|
102
|
+
stripe_invoice.update(
|
103
|
+
customer: customer,
|
104
|
+
user: customer.user,
|
105
|
+
status: event_data.status,
|
106
|
+
paid: event_data.paid,
|
107
|
+
currency: event_data.currency,
|
108
|
+
amount_paid: event_data.amount_paid || 0.0,
|
109
|
+
subtotal: event_data.subtotal || 0.0,
|
110
|
+
subtotal_excluding_tax: event_data.subtotal_excluding_tax || 0.0,
|
111
|
+
tax: event_data.tax || 0.0,
|
112
|
+
total: event_data.total || 0.0,
|
113
|
+
total_excluding_tax: event_data.total_excluding_tax || 0.0,
|
114
|
+
customer_name: event_data.customer_name,
|
115
|
+
billing_reason: event_data.billing_reason,
|
116
|
+
invoice_pdf: event_data.invoice_pdf,
|
117
|
+
period_start: period_start ? Time.at(period_start).utc.to_datetime : nil,
|
118
|
+
period_end: period_end ? Time.at(period_end).utc.to_datetime : nil,
|
119
|
+
raw_data: event_data
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
123
|
+
webhook_subscription
|
124
|
+
end
|
125
|
+
|
126
|
+
def stripe_subscription_schedule
|
127
|
+
stripe_schedule = nil
|
128
|
+
if schedule.present?
|
129
|
+
stripe_schedule = Stripe::SubscriptionSchedule.retrieve(schedule)
|
130
|
+
else
|
131
|
+
stripe_schedule = Stripe::SubscriptionSchedule.create({
|
132
|
+
from_subscription: stripe_subscription_id
|
133
|
+
})
|
134
|
+
end
|
135
|
+
rescue StandardError => e
|
136
|
+
Rails.logger.error e.message
|
137
|
+
ensure
|
138
|
+
stripe_schedule
|
139
|
+
end
|
140
|
+
|
141
|
+
def cancel_renewal
|
142
|
+
Stripe::Subscription.update(
|
143
|
+
stripe_subscription_id,
|
144
|
+
{ cancel_at_period_end: true }
|
145
|
+
)
|
146
|
+
rescue StandardError => e
|
147
|
+
Rails.logger.error e
|
148
|
+
end
|
149
|
+
|
150
|
+
def unsubscribe
|
151
|
+
Stripe::Subscription.delete(
|
152
|
+
stripe_subscription_id
|
153
|
+
)
|
154
|
+
rescue StandardError => e
|
155
|
+
Rails.logger.error e
|
156
|
+
end
|
157
|
+
|
158
|
+
def register_webhook_event(event)
|
159
|
+
stripe_subscription_events.create(
|
160
|
+
event_id: event.id,
|
161
|
+
event_type: event.type,
|
162
|
+
user: user,
|
163
|
+
response: event.to_json
|
164
|
+
)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SpreeStripeSubscriptions
|
2
|
+
class Configuration < Spree::Preferences::Configuration
|
3
|
+
|
4
|
+
# Some example preferences are shown below, for more information visit:
|
5
|
+
# https://dev-docs.spreecommerce.org/internals/preferences
|
6
|
+
|
7
|
+
preference :enabled, :boolean, default: true
|
8
|
+
preference :stripe_plans_path, :string, default: 'stripe_plans'
|
9
|
+
preference :stripe_webhooks_path, :string, default: 'stripe_webhooks'
|
10
|
+
# preference :dark_chocolate, :boolean, default: true
|
11
|
+
# preference :color, :string, default: 'Red'
|
12
|
+
# preference :favorite_number, :integer
|
13
|
+
# preference :supported_locales, :array, default: [:en]
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SpreeStripeSubscriptions
|
4
|
+
module UserDecorator
|
5
|
+
def self.prepended(base)
|
6
|
+
base.has_many :stripe_customers,
|
7
|
+
class_name: 'Spree::StripeCustomer',
|
8
|
+
foreign_key: :user_id,
|
9
|
+
inverse_of: :user,
|
10
|
+
dependent: :restrict_with_error
|
11
|
+
base.has_many :stripe_subscriptions,
|
12
|
+
class_name: 'Spree::StripeSubscription',
|
13
|
+
foreign_key: :user_id,
|
14
|
+
inverse_of: :user,
|
15
|
+
dependent: :restrict_with_error
|
16
|
+
base.has_many :stripe_subscription_events,
|
17
|
+
class_name: 'Spree::StripeSubscriptionEvent',
|
18
|
+
foreign_key: :user_id,
|
19
|
+
inverse_of: :user,
|
20
|
+
dependent: :restrict_with_error
|
21
|
+
base.has_many :stripe_invoices,
|
22
|
+
class_name: 'Spree::StripeInvoice',
|
23
|
+
foreign_key: :user_id,
|
24
|
+
inverse_of: :user,
|
25
|
+
dependent: :restrict_with_error
|
26
|
+
end
|
27
|
+
|
28
|
+
def probable_name
|
29
|
+
name = email[/[^@]+/]
|
30
|
+
name.split('.').map(&:capitalize).join(' ')
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_or_create_stripe_customer
|
34
|
+
current_customer = stripe_customers.last
|
35
|
+
stripe_customer = current_customer&.stripe_customer
|
36
|
+
return stripe_customer if stripe_customer
|
37
|
+
|
38
|
+
stripe_customer = Stripe::Customer.create(
|
39
|
+
email: email,
|
40
|
+
name: probable_name,
|
41
|
+
metadata: { user_id: id }
|
42
|
+
)
|
43
|
+
stripe_customers.create(stripe_customer_id: stripe_customer.id)
|
44
|
+
|
45
|
+
stripe_customer
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Spree::User.prepend SpreeStripeSubscriptions::UserDecorator if Spree::User.included_modules.exclude?(SpreeStripeSubscriptions::UserDecorator)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Deface::Override.new(
|
2
|
+
virtual_path: 'spree/admin/shared/_main_menu',
|
3
|
+
name: 'admin_stripe_subscriptions_menu_index',
|
4
|
+
insert_before: '[id="sidebarConfiguration"]'
|
5
|
+
) do
|
6
|
+
<<-HTML
|
7
|
+
<% if can? :admin, Spree::StripeConfiguration %>
|
8
|
+
<ul class="nav nav-sidebar border-bottom" id="sidebarStripeSubscriptions">
|
9
|
+
<%= main_menu_tree I18n.t('spree_stripe_subscriptions.admin.stripe_subscriptions'), icon: 'list.svg', sub_menu: 'stripe_subscriptions', url: '#sidebar-stripe-subscriptions' %>
|
10
|
+
</ul>
|
11
|
+
<% end %>
|
12
|
+
HTML
|
13
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<ul id="sidebar-stripe-subscriptions" class="border-top bg-white collapse nav nav-pills nav-stacked">
|
2
|
+
<%= tab :stripe_configurations,
|
3
|
+
label: I18n.t('spree_stripe_subscriptions.admin.stripe_configurations'),
|
4
|
+
match_path: /\/dashboard\/stripe_configurations/ %>
|
5
|
+
<%= tab :stripe_customers, label: I18n.t('spree_stripe_subscriptions.admin.stripe_customers') %>
|
6
|
+
<%= tab :stripe_subscriptions, label: I18n.t('spree_stripe_subscriptions.admin.stripe_subscriptions') %>
|
7
|
+
<%= tab :stripe_subscription_events, label: I18n.t('spree_stripe_subscriptions.admin.stripe_subscription_events') %>
|
8
|
+
</ul>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<div data-hook="admin_stripe_configurations_fields">
|
2
|
+
<%= f.field_container :name do %>
|
3
|
+
<%= f.label :name, I18n.t('spree_stripe_subscriptions.models.stripe_configuration.name') %>
|
4
|
+
<%= f.text_field :name, class: 'form-control' %>
|
5
|
+
<%= f.error_message_on :name %>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<%= f.field_container :description do %>
|
9
|
+
<%= f.label :description, I18n.t('spree_stripe_subscriptions.models.stripe_configuration.description') %><br>
|
10
|
+
<%= f.text_area :description, class: 'form-control' %>
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
<div id="preference-settings" class="form-group">
|
14
|
+
<%= preference_fields(@stripe_configuration, f) %>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<%= f.field_container :billing_address_collection, class: ['form-group'] do %>
|
18
|
+
<%= f.label :billing_address_collection, I18n.t('spree_stripe_subscriptions.models.stripe_configuration.billing_address_collection') %>
|
19
|
+
<%= f.select :billing_address_collection, Spree::StripeConfiguration::ADDRESS_COLLECTION_OPTIONS.collect { |k, v| [v, k] }, {}, { class: 'select2' } %>
|
20
|
+
<% end %>
|
21
|
+
|
22
|
+
<%= f.field_container :automatic_tax, class: ['checkbox'] do %>
|
23
|
+
<%= f.label :automatic_tax do %>
|
24
|
+
<%= f.check_box :automatic_tax %>
|
25
|
+
<%= I18n.t('spree_stripe_subscriptions.models.stripe_configuration.automatic_tax') %>
|
26
|
+
<% end %>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<%= f.field_container :tax_id_collection, class: ['checkbox'] do %>
|
30
|
+
<%= f.label :tax_id_collection do %>
|
31
|
+
<%= f.check_box :tax_id_collection %>
|
32
|
+
<%= I18n.t('spree_stripe_subscriptions.models.stripe_configuration.tax_id_collection') %>
|
33
|
+
<% end %>
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
<%= f.field_container :active, class: ['checkbox'] do %>
|
37
|
+
<%= f.label :active do %>
|
38
|
+
<%= f.check_box :active %>
|
39
|
+
<%= I18n.t('spree_stripe_subscriptions.models.stripe_configuration.active') %>
|
40
|
+
<% end %>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= link_to I18n.t('spree_stripe_subscriptions.admin.stripe_subscriptions'), spree.admin_stripe_configurations_url %> /
|
3
|
+
<%= @stripe_configuration.name %>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<% content_for :page_actions do %>
|
7
|
+
<%= button_link_to I18n.t('spree_stripe_subscriptions.admin.manage_plans'), admin_stripe_configuration_stripe_plans_url(@stripe_configuration), class: "btn-success" %>
|
8
|
+
<% end if @stripe_configuration.preferred_keys_available? %>
|
9
|
+
|
10
|
+
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @stripe_configuration } %>
|
11
|
+
|
12
|
+
<%= form_for [:admin, @stripe_configuration] do |f| %>
|
13
|
+
<fieldset>
|
14
|
+
<%= render partial: 'form', locals: { f: f } %>
|
15
|
+
<%= render partial: 'spree/admin/shared/edit_resource_links' %>
|
16
|
+
</fieldset>
|
17
|
+
<% end %>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= I18n.t('spree_stripe_subscriptions.admin.stripe_configurations') %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<% content_for :page_actions do %>
|
6
|
+
<%= button_link_to I18n.t('spree_stripe_subscriptions.admin.new_stripe_configuration'), new_object_url, class: "btn-success", icon: 'add.svg' %>
|
7
|
+
<% end if can? :create, Spree::StripeConfiguration %>
|
8
|
+
|
9
|
+
<% if @stripe_configurations.any? %>
|
10
|
+
<div class="table-responsive">
|
11
|
+
<table class="table">
|
12
|
+
<thead>
|
13
|
+
<tr>
|
14
|
+
<th><%= I18n.t('spree_stripe_subscriptions.models.stripe_configuration.name') %></th>
|
15
|
+
<th><%= I18n.t('spree_stripe_subscriptions.models.stripe_configuration.active') %></th>
|
16
|
+
<th></th>
|
17
|
+
</tr>
|
18
|
+
</thead>
|
19
|
+
<tbody>
|
20
|
+
<% @stripe_configurations.each do |stripe_configuration| %>
|
21
|
+
<tr id="<%= spree_dom_id stripe_configuration %>">
|
22
|
+
<td><%= stripe_configuration.name %></td>
|
23
|
+
<td><%= active_badge(stripe_configuration.active) %></td>
|
24
|
+
<td class="actions">
|
25
|
+
<span class="d-flex justify-content-end">
|
26
|
+
<%= link_to_edit(stripe_configuration, no_text: true) if can? :edit, stripe_configuration %>
|
27
|
+
<%= link_to_delete(stripe_configuration, no_text: true) if can? :delete, stripe_configuration %>
|
28
|
+
<%= link_to_with_icon 'adjust.svg',
|
29
|
+
I18n.t('spree_stripe_subscriptions.admin.manage_plans'),
|
30
|
+
spree.admin_stripe_configuration_stripe_plans_url(stripe_configuration),
|
31
|
+
class: "btn btn-outline-secondary" if stripe_configuration.preferred_keys_available? %>
|
32
|
+
</span>
|
33
|
+
</tr>
|
34
|
+
<% end %>
|
35
|
+
</tbody>
|
36
|
+
</table>
|
37
|
+
</div>
|
38
|
+
<% else %>
|
39
|
+
<div class="alert alert-info no-objects-found">
|
40
|
+
<%= I18n.t('spree_stripe_subscriptions.admin.no_resource_found',
|
41
|
+
resource: I18n.t('spree_stripe_subscriptions.admin.stripe_configurations')) %>,
|
42
|
+
<%= link_to(I18n.t('spree_stripe_subscriptions.admin.add_one'), new_object_url) if can? :create, Spree::StripeConfiguration %>
|
43
|
+
</div>
|
44
|
+
<% end %>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= link_to I18n.t('spree_stripe_subscriptions.admin.stripe_configurations'), spree.admin_stripe_configurations_url %> /
|
3
|
+
<%= I18n.t('spree_stripe_subscriptions.admin.new_stripe_configuration') %>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @stripe_configuration } %>
|
7
|
+
|
8
|
+
<%= form_for [:admin, @stripe_configuration] do |f| %>
|
9
|
+
<fieldset>
|
10
|
+
<%= render partial: 'form', locals: { f: f } %>
|
11
|
+
<%= render partial: 'spree/admin/shared/new_resource_links' %>
|
12
|
+
</fieldset>
|
13
|
+
<% end %>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= I18n.t('spree_stripe_subscriptions.admin.stripe_customers') %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<% if @stripe_customers.any? %>
|
6
|
+
<div class="table-responsive">
|
7
|
+
<table class="table">
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th><%= I18n.t('spree_stripe_subscriptions.models.stripe_customers.name') %></th>
|
11
|
+
<th><%= I18n.t('spree_stripe_subscriptions.models.stripe_customers.email') %></th>
|
12
|
+
<th><%= I18n.t('spree_stripe_subscriptions.models.stripe_customers.stripe_customer_id') %></th>
|
13
|
+
<th></th>
|
14
|
+
</tr>
|
15
|
+
</thead>
|
16
|
+
<tbody>
|
17
|
+
<% @stripe_customers.each do |stripe_customer| %>
|
18
|
+
<tr id="<%= spree_dom_id stripe_customer %>">
|
19
|
+
<td><%= stripe_customer.user.probable_name %></td>
|
20
|
+
<td><%= stripe_customer.user.email %></td>
|
21
|
+
<td><%= stripe_customer.stripe_customer_id %></td>
|
22
|
+
<td class="actions">
|
23
|
+
<span class="d-flex justify-content-end">
|
24
|
+
<%#= link_to_edit(stripe_customer, no_text: true) if can? :edit, stripe_customer %>
|
25
|
+
<%#= link_to_delete(stripe_customer, no_text: true) if can? :delete, stripe_customer %>
|
26
|
+
</span>
|
27
|
+
</tr>
|
28
|
+
<% end %>
|
29
|
+
</tbody>
|
30
|
+
</table>
|
31
|
+
</div>
|
32
|
+
<% else %>
|
33
|
+
<div class="alert alert-info no-objects-found">
|
34
|
+
<%= I18n.t('spree_stripe_subscriptions.admin.no_resource_found', resource: I18n.t('spree_stripe_subscriptions.admin.stripe_customers')) %>
|
35
|
+
</div>
|
36
|
+
<% end %>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<div data-hook="admin_stripe_plans_fields">
|
2
|
+
<%= f.hidden_field :configuration_id, value: @stripe_configuration.id %>
|
3
|
+
|
4
|
+
<%= f.field_container :name, class: ['form-group'] do %>
|
5
|
+
<%= f.label :name, I18n.t('spree_stripe_subscriptions.models.stripe_plans.name') %>
|
6
|
+
<%= f.text_field :name, class: 'form-control' %>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<%= f.field_container :description, class: ['form-group'] do %>
|
10
|
+
<%= f.label :description, I18n.t('spree_stripe_subscriptions.models.stripe_plans.description') %><br>
|
11
|
+
<%= f.text_area :description, class: 'form-control' %>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<%= f.field_container :interval, class: ['form-group'] do %>
|
15
|
+
<%= f.label :interval, I18n.t('spree_stripe_subscriptions.models.stripe_plans.interval') %>
|
16
|
+
<%= f.select :interval, Spree::StripePlan::INTERVAL.collect { |k, v| [v, k] }, {}, { :disabled => @stripe_plan.persisted?, class: 'select2' } %>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<%= f.field_container :interval_count, class: ['form-group'] do %>
|
20
|
+
<%= f.label :interval_count, I18n.t('spree_stripe_subscriptions.models.stripe_plans.interval_count') %>
|
21
|
+
<%= f.select :interval_count, (1..11).collect { |i| [i, i] }, {}, { :disabled => @stripe_plan.persisted?, class: 'select2' } %>
|
22
|
+
<% end %>
|
23
|
+
|
24
|
+
<%= f.field_container :currency, class: ['form-group'] do %>
|
25
|
+
<%= f.label :currency, I18n.t('spree_stripe_subscriptions.models.stripe_plans.currency') %>
|
26
|
+
<%= f.select :currency, Spree::StripePlan::CURRENCY.collect { |k, v| [v, k] }, {}, { :disabled => @stripe_plan.persisted?, class: 'select2' } %>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<%= f.field_container :amount, class: ['form-group'] do %>
|
30
|
+
<%= f.label :amount, I18n.t('spree_stripe_subscriptions.models.stripe_plans.amount') %>
|
31
|
+
<%= f.text_field :amount, :class => 'form-control', :disabled => @stripe_plan.persisted? %>
|
32
|
+
<% end %>
|
33
|
+
|
34
|
+
<%= f.field_container :trial_period_days, class: ['form-group'] do %>
|
35
|
+
<%= f.label :trial_period_days, I18n.t('spree_stripe_subscriptions.models.stripe_plans.trial_period_days') %>
|
36
|
+
<%= f.text_field :trial_period_days, :class => 'form-control', :disabled => @stripe_plan.persisted? %>
|
37
|
+
<% end %>
|
38
|
+
|
39
|
+
<%= f.field_container :tax_behavior, class: ['form-group'] do %>
|
40
|
+
<%= f.label :tax_behavior, I18n.t('spree_stripe_subscriptions.models.stripe_plans.tax_behavior') %>
|
41
|
+
<%= f.select :tax_behavior, Spree::StripePlan::TAX_BEHAVIOUR_OPTIONS.collect { |k, v| [v, k] }, {}, { class: 'select2' } %>
|
42
|
+
<% end %>
|
43
|
+
|
44
|
+
<%= f.field_container :active, class: ['form-group'] do %>
|
45
|
+
<div class="custom-control custom-switch">
|
46
|
+
<%= f.check_box :active, class: 'custom-control-input' %>
|
47
|
+
<%= f.label :active, class: 'custom-control-label' %>
|
48
|
+
</div>
|
49
|
+
<% end %>
|
50
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= link_to I18n.t('spree_stripe_subscriptions.admin.stripe_configurations'), spree.admin_stripe_configurations_url %> /
|
3
|
+
<%= link_to @stripe_configuration.name, spree.edit_admin_stripe_configuration_url(@stripe_configuration) %> /
|
4
|
+
<%= link_to I18n.t('spree_stripe_subscriptions.admin.stripe_plans'), spree.admin_stripe_configuration_stripe_plans_url(@stripe_configuration) %> /
|
5
|
+
<%= @stripe_plan.name %>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @stripe_plan } %>
|
9
|
+
|
10
|
+
<%= form_for [:admin, @stripe_configuration, @stripe_plan] do |f| %>
|
11
|
+
<fieldset>
|
12
|
+
<%= render partial: 'form', locals: { f: f } %>
|
13
|
+
<%= render partial: 'spree/admin/shared/edit_resource_links' %>
|
14
|
+
</fieldset>
|
15
|
+
<% end %>
|