effective_orders 2.2.4 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -6,10 +6,12 @@ module Effective
|
|
6
6
|
included do
|
7
7
|
end
|
8
8
|
|
9
|
+
# TODO: Make app checkout work with admin checkout workflow
|
10
|
+
|
9
11
|
def app_checkout
|
10
12
|
@order = Order.find(params[:id])
|
11
13
|
|
12
|
-
(EffectiveOrders.
|
14
|
+
(EffectiveOrders.authorize!(self, :update, @order) rescue false)
|
13
15
|
|
14
16
|
checkout = EffectiveOrders.app_checkout[:service].call(order: @order)
|
15
17
|
if checkout.success?
|
@@ -4,18 +4,16 @@ module Effective
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
|
8
|
-
skip_before_action :verify_authenticity_token, only: [:ccbill_postback]
|
9
|
-
else
|
10
|
-
skip_before_filter :verify_authenticity_token, only: [:ccbill_postback]
|
11
|
-
end
|
7
|
+
skip_before_action :verify_authenticity_token, only: [:ccbill_postback]
|
12
8
|
end
|
13
9
|
|
10
|
+
# TODO: Make ccbill work with admin checkout workflow
|
11
|
+
|
14
12
|
def ccbill_postback
|
15
13
|
postback = Effective::Providers::CcbillPostback.new(params)
|
16
14
|
@order ||= Effective::Order.find(postback.order_id)
|
17
15
|
|
18
|
-
(EffectiveOrders.
|
16
|
+
(EffectiveOrders.authorize!(self, :update, @order) rescue false)
|
19
17
|
|
20
18
|
if @order.present? && postback.verified?
|
21
19
|
if @order.purchased?
|
@@ -5,25 +5,34 @@ module Effective
|
|
5
5
|
|
6
6
|
def pay_by_cheque
|
7
7
|
@order ||= Order.find(params[:id])
|
8
|
+
@page_title = 'Payment Required'
|
9
|
+
|
10
|
+
EffectiveOrders.authorize!(self, :update, @order)
|
8
11
|
|
9
12
|
@order.purchase_state = EffectiveOrders::PENDING
|
10
13
|
@order.payment_provider = 'cheque'
|
11
14
|
|
12
|
-
|
15
|
+
begin
|
16
|
+
@order.save!
|
17
|
+
@order.send_pending_order_invoice_to_buyer!
|
13
18
|
|
14
|
-
|
19
|
+
Effective::Cart.where(user_id: @order.user_id).destroy_all
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
+
message = "Successfully indicated order will be payed by cheque. A pending order invoice has been sent to #{@order.user.email}"
|
22
|
+
|
23
|
+
# When posted from admin form, there will be a redirect url
|
24
|
+
if params[:purchased_url].present?
|
25
|
+
flash[:success] = message
|
26
|
+
redirect_to params[:purchased_url].gsub(':id', @order.to_param.to_s)
|
27
|
+
else
|
28
|
+
# Otherwise this is the user flow
|
29
|
+
flash.now[:success] = message
|
30
|
+
render 'effective/orders/cheque/pay_by_cheque'
|
31
|
+
end
|
32
|
+
rescue => e
|
21
33
|
flash[:danger] = "Unable to save your order: #{@order.errors.full_messages.to_sentence}. Please try again."
|
22
|
-
redirect_to effective_orders.order_path(@order)
|
23
|
-
return
|
34
|
+
redirect_to params[:declined_url].presence || effective_orders.order_path(@order)
|
24
35
|
end
|
25
|
-
|
26
|
-
render 'effective/orders/cheque/pay_by_cheque'
|
27
36
|
end
|
28
37
|
end
|
29
38
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Effective
|
2
|
+
module Providers
|
3
|
+
module Free
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def free
|
7
|
+
@order ||= Order.find(params[:id])
|
8
|
+
|
9
|
+
EffectiveOrders.authorize!(self, :update, @order)
|
10
|
+
|
11
|
+
unless @order.free?
|
12
|
+
flash[:danger] = 'Unable to process free order with a non-zero total'
|
13
|
+
redirect_to effective_orders.order_path(@order)
|
14
|
+
return
|
15
|
+
end
|
16
|
+
|
17
|
+
order_purchased(
|
18
|
+
details: 'free order. no payment required.',
|
19
|
+
provider: 'free',
|
20
|
+
card: 'none',
|
21
|
+
purchased_url: params[:purchased_url],
|
22
|
+
declined_url: params[:declined_url],
|
23
|
+
email: false
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def free_params
|
28
|
+
params.require(:effective_order).permit(:purchased_url, :declined_url)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Effective
|
2
|
+
module Providers
|
3
|
+
module MarkAsPaid
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def mark_as_paid
|
7
|
+
@order ||= Order.find(params[:id])
|
8
|
+
|
9
|
+
EffectiveOrders.authorize!(self, :update, @order)
|
10
|
+
EffectiveOrders.authorize!(self, :admin, :effective_orders)
|
11
|
+
|
12
|
+
@order.assign_attributes(mark_as_paid_params.except(:payment, :payment_provider, :payment_card))
|
13
|
+
|
14
|
+
order_purchased(
|
15
|
+
details: mark_as_paid_params[:payment],
|
16
|
+
provider: mark_as_paid_params[:payment_provider],
|
17
|
+
card: mark_as_paid_params[:payment_card],
|
18
|
+
email: @order.send_mark_as_paid_email_to_buyer?,
|
19
|
+
skip_buyer_validations: true,
|
20
|
+
purchased_url: params[:purchased_url].presence || effective_orders.admin_order_path(@order),
|
21
|
+
declined_url: params[:declined_url].presence || effective_orders.admin_order_path(@order)
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def mark_as_paid_params
|
26
|
+
params.require(:effective_order).permit(
|
27
|
+
:payment, :payment_provider, :payment_card, :note_to_buyer, :send_mark_as_paid_email_to_buyer
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -4,24 +4,20 @@ module Effective
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
|
8
|
-
prepend_before_action :find_authenticity_token_from_moneris, only: [:moneris_postback]
|
9
|
-
else
|
10
|
-
prepend_before_filter :find_authenticity_token_from_moneris, only: [:moneris_postback]
|
11
|
-
end
|
7
|
+
skip_before_action :verify_authenticity_token, only: [:moneris_postback]
|
12
8
|
end
|
13
9
|
|
14
10
|
def moneris_postback
|
15
11
|
@order ||= Effective::Order.find(params[:response_order_id])
|
16
12
|
|
17
|
-
(EffectiveOrders.
|
13
|
+
(EffectiveOrders.authorize!(self, :update, @order) rescue false)
|
18
14
|
|
19
15
|
# Delete the Purchased and Declined Redirect URLs
|
20
|
-
|
21
|
-
|
16
|
+
purchased_url = params.delete(:rvar_purchased_url)
|
17
|
+
declined_url = params.delete(:rvar_declined_url)
|
22
18
|
|
23
19
|
if @order.purchased? # Fallback to a success condition of the Order is already purchased
|
24
|
-
order_purchased(details: params, provider: 'moneris', card: params[:card],
|
20
|
+
order_purchased(details: params, provider: 'moneris', card: params[:card], purchased_url: purchased_url)
|
25
21
|
return
|
26
22
|
end
|
27
23
|
|
@@ -31,12 +27,12 @@ module Effective
|
|
31
27
|
response_code = verify_params[:response_code].to_i # Sometimes moneris sends us the string 'null'
|
32
28
|
|
33
29
|
if response_code > 0 && response_code < 50 # Less than 50 means a successful validation
|
34
|
-
order_purchased(details: params.merge(verify_params), provider: 'moneris', card: params[:card],
|
30
|
+
order_purchased(details: params.merge(verify_params), provider: 'moneris', card: params[:card], purchased_url: purchased_url)
|
35
31
|
else
|
36
|
-
order_declined(details: params.merge(verify_params), provider: 'moneris', card: params[:card],
|
32
|
+
order_declined(details: params.merge(verify_params), provider: 'moneris', card: params[:card], declined_url: declined_url)
|
37
33
|
end
|
38
34
|
else
|
39
|
-
order_declined(details: params, provider: 'moneris', card: params[:card],
|
35
|
+
order_declined(details: params, provider: 'moneris', card: params[:card], declined_url: declined_url)
|
40
36
|
end
|
41
37
|
end
|
42
38
|
|
@@ -47,11 +43,7 @@ module Effective
|
|
47
43
|
end
|
48
44
|
|
49
45
|
def send_moneris_verify_request(verify_key)
|
50
|
-
`curl -F ps_store_id='#{EffectiveOrders.moneris[:ps_store_id]}' -F hpp_key='#{EffectiveOrders.moneris[:hpp_key]}' -F transactionKey='#{verify_key}' --referer #{effective_orders.
|
51
|
-
end
|
52
|
-
|
53
|
-
def find_authenticity_token_from_moneris
|
54
|
-
params[:authenticity_token] = params.delete(:rvar_authenticity_token)
|
46
|
+
`curl -F ps_store_id='#{EffectiveOrders.moneris[:ps_store_id]}' -F hpp_key='#{EffectiveOrders.moneris[:hpp_key]}' -F transactionKey='#{verify_key}' --referer #{effective_orders.moneris_postback_orders_url} #{EffectiveOrders.moneris[:verify_url]}`
|
55
47
|
end
|
56
48
|
|
57
49
|
end
|
@@ -4,17 +4,15 @@ module Effective
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
|
8
|
-
skip_before_action :verify_authenticity_token, :only => [:paypal_postback]
|
9
|
-
else
|
10
|
-
skip_before_filter :verify_authenticity_token, :only => [:paypal_postback]
|
11
|
-
end
|
7
|
+
skip_before_action :verify_authenticity_token, only: [:paypal_postback]
|
12
8
|
end
|
13
9
|
|
10
|
+
# TODO: Make paypal postback work with admin checkout workflow
|
11
|
+
|
14
12
|
def paypal_postback
|
15
13
|
@order ||= Effective::Order.where(id: (params[:invoice].to_i rescue 0)).first
|
16
14
|
|
17
|
-
(EffectiveOrders.
|
15
|
+
(EffectiveOrders.authorize!(self, :update, @order) rescue false)
|
18
16
|
|
19
17
|
if @order.present?
|
20
18
|
if @order.purchased?
|
@@ -3,17 +3,17 @@ module Effective
|
|
3
3
|
module Pretend
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
def
|
6
|
+
def pretend
|
7
7
|
@order ||= Order.find(params[:id])
|
8
8
|
|
9
|
-
EffectiveOrders.
|
9
|
+
EffectiveOrders.authorize!(self, :update, @order)
|
10
10
|
|
11
11
|
order_purchased(
|
12
12
|
details: 'for pretend',
|
13
13
|
provider: 'pretend',
|
14
14
|
card: 'none',
|
15
|
-
|
16
|
-
|
15
|
+
purchased_url: params[:purchased_url],
|
16
|
+
declined_url: params[:declined_url]
|
17
17
|
)
|
18
18
|
end
|
19
19
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Effective
|
2
|
+
module Providers
|
3
|
+
module Refund
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def refund
|
7
|
+
@order ||= Order.find(params[:id])
|
8
|
+
|
9
|
+
EffectiveOrders.authorize!(self, :update, @order)
|
10
|
+
EffectiveOrders.authorize!(self, :admin, :effective_orders)
|
11
|
+
|
12
|
+
unless @order.refund?
|
13
|
+
flash[:danger] = 'Unable to process refund with a non-negative total'
|
14
|
+
redirect_to effective_orders.admin_order_path(@order)
|
15
|
+
return
|
16
|
+
end
|
17
|
+
|
18
|
+
@order.assign_attributes(refund_params.except(:payment, :payment_provider, :payment_card))
|
19
|
+
|
20
|
+
order_purchased(
|
21
|
+
details: refund_params[:payment],
|
22
|
+
provider: refund_params[:payment_provider],
|
23
|
+
card: refund_params[:payment_card],
|
24
|
+
email: @order.send_mark_as_paid_email_to_buyer?,
|
25
|
+
skip_buyer_validations: true,
|
26
|
+
purchased_url: params[:purchased_url].presence || effective_orders.admin_order_path(@order),
|
27
|
+
declined_url: params[:declined_url].presence || effective_orders.admin_order_path(@order)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def refund_params
|
32
|
+
params.require(:effective_order).permit(
|
33
|
+
:payment, :payment_provider, :payment_card, :note_to_buyer, :send_mark_as_paid_email_to_buyer
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -3,23 +3,26 @@ module Effective
|
|
3
3
|
module Stripe
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
+
# TODO: Make stripe charge work with admin checkout workflow, purchased_url and declined_url
|
7
|
+
# Make it save the customer and not require typing in a CC every time.
|
8
|
+
|
6
9
|
def stripe_charge
|
7
10
|
@order ||= Effective::Order.find(stripe_charge_params[:effective_order_id])
|
8
11
|
@stripe_charge = Effective::Providers::StripeCharge.new(stripe_charge_params)
|
9
12
|
@stripe_charge.order = @order
|
10
13
|
|
11
|
-
EffectiveOrders.
|
14
|
+
EffectiveOrders.authorize!(self, :update, @order)
|
12
15
|
|
13
16
|
if @stripe_charge.valid? && (response = process_stripe_charge(@stripe_charge)) != false
|
14
17
|
order_purchased(
|
15
18
|
details: response,
|
16
19
|
provider: (EffectiveOrders.stripe_connect_enabled ? 'stripe_connect' : 'stripe'),
|
17
|
-
card: (response[
|
20
|
+
card: (response[:charge]['source']['brand'] rescue nil)
|
18
21
|
)
|
19
22
|
else
|
20
23
|
@page_title = 'Checkout'
|
21
24
|
flash.now[:danger] = @stripe_charge.errors.full_messages.to_sentence
|
22
|
-
render :
|
25
|
+
render :show
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
@@ -28,16 +31,16 @@ module Effective
|
|
28
31
|
def process_stripe_charge(charge)
|
29
32
|
Effective::Order.transaction do
|
30
33
|
begin
|
31
|
-
|
32
|
-
|
34
|
+
subscripter = Effective::Subscripter.new(user: charge.order.user, stripe_token: charge.stripe_token)
|
35
|
+
subscripter.save!
|
33
36
|
|
34
37
|
if EffectiveOrders.stripe_connect_enabled
|
35
|
-
return charge_with_stripe_connect(charge,
|
38
|
+
return charge_with_stripe_connect(charge, subscripter.customer)
|
36
39
|
else
|
37
|
-
return charge_with_stripe(charge,
|
40
|
+
return charge_with_stripe(charge, subscripter.customer)
|
38
41
|
end
|
39
42
|
rescue => e
|
40
|
-
charge.errors.add(:base, "Unable to process order with Stripe.
|
43
|
+
charge.errors.add(:base, "Unable to process order with Stripe. Your credit card has not been charged. Message: \"#{e.message}\".")
|
41
44
|
raise ActiveRecord::Rollback
|
42
45
|
end
|
43
46
|
end
|
@@ -45,35 +48,15 @@ module Effective
|
|
45
48
|
false
|
46
49
|
end
|
47
50
|
|
48
|
-
def charge_with_stripe(charge,
|
49
|
-
results = {
|
50
|
-
|
51
|
-
# Process subscriptions.
|
52
|
-
charge.subscriptions.each do |subscription|
|
53
|
-
next if subscription.stripe_plan_id.blank?
|
54
|
-
|
55
|
-
stripe_subscription = if subscription.stripe_coupon_id.present?
|
56
|
-
buyer.stripe_customer.subscriptions.create({plan: subscription.stripe_plan_id, coupon: subscription.stripe_coupon_id})
|
57
|
-
else
|
58
|
-
buyer.stripe_customer.subscriptions.create({plan: subscription.stripe_plan.id})
|
59
|
-
end
|
60
|
-
|
61
|
-
subscription.stripe_subscription_id = stripe_subscription.id
|
62
|
-
subscription.save!
|
51
|
+
def charge_with_stripe(charge, customer)
|
52
|
+
results = { charge: nil }
|
63
53
|
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
# Process regular order_items.
|
68
|
-
amount = charge.order_items.map { |oi| oi.total }.sum # A positive integer in cents representing how much to charge the card. The minimum amount is 50 cents.
|
69
|
-
description = "Charge for Order ##{charge.order.to_param}"
|
70
|
-
|
71
|
-
if amount > 0
|
54
|
+
if charge.order.total > 0
|
72
55
|
results[:charge] = JSON.parse(::Stripe::Charge.create(
|
73
|
-
amount:
|
56
|
+
amount: charge.order.total,
|
74
57
|
currency: EffectiveOrders.stripe[:currency],
|
75
|
-
customer:
|
76
|
-
description:
|
58
|
+
customer: customer.stripe_customer.id,
|
59
|
+
description: "Charge for Order ##{charge.order.to_param}"
|
77
60
|
).to_json)
|
78
61
|
end
|
79
62
|
|
@@ -82,7 +65,7 @@ module Effective
|
|
82
65
|
|
83
66
|
def charge_with_stripe_connect(charge, buyer)
|
84
67
|
# Go through and create Stripe::Tokens for each seller
|
85
|
-
items = charge.order_items.group_by
|
68
|
+
items = charge.order_items.group_by { |oi| oi.seller }
|
86
69
|
results = {}
|
87
70
|
|
88
71
|
# We do all these Tokens first, so if one throws an exception no charges are made
|
@@ -113,11 +96,7 @@ module Effective
|
|
113
96
|
|
114
97
|
# StrongParameters
|
115
98
|
def stripe_charge_params
|
116
|
-
|
117
|
-
params.require(:effective_providers_stripe_charge).permit(:token, :effective_order_id)
|
118
|
-
rescue => e
|
119
|
-
params[:effective_providers_stripe_charge]
|
120
|
-
end
|
99
|
+
params.require(:effective_providers_stripe_charge).permit(:stripe_token, :effective_order_id)
|
121
100
|
end
|
122
101
|
|
123
102
|
end
|
@@ -4,11 +4,7 @@ module Effective
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
|
8
|
-
prepend_before_action :set_stripe_connect_state_params, :only => [:stripe_connect_redirect_uri]
|
9
|
-
else
|
10
|
-
prepend_before_filter :set_stripe_connect_state_params, :only => [:stripe_connect_redirect_uri]
|
11
|
-
end
|
7
|
+
prepend_before_action :set_stripe_connect_state_params, only: [:stripe_connect_redirect_uri]
|
12
8
|
end
|
13
9
|
|
14
10
|
# So this is the postback after Stripe does its oAuth authentication
|
@@ -18,7 +14,7 @@ module Effective
|
|
18
14
|
customer = Effective::Customer.for_user(current_user)
|
19
15
|
|
20
16
|
if token_params['access_token'].present? && customer.present?
|
21
|
-
if customer.update_attributes(:
|
17
|
+
if customer.update_attributes(stripe_connect_access_token: token_params['access_token'])
|
22
18
|
flash[:success] = 'Successfully Connected with Stripe Connect'
|
23
19
|
else
|
24
20
|
flash[:danger] = "Unable to update customer: #{customer.errors[:base].first}"
|
@@ -3,115 +3,64 @@ module Effective
|
|
3
3
|
protect_from_forgery except: [:stripe]
|
4
4
|
skip_authorization_check if defined?(CanCan)
|
5
5
|
|
6
|
-
# Webhook from stripe
|
7
6
|
def stripe
|
8
|
-
|
7
|
+
@event = (Stripe::Webhook.construct_event(request.body.read, request.env['HTTP_STRIPE_SIGNATURE'], EffectiveOrders.subscription[:webhook_secret]) rescue nil)
|
8
|
+
(head(:bad_request) and return) if !@event || (params[:livemode] == false && Rails.env.production?)
|
9
9
|
|
10
|
-
|
11
|
-
@event = Stripe::Event.retrieve(params[:id]) rescue (head(:ok) && return)
|
10
|
+
Rails.logger.info "STRIPE WEBHOOK: #{@event.type}"
|
12
11
|
|
13
12
|
Effective::Customer.transaction do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
13
|
+
case @event.type
|
14
|
+
# when 'customer.created'
|
15
|
+
# when 'customer.updated'
|
16
|
+
# when 'customer.source.created'
|
17
|
+
# when 'customer.source.deleted'
|
18
|
+
# when 'customer.subscription.created'
|
19
|
+
# when 'customer.subscription.updated'
|
20
|
+
# when 'invoice.created'
|
21
|
+
# when 'invoice.payment_succeeded'
|
22
|
+
# when 'invoiceitem.created'
|
23
|
+
# when 'invoiceitem.updated'
|
24
|
+
# when 'charge.succeeded'
|
25
|
+
# when 'charge.failed' # Card declined. 4000 0000 0000 0341
|
26
|
+
|
27
|
+
when 'invoice.payment_succeeded'
|
28
|
+
customer = Effective::Customer.where(stripe_customer_id: @event.data.object.customer).first!
|
29
|
+
customer.update_attributes!(status: 'active')
|
30
|
+
|
31
|
+
send_email(:subscription_payment_succeeded, customer)
|
32
|
+
when 'invoice.payment_failed'
|
33
|
+
customer = Effective::Customer.where(stripe_customer_id: @event.data.object.customer).first!
|
34
|
+
customer.update_attributes!(status: 'past_due')
|
35
|
+
|
36
|
+
send_email(:subscription_payment_failed, customer)
|
37
|
+
when 'customer.subscription.deleted'
|
38
|
+
customer = Effective::Customer.where(stripe_customer_id: @event.data.object.customer).first!
|
39
|
+
Effective::Subscription.where(customer: customer).destroy_all
|
40
|
+
customer.update_attributes!(stripe_subscription_id: nil, status: nil, active_card: nil)
|
41
|
+
|
42
|
+
send_email(:subscription_canceled, customer)
|
43
|
+
else
|
44
|
+
Rails.logger.info "[STRIPE WEBHOOK] Unhandled event type #{@event.type}"
|
25
45
|
end
|
26
46
|
end
|
27
47
|
|
28
|
-
head
|
48
|
+
head(:ok)
|
29
49
|
end
|
30
50
|
|
31
51
|
private
|
32
52
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
customer.save!
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def stripe_customer_deleted(event)
|
45
|
-
stripe_customer = event.data.object
|
46
|
-
user = ::User.where(email: stripe_customer.email).first
|
47
|
-
|
48
|
-
if user.present?
|
49
|
-
customer = Effective::Customer.where(user_id: user.id).first
|
50
|
-
customer.destroy! if customer
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def stripe_subscription_created(event)
|
55
|
-
stripe_subscription = event.data.object
|
56
|
-
@customer = Effective::Customer.where(stripe_customer_id: stripe_subscription.customer).first
|
57
|
-
|
58
|
-
if @customer.present?
|
59
|
-
subscription = @customer.subscriptions.where(stripe_plan_id: stripe_subscription.plan.id).first_or_initialize
|
60
|
-
|
61
|
-
subscription.stripe_subscription_id = stripe_subscription.id
|
62
|
-
subscription.stripe_plan_id = (stripe_subscription.plan.id rescue nil)
|
63
|
-
subscription.stripe_coupon_id = stripe_subscription.discount.coupon.id if (stripe_subscription.discount.present? rescue false)
|
64
|
-
|
65
|
-
subscription.save!
|
66
|
-
|
67
|
-
unless subscription.purchased?
|
68
|
-
# Now we have to purchase it
|
69
|
-
@order = Effective::Order.new(subscription, user: @customer.user)
|
70
|
-
@order.purchase!(details: "Webhook #{event.id}", provider: 'stripe', validate: false)
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def stripe_subscription_deleted(event)
|
77
|
-
stripe_subscription = event.data.object
|
78
|
-
@customer = Effective::Customer.where(stripe_customer_id: stripe_subscription.customer).first
|
79
|
-
|
80
|
-
if @customer.present?
|
81
|
-
@customer.subscriptions.find { |subscription| subscription.stripe_plan_id == stripe_subscription.plan.id }.try(:destroy)
|
82
|
-
subscription_deleted_callback(event)
|
53
|
+
def send_email(email, *mailer_args)
|
54
|
+
if EffectiveOrders.mailer[:delayed_job_deliver] && EffectiveOrders.mailer[:deliver_method] == :deliver_later
|
55
|
+
Effective::OrdersMailer.delay.public_send(email, *mailer_args)
|
56
|
+
elsif EffectiveOrders.mailer[:deliver_method].present?
|
57
|
+
Effective::OrdersMailer.public_send(email, *mailer_args).public_send(EffectiveOrders.mailer[:deliver_method])
|
58
|
+
else
|
59
|
+
Effective::OrdersMailer.public_send(email, *mailer_args).deliver_now
|
83
60
|
end
|
84
|
-
end
|
85
61
|
|
86
|
-
|
87
|
-
@customer = Effective::Customer.where(stripe_customer_id: event.data.object.customer).first
|
88
|
-
|
89
|
-
check_for_subscription_renewal(event) if @customer.present?
|
62
|
+
true
|
90
63
|
end
|
91
64
|
|
92
|
-
def check_for_subscription_renewal(event)
|
93
|
-
invoice_payment = event.data.object
|
94
|
-
subscription_payments = invoice_payment.lines.select { |line_item| line_item.type == 'subscription' }
|
95
|
-
|
96
|
-
if subscription_payments.present?
|
97
|
-
customer = Stripe::Customer.retrieve(invoice_payment.customer)
|
98
|
-
subscription_payments.each do |subscription_payment|
|
99
|
-
subscription_renewed_callback(event) if stripe_subscription_renewed?(customer, subscription_payment)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def stripe_subscription_renewed?(customer, subscription_payment)
|
105
|
-
subscription = customer.subscriptions.retrieve(subscription_payment.id) rescue nil # API client raises error when object not found
|
106
|
-
subscription.present? && subscription.status == 'active' && subscription.start < (subscription_payment.period.start - 1.day)
|
107
|
-
end
|
108
|
-
|
109
|
-
def subscription_deleted_callback(_event)
|
110
|
-
# Can be overridden in Effective::WebhooksController within a Rails application
|
111
|
-
end
|
112
|
-
|
113
|
-
def subscription_renewed_callback(_event)
|
114
|
-
# Can be overridden in Effective::WebhooksController within a Rails application
|
115
|
-
end
|
116
65
|
end
|
117
66
|
end
|