spree_account_recurring 1.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.
- data/LICENSE +26 -0
- data/README.md +108 -0
- data/app/assets/javascripts/admin/spree_account_recurring.js +1 -0
- data/app/assets/javascripts/store/spree_account_recurring.js +1 -0
- data/app/assets/javascripts/store/stripe.js +53 -0
- data/app/assets/stylesheets/admin/spree_account_recurring.css +3 -0
- data/app/assets/stylesheets/store/spree_account_recurring.css +3 -0
- data/app/controllers/concerns/spree/admin/ransack_date_search.rb +47 -0
- data/app/controllers/spree/admin/plans_controller.rb +63 -0
- data/app/controllers/spree/admin/recurrings_controller.rb +66 -0
- data/app/controllers/spree/admin/subscription_events_controller.rb +14 -0
- data/app/controllers/spree/admin/subscriptions_controller.rb +14 -0
- data/app/controllers/spree/plans_controller.rb +7 -0
- data/app/controllers/spree/recurring_hooks_controller.rb +53 -0
- data/app/controllers/spree/subscriptions_controller.rb +69 -0
- data/app/models/concerns/before_each.rb +21 -0
- data/app/models/concerns/restrictive_destroyer.rb +44 -0
- data/app/models/concerns/spree/plan/api_handler.rb +46 -0
- data/app/models/concerns/spree/recurring/stripe_recurring/api_handler.rb +28 -0
- data/app/models/concerns/spree/recurring/stripe_recurring/api_handler/plan_api_handler.rb +49 -0
- data/app/models/concerns/spree/recurring/stripe_recurring/api_handler/subscription_api_handler.rb +20 -0
- data/app/models/concerns/spree/recurring/stripe_recurring/api_handler/subscription_event_api_handler.rb +19 -0
- data/app/models/concerns/spree/subscription/api_handler.rb +38 -0
- data/app/models/concerns/spree/subscription/role_subscriber.rb +36 -0
- data/app/models/spree/plan.rb +31 -0
- data/app/models/spree/recurring.rb +27 -0
- data/app/models/spree/recurring/stripe_recurring.rb +16 -0
- data/app/models/spree/subscriber_ability.rb +17 -0
- data/app/models/spree/subscription.rb +33 -0
- data/app/models/spree/subscription_event.rb +11 -0
- data/app/models/spree/user_decorator.rb +14 -0
- data/app/overrides/admin/view_decorator.rb +27 -0
- data/app/views/spree/admin/plans/_form.html.erb +47 -0
- data/app/views/spree/admin/plans/destroy.js.erb +0 -0
- data/app/views/spree/admin/plans/edit.html.erb +22 -0
- data/app/views/spree/admin/plans/index.html.erb +70 -0
- data/app/views/spree/admin/plans/new.html.erb +22 -0
- data/app/views/spree/admin/recurrings/_form.html.erb +42 -0
- data/app/views/spree/admin/recurrings/destroy.js.erb +0 -0
- data/app/views/spree/admin/recurrings/edit.html.erb +23 -0
- data/app/views/spree/admin/recurrings/index.html.erb +48 -0
- data/app/views/spree/admin/recurrings/new.html.erb +22 -0
- data/app/views/spree/admin/subscription_events/index.html.erb +72 -0
- data/app/views/spree/admin/subscriptions/index.html.erb +76 -0
- data/app/views/spree/plans/index.html.erb +14 -0
- data/app/views/spree/subscriptions/new.html.erb +36 -0
- data/app/views/spree/subscriptions/show.html.erb +4 -0
- data/config/initializers/stripe.rb +2 -0
- data/config/locales/en.yml +43 -0
- data/config/routes.rb +24 -0
- data/db/migrate/20131119054112_create_spree_recurring.rb +13 -0
- data/db/migrate/20131119054212_create_spree_plan.rb +21 -0
- data/db/migrate/20131119054322_create_spree_subscription.rb +16 -0
- data/db/migrate/20131125123820_create_spree_subscription_events.rb +14 -0
- data/db/migrate/20131202110012_add_subscriber_role_to_spree_roles.rb +15 -0
- data/db/migrate/20140301141327_add_stripe_customer_id_to_spree_users.rb +6 -0
- data/db/migrate/20140303072857_add_default_to_spree_plans.rb +6 -0
- data/db/migrate/20140319092254_add_response_to_spree_subscription_events.rb +5 -0
- data/lib/generators/spree_account_recurring/install/install_generator.rb +31 -0
- data/lib/spree_account_recurring.rb +2 -0
- data/lib/spree_account_recurring/engine.rb +22 -0
- data/lib/spree_account_recurring/factories.rb +6 -0
- data/lib/spree_account_recurring/testing_support/ransack_date_search_helper.rb +125 -0
- metadata +188 -0
data/LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2013 [name of plugin creator]
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name Spree nor the names of its contributors may be used to
|
13
|
+
endorse or promote products derived from this software without specific
|
14
|
+
prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
17
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
18
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
19
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
20
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
21
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
23
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
26
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
Spree Account Recurring [](https://codeclimate.com/github/vinsol/spree-account-recurring) [](https://travis-ci.org/vinsol/spree-account-recurring)
|
2
|
+
=========================
|
3
|
+
|
4
|
+
Spree extension to manage recurring payments/subscriptions using [Stripe Payment Gateway](https://stripe.com/).
|
5
|
+
|
6
|
+
All plans and subscription scenarios are been managed as per [Stripe Docs](https://stripe.com/docs/api)
|
7
|
+
|
8
|
+
Installation
|
9
|
+
------------
|
10
|
+
|
11
|
+
Install `spree_account_recurring` by adding the following to your `Gemfile`:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'spree_account_recurring'
|
15
|
+
```
|
16
|
+
|
17
|
+
Bundle your dependencies and run the installation generator:
|
18
|
+
|
19
|
+
```shell
|
20
|
+
bundle
|
21
|
+
bundle exec rails g spree_account_recurring:install
|
22
|
+
```
|
23
|
+
|
24
|
+
Usage
|
25
|
+
-----
|
26
|
+
|
27
|
+
At Admin end this will add a configuration tab as "Recurring".
|
28
|
+
|
29
|
+
* Creating a Recurring Provider:
|
30
|
+
* Create a recurring using `Spree::Recurring::StripeRecurring` Provider and save
|
31
|
+
* Add secret key and public key provided by [stripe](https://stripe.com/) to this recurring.
|
32
|
+
|
33
|
+
* Creating Plans for Recurring Provider:
|
34
|
+
* Go to "Manage Plans" from Recurring edit page.
|
35
|
+
* Create a plan by specifying respective details. This will create the same plan on your stripe account.
|
36
|
+
* Only name can be updated for a plan.
|
37
|
+
|
38
|
+
One Recurring Provider can have multiple plans.
|
39
|
+
|
40
|
+
At Front end you can view all plans here: `http://your.domain.name/recurring/plans`
|
41
|
+
|
42
|
+
* Subscribe a plan:
|
43
|
+
* Click subscribe for any plan.
|
44
|
+
* Fill in credit card details and submit.
|
45
|
+
* This will create a customer in Stripe for user and subscribe that user respective to plan.
|
46
|
+
|
47
|
+
* Unsubscribe a plan:
|
48
|
+
* In plans page subscribed plan will be listed and from there user can unsubscribe from plan.
|
49
|
+
|
50
|
+
At Admin, all subscriptions can be seen under "Reports" -> "Subscriptions".
|
51
|
+
|
52
|
+
Stripe Webhook
|
53
|
+
--------------
|
54
|
+
|
55
|
+
Create a webhook at stripe with url `http://your.domain.name/recurring_hooks/handler` which will receive below mentioned stripe event hooks.
|
56
|
+
|
57
|
+
Events:
|
58
|
+
* `customer.subscription.deleted`
|
59
|
+
* `customer.subscription.created`
|
60
|
+
* `customer.subscription.updated`
|
61
|
+
* `invoice.payment_succeeded`
|
62
|
+
* `invoice.payment_failed`
|
63
|
+
* `charge.succeeded`
|
64
|
+
* `charge.failed`
|
65
|
+
* `charge.refunded`
|
66
|
+
* `charge.captured`
|
67
|
+
* `plan.created`
|
68
|
+
* `plan.updated`
|
69
|
+
* `plan.deleted`
|
70
|
+
|
71
|
+
These events can be viewed at admin in "Reports" -> "Subscription Events"
|
72
|
+
|
73
|
+
Testing
|
74
|
+
-------
|
75
|
+
|
76
|
+
Be sure to bundle your dependencies and then create a dummy test app for the specs to run against.
|
77
|
+
|
78
|
+
```shell
|
79
|
+
bundle
|
80
|
+
bundle exec rake test_app
|
81
|
+
bundle exec rspec spec
|
82
|
+
```
|
83
|
+
|
84
|
+
When testing your applications integration with this extension you may use it's factories.
|
85
|
+
Simply add this require statement to your spec_helper:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
require 'spree_account_recurring/factories'
|
89
|
+
```
|
90
|
+
|
91
|
+
Contributing
|
92
|
+
------------
|
93
|
+
|
94
|
+
1. Fork the repo.
|
95
|
+
2. Clone your repo.
|
96
|
+
3. Run `bundle install`.
|
97
|
+
4. Run `bundle exec rake test_app` to create the test application in `spec/test_app`.
|
98
|
+
5. Make your changes.
|
99
|
+
6. Ensure specs pass by running `bundle exec rspec spec`.
|
100
|
+
7. Submit your pull request.
|
101
|
+
|
102
|
+
|
103
|
+
Credits
|
104
|
+
-------
|
105
|
+
|
106
|
+
[](http://vinsol.com)
|
107
|
+
|
108
|
+
Copyright (c) 2014 [vinsol.com](http://vinsol.com "Ruby on Rails, iOS and Android developers"), released under the New MIT License
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require admin/spree_backend
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require store/spree_frontend
|
@@ -0,0 +1,53 @@
|
|
1
|
+
// Inspired by https://stripe.com/docs/stripe.js
|
2
|
+
|
3
|
+
mapCC = function(ccType){
|
4
|
+
if(ccType == 'MasterCard'){
|
5
|
+
return 'mastercard';
|
6
|
+
} else if(ccType == 'Visa'){
|
7
|
+
return 'visa';
|
8
|
+
} else if(ccType == 'American Express'){
|
9
|
+
return 'amex';
|
10
|
+
} else if(ccType == 'Discover'){
|
11
|
+
return 'discover';
|
12
|
+
} else if(ccType == 'Diners Club'){
|
13
|
+
return 'dinersclub';
|
14
|
+
} else if(ccType == 'JCB'){
|
15
|
+
return 'jcb';
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
$(document).ready(function(){
|
20
|
+
// For errors that happen later.
|
21
|
+
Spree.stripePaymentMethod.prepend("<div id='stripeError' class='errorExplanation' style='display:none'></div>")
|
22
|
+
|
23
|
+
$('.continue').on('click', function(){
|
24
|
+
$('#stripeError').hide();
|
25
|
+
if(Spree.stripePaymentMethod.is(':visible')){
|
26
|
+
expiration = $('.cardExpiry:visible').payment('cardExpiryVal')
|
27
|
+
params = {
|
28
|
+
number: $('.cardNumber:visible').val(),
|
29
|
+
cvc: $('.cardCode:visible').val(),
|
30
|
+
exp_month: expiration.month || 0,
|
31
|
+
exp_year: expiration.year || 0
|
32
|
+
};
|
33
|
+
|
34
|
+
Stripe.card.createToken(params, stripeResponseHandler);
|
35
|
+
return false;
|
36
|
+
}
|
37
|
+
});
|
38
|
+
});
|
39
|
+
|
40
|
+
stripeResponseHandler = function(status, response){
|
41
|
+
if(response.error){
|
42
|
+
$('#stripeError').html(response.error.message);
|
43
|
+
$('#stripeError').show();
|
44
|
+
} else {
|
45
|
+
Spree.stripePaymentMethod.find('#card_number, #card_expiry, #card_code').prop("disabled" , true);
|
46
|
+
Spree.stripePaymentMethod.find(".ccType").prop("disabled", false);
|
47
|
+
Spree.stripePaymentMethod.find(".ccType").val(mapCC(response.card.type))
|
48
|
+
token = response['id'];
|
49
|
+
// insert the token into the form so it gets submitted to the server
|
50
|
+
Spree.stripePaymentMethod.append("<input type='hidden' class='stripeToken' name='subscription[card_token]' value='" + token + "'/>");
|
51
|
+
Spree.stripePaymentMethod.parents("form").get(0).submit();
|
52
|
+
}
|
53
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
module RansackDateSearch
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def ransack_date_searchable(options={})
|
8
|
+
raise ArgumentError, "Hash expected, got #{options.class.name}" unless options.is_a?(Hash)
|
9
|
+
class_attribute :ransack_date_search_config, :ransack_date_search_col_ref, :ransack_date_search_param_gt, :ransack_date_search_param_lt
|
10
|
+
self.ransack_date_search_config = { date_col: "created_at" }.merge!(options)
|
11
|
+
# self.ransack_date_search_config[:before_action] = [ransack_date_search_config[:before_action]] unless ransack_date_search_config[:before_action].is_a?(Array)
|
12
|
+
self.ransack_date_search_col_ref = ransack_date_search_config[:date_col]
|
13
|
+
self.ransack_date_search_param_gt = "#{ransack_date_search_col_ref}_gt"
|
14
|
+
self.ransack_date_search_param_lt = "#{ransack_date_search_col_ref}_lt"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
included do
|
19
|
+
before_action :parse_ransack_date_search_param!, only: 'index'
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def parse_ransack_date_search_param!
|
25
|
+
params[:q] = {} unless params[:q]
|
26
|
+
parse_ransack_date_search_param_gt!
|
27
|
+
parse_ransack_date_search_param_lt!
|
28
|
+
params[:q][:s] ||= "#{ransack_date_search_col_ref} desc"
|
29
|
+
params[:q].delete_if{ |k, v| v.blank? }
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse_ransack_date_search_param_gt!
|
33
|
+
if params[:q][ransack_date_search_param_gt].blank?
|
34
|
+
params[:q][ransack_date_search_param_gt] = Time.current.beginning_of_month
|
35
|
+
else
|
36
|
+
params[:q][ransack_date_search_param_gt] = Time.zone.parse(params[:q][ransack_date_search_param_gt]).beginning_of_day rescue Time.current.beginning_of_month
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_ransack_date_search_param_lt!
|
41
|
+
if params[:q][ransack_date_search_param_lt].present?
|
42
|
+
params[:q][ransack_date_search_param_lt] = Time.zone.parse(params[:q][ransack_date_search_param_lt]).end_of_day rescue ""
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
class PlansController < Spree::Admin::BaseController
|
4
|
+
before_action :load_recurring
|
5
|
+
before_action :find_plan, :only => [:edit, :destroy, :update]
|
6
|
+
|
7
|
+
def index
|
8
|
+
@plans = Spree::Plan.undeleted.order('id desc')
|
9
|
+
end
|
10
|
+
|
11
|
+
def new
|
12
|
+
@plan = @recurring.plans.build
|
13
|
+
end
|
14
|
+
|
15
|
+
def create
|
16
|
+
@plan = @recurring.plans.build(plan_params)
|
17
|
+
if @plan.save_and_manage_api
|
18
|
+
flash[:notice] = 'Plan created successfully.'
|
19
|
+
redirect_to edit_admin_recurring_plan_path(@recurring, @plan)
|
20
|
+
else
|
21
|
+
render :new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def update
|
26
|
+
if @plan.save_and_manage_api(plan_params(:update))
|
27
|
+
flash[:notice] = 'Plan updated successfully.'
|
28
|
+
redirect_to edit_admin_recurring_plan_path(@recurring, @plan)
|
29
|
+
else
|
30
|
+
render :edit
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def destroy
|
35
|
+
@plan.restrictive_destroy_with_api
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def load_recurring
|
41
|
+
unless @recurring = Spree::Recurring.undeleted.where(id: params[:recurring_id]).first
|
42
|
+
flash[:error] = "Recurring not found."
|
43
|
+
redirect_to admin_recurrings_path
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def plan_params(action=:create)
|
48
|
+
if action == :create
|
49
|
+
params.require(:plan).permit(:name, :trial_period_days, :interval, :currency, :amount, :active, :interval_count, :default)
|
50
|
+
else
|
51
|
+
params.require(:plan).permit(:name, :active, :default)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def find_plan
|
56
|
+
unless @plan = @recurring.plans.undeleted.where(id: params[:id]).first
|
57
|
+
flash[:error] = "Plan not found."
|
58
|
+
redirect_to admin_recurring_plans_path(@recurring)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
class RecurringsController < Spree::Admin::BaseController
|
4
|
+
before_action :find_recurring, :only => [:edit, :update, :destroy]
|
5
|
+
before_action :build_recurring, :only => :create
|
6
|
+
|
7
|
+
def index
|
8
|
+
@recurrings = Spree::Recurring.undeleted.order('id desc')
|
9
|
+
end
|
10
|
+
|
11
|
+
def new
|
12
|
+
@recurring = Spree::Recurring.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def create
|
16
|
+
if @recurring.save
|
17
|
+
flash[:notice] = "Recurring created succesfully."
|
18
|
+
redirect_to edit_admin_recurring_url(@recurring)
|
19
|
+
else
|
20
|
+
render :new
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def update
|
25
|
+
if @recurring.update_attributes(recurring_params(:update))
|
26
|
+
flash[:notice] = "Recurring updated succesfully."
|
27
|
+
redirect_to edit_admin_recurring_url(@recurring)
|
28
|
+
else
|
29
|
+
render :edit
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy
|
34
|
+
@recurring.restrictive_destroy
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def find_recurring
|
40
|
+
unless @recurring = Spree::Recurring.undeleted.where(id: params[:id]).first
|
41
|
+
flash[:error] = "Recurring not found."
|
42
|
+
respond_to do |format|
|
43
|
+
format.html {redirect_to admin_recurrings_url}
|
44
|
+
format.js { }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def recurring_params(action=:create)
|
50
|
+
if action == :create
|
51
|
+
params.require(:recurring).permit(:name, :type, :description, :active)
|
52
|
+
else
|
53
|
+
params.require(:recurring).permit(:name, :description, :active).merge(preference_params)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_recurring
|
58
|
+
@recurring = recurring_params.delete(:type).constantize.new(recurring_params)
|
59
|
+
end
|
60
|
+
|
61
|
+
def preference_params
|
62
|
+
params[ActiveModel::Naming.param_key(@recurring)]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
class SubscriptionEventsController < Spree::Admin::BaseController
|
4
|
+
include RansackDateSearch
|
5
|
+
ransack_date_searchable date_col: 'created_at'
|
6
|
+
|
7
|
+
def index
|
8
|
+
@search = Spree::SubscriptionEvent.ransack(params[:q])
|
9
|
+
@subscription_events = @search.result.includes(subscription: { plan: :recurring }).references(subscription: { plan: :recurring }).page(params[:page]).per(15)
|
10
|
+
respond_with(@subscription_events)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
class SubscriptionsController < Spree::Admin::BaseController
|
4
|
+
include RansackDateSearch
|
5
|
+
ransack_date_searchable date_col: 'subscribed_at'
|
6
|
+
|
7
|
+
def index
|
8
|
+
@search = Spree::Subscription.ransack(params[:q])
|
9
|
+
@subscriptions = @search.result.includes(plan: :recurring).references(plan: :recurring).page(params[:page]).per(15)
|
10
|
+
respond_with(@subscriptions)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Spree
|
2
|
+
class RecurringHooksController < BaseController
|
3
|
+
skip_before_filter :verify_authenticity_token
|
4
|
+
|
5
|
+
before_action :authenticate_webhook
|
6
|
+
before_action :find_subscription
|
7
|
+
|
8
|
+
respond_to :json
|
9
|
+
|
10
|
+
def handler
|
11
|
+
@subscription_event = @subscription.events.build(subscription_event_params)
|
12
|
+
if @subscription_event.save
|
13
|
+
render_status_ok
|
14
|
+
else
|
15
|
+
render_status_failure
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def event
|
22
|
+
@event ||= (Rails.env.production? ? params.deep_dup : params.deep_dup[:recurring_hook])
|
23
|
+
end
|
24
|
+
|
25
|
+
def authenticate_webhook
|
26
|
+
render_status_ok if event.blank? || (event[:livemode] != Rails.env.production?) || (!Spree::Recurring::StripeRecurring::WEBHOOKS.include?(event[:type]))
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_subscription
|
30
|
+
render_status_ok unless @subscription = Spree::User.find_by(stripe_customer_id: event[:data][:object][:customer]).subscription
|
31
|
+
end
|
32
|
+
|
33
|
+
def retrieve_api_event
|
34
|
+
@event = @subscription.provider.retrieve_event(event[:id])
|
35
|
+
end
|
36
|
+
|
37
|
+
def subscription_event_params
|
38
|
+
if retrieve_api_event && event.data.object.customer == @subscription.user.stripe_customer_id
|
39
|
+
{ event_id: event.id, request_type: event.type, response: event.to_json }
|
40
|
+
else
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def render_status_ok
|
46
|
+
render text: '', status: 200
|
47
|
+
end
|
48
|
+
|
49
|
+
def render_status_failure
|
50
|
+
render text: '', status: 403
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|