effective_orders 2.2.4 → 3.0.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 +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +124 -84
- data/app/assets/javascripts/effective_orders/customers.js.coffee +39 -0
- data/app/assets/javascripts/effective_orders/providers/{stripe_charges.js.coffee → stripe.js.coffee} +15 -13
- data/app/assets/javascripts/effective_orders/subscriptions.js.coffee +73 -0
- data/app/assets/stylesheets/effective_orders.scss +2 -1
- data/app/assets/stylesheets/effective_orders/_order.scss +16 -8
- data/app/assets/stylesheets/effective_orders/_subscriptions.scss +14 -0
- data/app/controllers/admin/customers_controller.rb +11 -8
- data/app/controllers/admin/order_items_controller.rb +4 -8
- data/app/controllers/admin/orders_controller.rb +133 -87
- data/app/controllers/effective/carts_controller.rb +18 -8
- data/app/controllers/effective/concerns/purchase.rb +39 -0
- data/app/controllers/effective/customers_controller.rb +43 -0
- data/app/controllers/effective/orders_controller.rb +73 -119
- data/app/controllers/effective/providers/app_checkout.rb +3 -1
- data/app/controllers/effective/providers/ccbill.rb +4 -6
- data/app/controllers/effective/providers/cheque.rb +20 -11
- data/app/controllers/effective/providers/free.rb +33 -0
- data/app/controllers/effective/providers/mark_as_paid.rb +33 -0
- data/app/controllers/effective/providers/moneris.rb +9 -17
- data/app/controllers/effective/providers/paypal.rb +4 -6
- data/app/controllers/effective/providers/pretend.rb +4 -4
- data/app/controllers/effective/providers/refund.rb +39 -0
- data/app/controllers/effective/providers/stripe.rb +19 -40
- data/app/controllers/effective/providers/stripe_connect.rb +2 -6
- data/app/controllers/effective/webhooks_controller.rb +44 -95
- data/app/datatables/effective_customers_datatable.rb +21 -29
- data/app/datatables/effective_order_items_datatable.rb +77 -79
- data/app/datatables/effective_orders_datatable.rb +67 -57
- data/app/helpers/effective_carts_helper.rb +17 -14
- data/app/helpers/effective_orders_helper.rb +40 -56
- data/app/helpers/effective_paypal_helper.rb +3 -3
- data/app/helpers/effective_stripe_helper.rb +47 -18
- data/app/helpers/effective_subscriptions_helper.rb +79 -0
- data/app/mailers/effective/orders_mailer.rb +125 -2
- data/app/models/concerns/acts_as_purchasable.rb +23 -33
- data/app/models/concerns/acts_as_subscribable.rb +68 -0
- data/app/models/concerns/acts_as_subscribable_buyer.rb +22 -0
- data/app/models/effective/cart.rb +53 -24
- data/app/models/effective/cart_item.rb +6 -12
- data/app/models/effective/customer.rb +51 -54
- data/app/models/effective/order.rb +160 -147
- data/app/models/effective/order_item.rb +18 -21
- data/app/models/effective/product.rb +7 -7
- data/app/models/effective/providers/ccbill_postback.rb +1 -1
- data/app/models/effective/providers/stripe_charge.rb +8 -19
- data/app/models/effective/subscripter.rb +230 -0
- data/app/models/effective/subscription.rb +27 -76
- data/app/models/effective/tax_rate_calculator.rb +10 -7
- data/app/views/admin/customers/_actions.html.haml +1 -2
- data/app/views/admin/customers/index.html.haml +1 -1
- data/app/views/admin/customers/show.html.haml +6 -0
- data/app/views/admin/orders/_actions.html.haml +9 -7
- data/app/views/admin/orders/_form.html.haml +11 -7
- data/app/views/admin/orders/_order_actions.html.haml +2 -1
- data/app/views/admin/orders/_order_item_fields.html.haml +1 -1
- data/app/views/admin/orders/edit.html.haml +4 -0
- data/app/views/admin/orders/index.html.haml +1 -4
- data/app/views/admin/orders/new.html.haml +1 -1
- data/app/views/admin/orders/show.html.haml +5 -6
- data/app/views/effective/carts/_cart.html.haml +2 -2
- data/app/views/effective/carts/show.html.haml +2 -2
- data/app/views/effective/customers/_customer.html.haml +152 -0
- data/app/views/effective/customers/_fields.html.haml +12 -0
- data/app/views/effective/customers/_form.html.haml +13 -0
- data/app/views/effective/customers/edit.html.haml +3 -0
- data/app/views/effective/orders/_checkout_step1.html.haml +8 -15
- data/app/views/effective/orders/_checkout_step2.html.haml +34 -21
- data/app/views/effective/orders/_order.html.haml +8 -9
- data/app/views/effective/orders/_order_actions.html.haml +7 -8
- data/app/views/effective/orders/_order_header.html.haml +1 -1
- data/app/views/effective/orders/_order_items.html.haml +11 -5
- data/app/views/effective/orders/_order_note.html.haml +4 -7
- data/app/views/effective/orders/_orders_table.html.haml +26 -26
- data/app/views/effective/orders/app_checkout/_form.html.haml +2 -2
- data/app/views/effective/orders/ccbill/_form.html.haml +1 -1
- data/app/views/effective/orders/cheque/_form.html.haml +3 -1
- data/app/views/effective/orders/declined.html.haml +1 -1
- data/app/views/effective/orders/{checkout_step1.html.haml → edit.html.haml} +0 -0
- data/app/views/effective/orders/free/_form.html.haml +4 -0
- data/app/views/effective/orders/index.html.haml +2 -4
- data/app/views/effective/orders/mark_as_paid/_form.html.haml +32 -0
- data/app/views/effective/orders/moneris/_form.html.haml +6 -6
- data/app/views/effective/orders/{checkout_step2.html.haml → new.html.haml} +1 -1
- data/app/views/effective/orders/paypal/_form.html.haml +2 -2
- data/app/views/effective/orders/pretend/_form.html.haml +2 -2
- data/app/views/effective/orders/purchased.html.haml +3 -0
- data/app/views/effective/orders/refund/_form.html.haml +32 -0
- data/app/views/effective/orders/show.html.haml +4 -1
- data/app/views/effective/orders/stripe/_form.html.haml +5 -5
- data/app/views/effective/orders_mailer/subscription_canceled.html.haml +9 -0
- data/app/views/effective/orders_mailer/subscription_payment_failed.html.haml +9 -0
- data/app/views/effective/orders_mailer/subscription_payment_succeeded.html.haml +9 -0
- data/app/views/effective/orders_mailer/subscription_trial_expired.html.haml +5 -0
- data/app/views/effective/orders_mailer/subscription_trial_expiring.html.haml +7 -0
- data/app/views/effective/subscriptions/_fields.html.haml +16 -0
- data/app/views/effective/subscriptions/_plan.html.haml +21 -0
- data/app/views/layouts/effective_orders_mailer_layout.html.haml +6 -8
- data/config/effective_orders.rb +41 -20
- data/config/routes.rb +48 -48
- data/db/migrate/01_create_effective_orders.rb.erb +19 -5
- data/lib/effective_orders.rb +78 -42
- data/lib/effective_orders/engine.rb +36 -82
- data/lib/effective_orders/version.rb +1 -1
- data/lib/generators/effective_orders/install_generator.rb +2 -2
- data/lib/generators/templates/effective_orders_mailer_preview.rb +39 -4
- data/lib/tasks/effective_orders_tasks.rake +42 -0
- data/spec/controllers/carts_controller_spec.rb +1 -1
- data/spec/controllers/moneris_orders_controller_spec.rb +4 -4
- data/spec/controllers/orders_controller_spec.rb +4 -4
- data/spec/controllers/stripe_orders_controller_spec.rb +2 -2
- data/spec/controllers/webhooks_controller_spec.rb +1 -1
- data/spec/dummy/config/initializers/effective_orders.rb +1 -7
- data/spec/dummy/db/schema.rb +1 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +3 -0
- data/spec/models/acts_as_purchasable_spec.rb +0 -56
- data/spec/models/customer_spec.rb +3 -3
- data/spec/models/order_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -1
- data/spec/support/factories.rb +2 -1
- metadata +37 -49
- data/active_admin/effective_carts.rb +0 -14
- data/active_admin/effective_orders.rb +0 -112
- data/app/assets/javascripts/effective_orders/providers/stripe_subscriptions.js.coffee +0 -28
- data/app/controllers/concerns/acts_as_active_admin_controller.rb +0 -69
- data/app/controllers/effective/subscriptions_controller.rb +0 -126
- data/app/models/effective/datatables/customers.rb +0 -40
- data/app/models/effective/datatables/order_items.rb +0 -101
- data/app/models/effective/datatables/orders.rb +0 -91
- data/app/models/inputs/price_field.rb +0 -63
- data/app/models/inputs/price_form_input.rb +0 -7
- data/app/models/inputs/price_formtastic_input.rb +0 -9
- data/app/models/inputs/price_input.rb +0 -19
- data/app/models/inputs/price_simple_form_input.rb +0 -8
- data/app/views/admin/orders/_form_mark_as_paid.html.haml +0 -33
- data/app/views/admin/orders/_order_payment_details.html.haml +0 -5
- data/app/views/admin/orders/mark_as_paid.html.haml +0 -7
- data/app/views/effective/orders/stripe/_subscription_fields.html.haml +0 -7
- data/app/views/effective/subscriptions/index.html.haml +0 -22
- data/app/views/effective/subscriptions/new.html.haml +0 -9
- data/app/views/effective/subscriptions/show.html.haml +0 -49
- data/db/upgrade/02_upgrade_effective_orders_from03x.rb.erb +0 -29
- data/db/upgrade/03_upgrade_effective_orders_from1x.rb.erb +0 -98
- data/db/upgrade/upgrade_price_column_on_table.rb.erb +0 -17
- data/lib/generators/effective_orders/upgrade_from03x_generator.rb +0 -31
- data/lib/generators/effective_orders/upgrade_from1x_generator.rb +0 -27
- data/lib/generators/effective_orders/upgrade_price_column_generator.rb +0 -30
@@ -1,8 +1,8 @@
|
|
1
1
|
module EffectiveOrdersHelper
|
2
|
-
def price_to_currency(price
|
3
|
-
|
4
|
-
|
5
|
-
number_to_currency(price / 100.0
|
2
|
+
def price_to_currency(price)
|
3
|
+
price = price || 0
|
4
|
+
raise 'price_to_currency expects an Integer representing the number of cents' unless price.kind_of?(Integer)
|
5
|
+
number_to_currency(price / 100.0)
|
6
6
|
end
|
7
7
|
|
8
8
|
def tax_rate_to_percentage(tax_rate, options = {})
|
@@ -33,11 +33,15 @@ module EffectiveOrdersHelper
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def order_checkout_label(processor = nil)
|
36
|
-
return 'Checkout' if (EffectiveOrders.single_payment_processor? &&
|
36
|
+
return 'Checkout' if (EffectiveOrders.single_payment_processor? && ![:pretend, :mark_as_paid, :free, :refund].include?(processor))
|
37
37
|
|
38
38
|
case processor
|
39
|
+
when :mark_as_paid
|
40
|
+
'Mark as paid'
|
39
41
|
when :free
|
40
|
-
'Checkout'
|
42
|
+
'Checkout free'
|
43
|
+
when :refund
|
44
|
+
'Complete refund'
|
41
45
|
when :moneris, :stripe, :ccbill
|
42
46
|
'Checkout with credit card'
|
43
47
|
when :paypal
|
@@ -45,7 +49,7 @@ module EffectiveOrdersHelper
|
|
45
49
|
when :pretend
|
46
50
|
EffectiveOrders.allow_pretend_purchase_in_production ? 'Purchase Order' : 'Purchase Order (development only)'
|
47
51
|
when :cheque
|
48
|
-
'Pay by
|
52
|
+
'Pay by cheque'
|
49
53
|
when :app_checkout
|
50
54
|
EffectiveOrders.app_checkout[:checkout_label].presence || 'Checkout'
|
51
55
|
else
|
@@ -82,27 +86,38 @@ module EffectiveOrdersHelper
|
|
82
86
|
end
|
83
87
|
|
84
88
|
def render_order(order)
|
85
|
-
render(partial: 'effective/orders/order', locals: {order: order})
|
89
|
+
render(partial: 'effective/orders/order', locals: { order: order })
|
86
90
|
end
|
87
91
|
|
88
|
-
def render_checkout_step1(order,
|
89
|
-
raise
|
92
|
+
def render_checkout_step1(order, namespace: nil, purchased_url: nil, declined_url: nil)
|
93
|
+
raise 'unable to checkout an order without a user' unless order && order.user
|
90
94
|
|
91
|
-
locals = {
|
95
|
+
locals = { order: order, purchased_url: purchased_url, declined_url: declined_url, namespace: namespace }
|
92
96
|
|
93
|
-
render
|
97
|
+
render partial: 'effective/orders/checkout_step1', locals: locals
|
94
98
|
end
|
95
99
|
alias_method :render_checkout, :render_checkout_step1
|
96
100
|
|
97
|
-
def render_checkout_step2(order,
|
98
|
-
raise
|
101
|
+
def render_checkout_step2(order, namespace: nil, purchased_url: nil, declined_url: nil)
|
102
|
+
raise 'unable to checkout an order without a user' unless order && order.user
|
99
103
|
|
100
|
-
locals = {
|
104
|
+
locals = { order: order, purchased_url: purchased_url, declined_url: declined_url, namespace: namespace }
|
101
105
|
|
102
106
|
if order.new_record? || !order.valid?
|
103
|
-
render(partial: 'effective/orders/checkout_step1', locals: locals
|
107
|
+
render(partial: 'effective/orders/checkout_step1', locals: locals)
|
108
|
+
else
|
109
|
+
render(partial: 'effective/orders/checkout_step2', locals: locals)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def checkout_step1_form_url(order, namespace = nil)
|
114
|
+
raise 'expected an order' unless order
|
115
|
+
raise 'invalid namespace, expecting nil or :admin' unless [nil, :admin].include?(namespace)
|
116
|
+
|
117
|
+
if order.new_record?
|
118
|
+
namespace == nil ? effective_orders.orders_path : effective_orders.admin_orders_path
|
104
119
|
else
|
105
|
-
|
120
|
+
namespace == nil ? effective_orders.order_path(order) : effective_orders.checkout_admin_order_path(order)
|
106
121
|
end
|
107
122
|
end
|
108
123
|
|
@@ -116,56 +131,25 @@ module EffectiveOrdersHelper
|
|
116
131
|
label = options.delete(:label)
|
117
132
|
options[:class] = ((options[:class] || '') + ' btn-my-purchases')
|
118
133
|
|
119
|
-
link_to(label, effective_orders.
|
134
|
+
link_to(label, effective_orders.my_purchases_orders_path, options)
|
120
135
|
end
|
121
136
|
alias_method :link_to_order_history, :link_to_my_purchases
|
122
137
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
raise ArgumentError.new('expecting an instance of User or an array/collection of Effective::Order objects')
|
138
|
+
|
139
|
+
def render_orders(obj, opts = {})
|
140
|
+
orders = Array(obj.kind_of?(User) ? Effective::Order.purchased_by(obj) : obj)
|
141
|
+
|
142
|
+
if orders.any? { |order| order.kind_of?(Effective::Order) == false }
|
143
|
+
raise 'expected a User or Effective::Order'
|
130
144
|
end
|
131
145
|
|
132
|
-
render(partial: 'effective/orders/orders_table', locals: {orders: orders}.merge(opts))
|
146
|
+
render(partial: 'effective/orders/orders_table', locals: { orders: orders }.merge(opts))
|
133
147
|
end
|
134
148
|
|
135
149
|
alias_method :render_purchases, :render_orders
|
136
150
|
alias_method :render_my_purchases, :render_orders
|
137
151
|
alias_method :render_order_history, :render_orders
|
138
152
|
|
139
|
-
# Used by the _payment_details partial
|
140
|
-
def tableize_order_payment(hash, options = {class: 'table table-bordered'})
|
141
|
-
if hash.present? && hash.kind_of?(Hash)
|
142
|
-
content_tag(:table, class: options[:class]) do
|
143
|
-
title = options.delete(:title)
|
144
|
-
|
145
|
-
content = content_tag(:tbody) do
|
146
|
-
hash.map do |k, v|
|
147
|
-
content_tag(:tr) do
|
148
|
-
content_tag((options[:th] ? :th : :td), k) +
|
149
|
-
content_tag(:td) do
|
150
|
-
if v.kind_of?(Hash)
|
151
|
-
tableize_order_payment(v, options.merge(th: (options.key?(:sub_th) ? options[:sub_th] : options[:th])))
|
152
|
-
elsif v.kind_of?(Array)
|
153
|
-
'[' + v.join(', ') + ']'
|
154
|
-
else
|
155
|
-
v
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end.join.html_safe
|
160
|
-
end
|
161
|
-
|
162
|
-
title.blank? ? content : (content_tag(:thead) { content_tag(:tr) { content_tag(:th, title, colspan: 2) } } + content)
|
163
|
-
end
|
164
|
-
else
|
165
|
-
hash.to_s.html_safe
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
153
|
def payment_card_label(card)
|
170
154
|
card = card.to_s.downcase.gsub(' ', '').strip
|
171
155
|
|
@@ -15,9 +15,9 @@ module EffectivePaypalHelper
|
|
15
15
|
APP_KEY_PEM = ConfigReader.cert_or_key(:app_key)
|
16
16
|
|
17
17
|
def paypal_encrypted_payload(order)
|
18
|
-
raise
|
19
|
-
raise
|
20
|
-
raise
|
18
|
+
raise "unable to read EffectiveOrders PayPal paypal_cert #{EffectiveOrders.paypal[:paypal_cert]}" unless PAYPAL_CERT_PEM.present?
|
19
|
+
raise "unable to read EffectiveOrders PayPal app_cert #{EffectiveOrders.paypal[:app_cert]}" unless APP_CERT_PEM.present?
|
20
|
+
raise "unable to read EffectiveOrders PayPal app_key #{EffectiveOrders.paypal[:app_key]}" unless APP_KEY_PEM.present?
|
21
21
|
|
22
22
|
values = {
|
23
23
|
business: EffectiveOrders.paypal[:seller_email],
|
@@ -4,13 +4,13 @@ module EffectiveStripeHelper
|
|
4
4
|
STRIPE_CONNECT_TOKEN_URL = 'https://connect.stripe.com/oauth/token'
|
5
5
|
|
6
6
|
def is_stripe_connect_seller?(user)
|
7
|
-
Effective::Customer.
|
7
|
+
Effective::Customer.for_buyer(user).stripe_connect_access_token.present?
|
8
8
|
end
|
9
9
|
|
10
10
|
def link_to_new_stripe_connect_customer(opts = {})
|
11
11
|
client_id = EffectiveOrders.stripe[:connect_client_id]
|
12
12
|
|
13
|
-
raise
|
13
|
+
raise 'effective_orders config: stripe.connect_client_id has not been set' unless client_id.present?
|
14
14
|
|
15
15
|
authorize_params = {
|
16
16
|
response_type: :code,
|
@@ -26,28 +26,35 @@ module EffectiveStripeHelper
|
|
26
26
|
stripe_user_params = opts.delete :stripe_user
|
27
27
|
authorize_params.merge!({stripe_user: stripe_user_params}) if stripe_user_params.is_a?(Hash)
|
28
28
|
|
29
|
-
authorize_url = STRIPE_CONNECT_AUTHORIZE_URL
|
29
|
+
authorize_url = STRIPE_CONNECT_AUTHORIZE_URL + '?' + authorize_params.to_query
|
30
30
|
options = {}.merge(opts)
|
31
31
|
link_to image_tag('/assets/effective_orders/stripe_connect.png'), authorize_url, options
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
def stripe_plan_description(obj)
|
35
|
+
plan = (
|
36
|
+
case obj
|
37
|
+
when Hash ; obj
|
38
|
+
when ::Stripe::Plan ; EffectiveOrders.stripe_plans.find { |plan| plan.id == obj.id }
|
39
|
+
else ; raise 'unexpected object'
|
40
|
+
end
|
41
|
+
)
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
when 'yearly' ; '/year'
|
44
|
-
when 'week' ; plan.interval_count == 1 ? '/week' : " every #{plan.interval_count} weeks"
|
45
|
-
when 'month' ; plan.interval_count == 1 ? '/month' : " every #{plan.interval_count} months"
|
46
|
-
when 'year' ; plan.interval_count == 1 ? '/year' : " every #{plan.interval_count} years"
|
47
|
-
else ; plan.interval
|
48
|
-
end
|
43
|
+
raise("unknown stripe plan: #{obj}") unless plan.kind_of?(Hash) && plan[:id].present?
|
44
|
+
|
45
|
+
plan[:description]
|
46
|
+
end
|
49
47
|
|
50
|
-
|
48
|
+
def stripe_invoice_line_description(line, simple: false)
|
49
|
+
[
|
50
|
+
"#{line.quantity}x",
|
51
|
+
line.plan.name,
|
52
|
+
price_to_currency(line.amount),
|
53
|
+
("#{Time.zone.at(line.period.start).strftime('%F')}" unless simple),
|
54
|
+
('to' unless simple),
|
55
|
+
("#{Time.zone.at(line.period.end).strftime('%F')}" unless simple),
|
56
|
+
line.description.presence
|
57
|
+
].compact.join(' ')
|
51
58
|
end
|
52
59
|
|
53
60
|
def stripe_coupon_description(coupon)
|
@@ -60,4 +67,26 @@ module EffectiveStripeHelper
|
|
60
67
|
end
|
61
68
|
end
|
62
69
|
|
70
|
+
def stripe_site_image_url
|
71
|
+
return nil unless EffectiveOrders.stripe && (url = EffectiveOrders.stripe[:site_image].to_s).present?
|
72
|
+
url.start_with?('http') ? url : asset_url(url)
|
73
|
+
end
|
74
|
+
|
75
|
+
def stripe_order_description(order)
|
76
|
+
"#{order.num_items} items (#{price_to_currency(order.total)})"
|
77
|
+
end
|
78
|
+
|
79
|
+
def stripe_charge_data(order)
|
80
|
+
{
|
81
|
+
stripe: {
|
82
|
+
key: EffectiveOrders.stripe[:publishable_key],
|
83
|
+
name: EffectiveOrders.stripe[:site_title],
|
84
|
+
image: stripe_site_image_url,
|
85
|
+
email: order.user.email,
|
86
|
+
amount: order.total,
|
87
|
+
description: stripe_order_description(order)
|
88
|
+
}.to_json
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
63
92
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module EffectiveSubscriptionsHelper
|
2
|
+
|
3
|
+
def effective_customer_fields(form, submit: true)
|
4
|
+
raise 'expected a SimpleForm::FormBuilder object' unless form.class.name == 'SimpleForm::FormBuilder'
|
5
|
+
raise 'form object must be an Effective::Subscripter object' unless form.object.class.name == 'Effective::Subscripter'
|
6
|
+
|
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
|
21
|
+
|
22
|
+
def stripe_plans_collection(form, include_trial: nil, selected_class: 'selected panel-primary')
|
23
|
+
raise 'expected a SimpleForm::FormBuilder object' unless form.class.name == 'SimpleForm::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.subscribed?('trial') if include_trial.nil?
|
27
|
+
|
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] }
|
30
|
+
|
31
|
+
plans.map do |plan|
|
32
|
+
partial = (
|
33
|
+
if lookup_context.template_exists?("effective/subscriptions/#{plan[:id].downcase}", [], true)
|
34
|
+
"effective/subscriptions/#{plan[:id].downcase}" # Render the app's views/effective/subscriptions/_gold.html.haml
|
35
|
+
else
|
36
|
+
'effective/subscriptions/plan' # Render effective_orders default plan panel
|
37
|
+
end
|
38
|
+
)
|
39
|
+
|
40
|
+
content = render(partial: partial, locals: {
|
41
|
+
f: form,
|
42
|
+
plan: plan,
|
43
|
+
selected: Array(form.object.stripe_plan_id).include?(plan[:id]),
|
44
|
+
selected_class: selected_class,
|
45
|
+
subscribable: form.object.subscribable,
|
46
|
+
subscribed: form.object.subscribable.subscribed?(plan[:id])
|
47
|
+
})
|
48
|
+
|
49
|
+
[content, plan[:id]]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def effective_subscription_fields(form, label: false, required: true, include_trial: nil, item_wrapper_class: 'col-sm-6 col-md-4 col-lg-3', selected_class: 'selected panel-primary', wrapper_class: 'row')
|
54
|
+
raise 'expected a SimpleForm::FormBuilder object' unless form.class.name == 'SimpleForm::FormBuilder'
|
55
|
+
raise 'form object must be an acts_as_subscribable object' unless form.object.subscripter.present?
|
56
|
+
|
57
|
+
render(
|
58
|
+
partial: 'effective/subscriptions/fields',
|
59
|
+
locals: {
|
60
|
+
form: form,
|
61
|
+
label: label,
|
62
|
+
required: required,
|
63
|
+
include_trial: include_trial,
|
64
|
+
item_wrapper_class: item_wrapper_class,
|
65
|
+
selected_class: selected_class,
|
66
|
+
stripe: {
|
67
|
+
email: form.object.buyer.email,
|
68
|
+
image: stripe_site_image_url,
|
69
|
+
key: EffectiveOrders.stripe[:publishable_key],
|
70
|
+
name: EffectiveOrders.stripe[:site_title],
|
71
|
+
plans: EffectiveOrders.stripe_plans.values,
|
72
|
+
token_required: form.object.subscripter.token_required?
|
73
|
+
},
|
74
|
+
wrapper_class: wrapper_class
|
75
|
+
}
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -5,6 +5,8 @@ module Effective
|
|
5
5
|
layout EffectiveOrders.mailer[:layout].presence || 'effective_orders_mailer_layout'
|
6
6
|
|
7
7
|
def order_receipt_to_admin(order_param)
|
8
|
+
return true unless EffectiveOrders.mailer[:send_order_receipt_to_admin]
|
9
|
+
|
8
10
|
@order = (order_param.kind_of?(Effective::Order) ? order_param : Effective::Order.find(order_param))
|
9
11
|
|
10
12
|
mail(
|
@@ -15,6 +17,8 @@ module Effective
|
|
15
17
|
end
|
16
18
|
|
17
19
|
def order_receipt_to_buyer(order_param) # Buyer
|
20
|
+
return true unless EffectiveOrders.mailer[:send_order_receipt_to_buyer]
|
21
|
+
|
18
22
|
@order = (order_param.kind_of?(Effective::Order) ? order_param : Effective::Order.find(order_param))
|
19
23
|
|
20
24
|
mail(
|
@@ -25,6 +29,8 @@ module Effective
|
|
25
29
|
end
|
26
30
|
|
27
31
|
def order_receipt_to_seller(order_param, seller, order_items)
|
32
|
+
return true unless EffectiveOrders.mailer[:send_order_receipt_to_seller]
|
33
|
+
|
28
34
|
@order = (order_param.kind_of?(Effective::Order) ? order_param : Effective::Order.find(order_param))
|
29
35
|
@user = seller.user
|
30
36
|
@order_items = order_items
|
@@ -40,6 +46,8 @@ module Effective
|
|
40
46
|
# This is sent when an admin creates a new order or /admin/orders/new
|
41
47
|
# Or uses the order action Send Payment Request
|
42
48
|
def payment_request_to_buyer(order_param)
|
49
|
+
return true unless EffectiveOrders.mailer[:send_payment_request_to_buyer]
|
50
|
+
|
43
51
|
@order = (order_param.kind_of?(Effective::Order) ? order_param : Effective::Order.find(order_param))
|
44
52
|
|
45
53
|
mail(
|
@@ -51,6 +59,8 @@ module Effective
|
|
51
59
|
|
52
60
|
# This is sent when someone chooses to Pay by Cheque
|
53
61
|
def pending_order_invoice_to_buyer(order_param)
|
62
|
+
return true unless EffectiveOrders.mailer[:send_pending_order_invoice_to_buyer]
|
63
|
+
|
54
64
|
@order = (order_param.kind_of?(Effective::Order) ? order_param : Effective::Order.find(order_param))
|
55
65
|
|
56
66
|
mail(
|
@@ -60,6 +70,71 @@ module Effective
|
|
60
70
|
)
|
61
71
|
end
|
62
72
|
|
73
|
+
# Sent by the invoice.payment_succeeded webhook event
|
74
|
+
def subscription_payment_succeeded(customer_param)
|
75
|
+
return true unless EffectiveOrders.mailer[:send_subscription_payment_succeeded]
|
76
|
+
|
77
|
+
@customer = (customer_param.kind_of?(Effective::Customer) ? customer_param : Effective::Customer.find(customer_param))
|
78
|
+
|
79
|
+
mail(
|
80
|
+
to: @customer.user.email,
|
81
|
+
from: EffectiveOrders.mailer[:default_from],
|
82
|
+
subject: subject_for_subscription_payment_succeeded(@customer)
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Sent by the invoice.payment_failed webhook event
|
87
|
+
def subscription_payment_failed(customer_param)
|
88
|
+
return true unless EffectiveOrders.mailer[:send_subscription_payment_failed]
|
89
|
+
|
90
|
+
@customer = (customer_param.kind_of?(Effective::Customer) ? customer_param : Effective::Customer.find(customer_param))
|
91
|
+
|
92
|
+
mail(
|
93
|
+
to: @customer.user.email,
|
94
|
+
from: EffectiveOrders.mailer[:default_from],
|
95
|
+
subject: subject_for_subscription_payment_failed(@customer)
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Sent by the invoice.payment_failed webhook event
|
100
|
+
def subscription_canceled(customer_param)
|
101
|
+
return true unless EffectiveOrders.mailer[:send_subscription_canceled]
|
102
|
+
|
103
|
+
@customer = (customer_param.kind_of?(Effective::Customer) ? customer_param : Effective::Customer.find(customer_param))
|
104
|
+
|
105
|
+
mail(
|
106
|
+
to: @customer.user.email,
|
107
|
+
from: EffectiveOrders.mailer[:default_from],
|
108
|
+
subject: subject_for_subscription_canceled(@customer)
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Sent by the effective_orders:notify_trial_users rake task.
|
113
|
+
def subscription_trial_expiring(subscribable)
|
114
|
+
return true unless EffectiveOrders.mailer[:send_subscription_trial_expiring]
|
115
|
+
|
116
|
+
@subscribable = subscribable
|
117
|
+
|
118
|
+
mail(
|
119
|
+
to: @subscribable.buyer.email,
|
120
|
+
from: EffectiveOrders.mailer[:default_from],
|
121
|
+
subject: subject_for_subscription_trial_expiring(@subscribable)
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Sent by the effective_orders:notify_trial_users rake task.
|
126
|
+
def subscription_trial_expired(subscribable)
|
127
|
+
return true unless EffectiveOrders.mailer[:send_subscription_trial_expired]
|
128
|
+
|
129
|
+
@subscribable = subscribable
|
130
|
+
|
131
|
+
mail(
|
132
|
+
to: @subscribable.buyer.email,
|
133
|
+
from: EffectiveOrders.mailer[:default_from],
|
134
|
+
subject: subject_for_subscription_trial_expired(@subscribable)
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
63
138
|
def order_error(order: nil, error: nil, to: nil, from: nil, subject: nil, template: 'order_error')
|
64
139
|
if order.present?
|
65
140
|
@order = (order.kind_of?(Effective::Order) ? order : Effective::Order.find(order))
|
@@ -77,7 +152,6 @@ module Effective
|
|
77
152
|
) do |format|
|
78
153
|
format.html { render(template) }
|
79
154
|
end
|
80
|
-
|
81
155
|
end
|
82
156
|
|
83
157
|
private
|
@@ -103,7 +177,7 @@ module Effective
|
|
103
177
|
end
|
104
178
|
|
105
179
|
def subject_for_order_receipt_to_seller(order, order_items, seller)
|
106
|
-
string_or_callable = EffectiveOrders.mailer[:
|
180
|
+
string_or_callable = EffectiveOrders.mailer[:subject_for_order_receipt_to_seller]
|
107
181
|
|
108
182
|
if string_or_callable.respond_to?(:call) # This is a Proc or a function, not a string
|
109
183
|
string_or_callable = self.instance_exec(order, order_items, seller, &string_or_callable)
|
@@ -132,6 +206,55 @@ module Effective
|
|
132
206
|
prefix_subject(string_or_callable.presence || "Pending Order: ##{order.to_param}")
|
133
207
|
end
|
134
208
|
|
209
|
+
def subject_for_subscription_payment_succeeded(customer)
|
210
|
+
string_or_callable = EffectiveOrders.mailer[:subject_for_subscription_payment_succeeded]
|
211
|
+
|
212
|
+
if string_or_callable.respond_to?(:call) # This is a Proc or a function, not a string
|
213
|
+
string_or_callable = self.instance_exec(order, &string_or_callable)
|
214
|
+
end
|
215
|
+
|
216
|
+
prefix_subject(string_or_callable.presence || 'Thank you for your payment')
|
217
|
+
end
|
218
|
+
|
219
|
+
def subject_for_subscription_payment_failed(customer)
|
220
|
+
string_or_callable = EffectiveOrders.mailer[:subject_for_subscription_payment_failed]
|
221
|
+
|
222
|
+
if string_or_callable.respond_to?(:call) # This is a Proc or a function, not a string
|
223
|
+
string_or_callable = self.instance_exec(order, &string_or_callable)
|
224
|
+
end
|
225
|
+
|
226
|
+
prefix_subject(string_or_callable.presence || 'Payment failed - please update your card details')
|
227
|
+
end
|
228
|
+
|
229
|
+
def subject_for_subscription_canceled(customer)
|
230
|
+
string_or_callable = EffectiveOrders.mailer[:subject_for_subscription_canceled]
|
231
|
+
|
232
|
+
if string_or_callable.respond_to?(:call) # This is a Proc or a function, not a string
|
233
|
+
string_or_callable = self.instance_exec(order, &string_or_callable)
|
234
|
+
end
|
235
|
+
|
236
|
+
prefix_subject(string_or_callable.presence || 'Subscription canceled')
|
237
|
+
end
|
238
|
+
|
239
|
+
def subject_for_subscription_trial_expiring(customer)
|
240
|
+
string_or_callable = EffectiveOrders.mailer[:subject_for_subscription_trial_expiring]
|
241
|
+
|
242
|
+
if string_or_callable.respond_to?(:call) # This is a Proc or a function, not a string
|
243
|
+
string_or_callable = self.instance_exec(order, &string_or_callable)
|
244
|
+
end
|
245
|
+
|
246
|
+
prefix_subject(string_or_callable.presence || 'Trial expiring soon')
|
247
|
+
end
|
248
|
+
|
249
|
+
def subject_for_subscription_trial_expired(customer)
|
250
|
+
string_or_callable = EffectiveOrders.mailer[:subject_for_subscription_trial_expired]
|
251
|
+
|
252
|
+
if string_or_callable.respond_to?(:call) # This is a Proc or a function, not a string
|
253
|
+
string_or_callable = self.instance_exec(order, &string_or_callable)
|
254
|
+
end
|
255
|
+
|
256
|
+
prefix_subject(string_or_callable.presence || 'Trial expired')
|
257
|
+
end
|
135
258
|
|
136
259
|
def prefix_subject(text)
|
137
260
|
prefix = (EffectiveOrders.mailer[:subject_prefix].to_s rescue '')
|