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
@@ -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
|