effective_orders 1.3.13 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b754cd5d2aeb5e4000ee3b4c2fc1c16278f320e3
|
4
|
+
data.tar.gz: 0270f46b3bbef65baa6dbc4ac7167d8ca6871d05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84b348ed34d246acb8b47b4c71efe6a7e0feb58814aaf5e1ed4cf3228f4c6bdea625948cd1a519d6e4cbba7c1b792c2689d431ecf56e9d9e7690531168538faf
|
7
|
+
data.tar.gz: 43466c0a0104dc78c678ec8e458ca30d95acf73796a19e934c6df44b5aef7354dfc789d98954e75aa7e388d972fe711f0b2a6b787fdb09e6fc75e93601673b77
|
@@ -1,22 +1,23 @@
|
|
1
1
|
module Effective
|
2
2
|
class WebhooksController < ApplicationController
|
3
|
-
protect_from_forgery :
|
3
|
+
protect_from_forgery except: [:stripe]
|
4
4
|
skip_authorization_check if defined?(CanCan)
|
5
5
|
|
6
6
|
# Webhook from stripe
|
7
7
|
def stripe
|
8
|
-
(head(:ok)
|
8
|
+
(head(:ok) && return) if (params[:livemode] == false && Rails.env.production?) || params[:object] != 'event' || params[:id].blank?
|
9
9
|
|
10
10
|
# Dont trust the POST, and instead request the actual event from Stripe
|
11
|
-
@event = Stripe::Event.retrieve(params[:id]) rescue (head(:ok)
|
11
|
+
@event = Stripe::Event.retrieve(params[:id]) rescue (head(:ok) && return)
|
12
12
|
|
13
13
|
Effective::Customer.transaction do
|
14
14
|
begin
|
15
15
|
case @event.type
|
16
|
-
when 'customer.created'
|
17
|
-
when 'customer.deleted'
|
18
|
-
when 'customer.subscription.created'
|
19
|
-
when 'customer.subscription.deleted'
|
16
|
+
when 'customer.created' then stripe_customer_created(@event)
|
17
|
+
when 'customer.deleted' then stripe_customer_deleted(@event)
|
18
|
+
when 'customer.subscription.created' then stripe_subscription_created(@event)
|
19
|
+
when 'customer.subscription.deleted' then stripe_subscription_deleted(@event)
|
20
|
+
when 'invoice.payment_succeeded' then invoice_payment_succeeded(@event)
|
20
21
|
end
|
21
22
|
rescue => e
|
22
23
|
Rails.logger.info "Stripe Webhook Error: #{e.message}"
|
@@ -31,7 +32,7 @@ module Effective
|
|
31
32
|
|
32
33
|
def stripe_customer_created(event)
|
33
34
|
stripe_customer = event.data.object
|
34
|
-
user = ::User.where(:
|
35
|
+
user = ::User.where(email: stripe_customer.email).first
|
35
36
|
|
36
37
|
if user.present?
|
37
38
|
customer = Effective::Customer.for_user(user) # This is a first_or_create
|
@@ -42,20 +43,20 @@ module Effective
|
|
42
43
|
|
43
44
|
def stripe_customer_deleted(event)
|
44
45
|
stripe_customer = event.data.object
|
45
|
-
user = ::User.where(:
|
46
|
+
user = ::User.where(email: stripe_customer.email).first
|
46
47
|
|
47
48
|
if user.present?
|
48
|
-
customer = Effective::Customer.where(:
|
49
|
+
customer = Effective::Customer.where(user_id: user.id).first
|
49
50
|
customer.destroy! if customer
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
53
54
|
def stripe_subscription_created(event)
|
54
55
|
stripe_subscription = event.data.object
|
55
|
-
@customer = Effective::Customer.where(:
|
56
|
+
@customer = Effective::Customer.where(stripe_customer_id: stripe_subscription.customer).first
|
56
57
|
|
57
58
|
if @customer.present?
|
58
|
-
subscription = @customer.subscriptions.where(:
|
59
|
+
subscription = @customer.subscriptions.where(stripe_plan_id: stripe_subscription.plan.id).first_or_initialize
|
59
60
|
|
60
61
|
subscription.stripe_subscription_id = stripe_subscription.id
|
61
62
|
subscription.stripe_plan_id = (stripe_subscription.plan.id rescue nil)
|
@@ -75,12 +76,43 @@ module Effective
|
|
75
76
|
|
76
77
|
def stripe_subscription_deleted(event)
|
77
78
|
stripe_subscription = event.data.object
|
78
|
-
customer = Effective::Customer.where(:
|
79
|
+
@customer = Effective::Customer.where(stripe_customer_id: stripe_subscription.customer).first
|
79
80
|
|
80
|
-
if customer.present?
|
81
|
-
customer.subscriptions.find { |subscription| subscription.stripe_plan_id == stripe_subscription.plan.id }.try(:destroy)
|
81
|
+
if @customer.present?
|
82
|
+
@customer.subscriptions.find { |subscription| subscription.stripe_plan_id == stripe_subscription.plan.id }.try(:destroy)
|
83
|
+
subscription_deleted_callback(event)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def invoice_payment_succeeded(event)
|
88
|
+
@customer = Effective::Customer.where(stripe_customer_id: event.data.object.customer).first
|
89
|
+
|
90
|
+
check_for_subscription_renewal(event) if @customer.present?
|
91
|
+
end
|
92
|
+
|
93
|
+
def check_for_subscription_renewal(event)
|
94
|
+
invoice_payment = event.data.object
|
95
|
+
subscription_payments = invoice_payment.lines.select { |line_item| line_item.type == 'subscription' }
|
96
|
+
|
97
|
+
if subscription_payments.present?
|
98
|
+
customer = Stripe::Customer.retrieve(invoice_payment.customer)
|
99
|
+
subscription_payments.each do |subscription_payment|
|
100
|
+
subscription_renewed_callback(event) if stripe_subscription_renewed?(customer, subscription_payment)
|
101
|
+
end
|
82
102
|
end
|
83
103
|
end
|
84
104
|
|
105
|
+
def stripe_subscription_renewed?(customer, subscription_payment)
|
106
|
+
subscription = customer.subscriptions.retrieve(subscription_payment.id) rescue nil # API client raises error when object not found
|
107
|
+
subscription.present? && subscription.status == 'active' && subscription.start < (subscription_payment.period.start - 1.day)
|
108
|
+
end
|
109
|
+
|
110
|
+
def subscription_deleted_callback(_event)
|
111
|
+
# Can be overridden in Effective::WebhooksController within a Rails application
|
112
|
+
end
|
113
|
+
|
114
|
+
def subscription_renewed_callback(_event)
|
115
|
+
# Can be overridden in Effective::WebhooksController within a Rails application
|
116
|
+
end
|
85
117
|
end
|
86
118
|
end
|
@@ -9,10 +9,11 @@ describe Effective::WebhooksController do
|
|
9
9
|
let(:order) { FactoryGirl.create(:order) }
|
10
10
|
let(:buyer) { Effective::Customer.for_user(order.user) }
|
11
11
|
|
12
|
-
let(:event) { StripeMock.mock_webhook_event('customer.subscription.created') }
|
13
12
|
let(:event_hash) { event.to_hash }
|
14
13
|
|
15
14
|
describe '#stripe' do
|
15
|
+
let(:event) { StripeMock.mock_webhook_event('customer.subscription.created') }
|
16
|
+
|
16
17
|
it 'retrieves the real event from Stripe based on passed ID' do
|
17
18
|
Stripe::Event.should_receive(:retrieve).with(event_hash[:id])
|
18
19
|
post :stripe, event_hash
|
@@ -41,13 +42,12 @@ describe Effective::WebhooksController do
|
|
41
42
|
assigns(:event).should eq nil
|
42
43
|
response.code.should eq '200'
|
43
44
|
end
|
44
|
-
|
45
45
|
end
|
46
46
|
|
47
47
|
describe '#stripe.subscription_created' do
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
let(:event) { StripeMock.mock_webhook_event('customer.subscription.created') }
|
49
|
+
|
50
|
+
before { buyer.update_attributes(stripe_customer_id: event.data.object.customer) }
|
51
51
|
|
52
52
|
it 'assigns the existing customer, if exists' do
|
53
53
|
post :stripe, event_hash
|
@@ -73,7 +73,98 @@ describe Effective::WebhooksController do
|
|
73
73
|
|
74
74
|
assigns(:order).present?.should eq false
|
75
75
|
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#stripe.subscription_deleted' do
|
79
|
+
let(:event) { StripeMock.mock_webhook_event('customer.subscription.deleted') }
|
80
|
+
let!(:subscription) { FactoryGirl.create(:subscription, customer_id: buyer.id) }
|
81
|
+
|
82
|
+
context 'when customer exists' do
|
83
|
+
before do
|
84
|
+
buyer.update_attributes(stripe_customer_id: event.data.object.customer)
|
85
|
+
subscription.stripe_plan_id = event.data.object.plan.id
|
86
|
+
subscription.save(validate: false)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'assigns the existing customer' do
|
90
|
+
post :stripe, event_hash
|
91
|
+
assigns(:customer).should eq buyer
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should destroy customer subscription' do
|
95
|
+
expect { post :stripe, event_hash }.to change { buyer.subscriptions.count }.from(1).to(0)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should invoke subscription_deleted_callback' do
|
99
|
+
controller.should_receive(:subscription_deleted_callback).with(kind_of(Stripe::Event)).once
|
100
|
+
post :stripe, event_hash
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when customer does not exist' do
|
105
|
+
it 'should not destroy any of subscriptions' do
|
106
|
+
expect { post :stripe, event_hash }.not_to change { Effective::Subscription.count }
|
107
|
+
end
|
76
108
|
|
109
|
+
it 'should not invoke subscription_deleted_callback' do
|
110
|
+
controller.should_not_receive(:subscription_deleted_callback)
|
111
|
+
post :stripe, event_hash
|
112
|
+
end
|
113
|
+
end
|
77
114
|
end
|
78
115
|
|
116
|
+
describe '#stripe.invoice_payment_succeeded' do
|
117
|
+
let(:event) { StripeMock.mock_webhook_event('invoice.payment_succeeded') }
|
118
|
+
|
119
|
+
context 'when customer exists' do
|
120
|
+
before { buyer.update_attributes(stripe_customer_id: event.data.object.customer) }
|
121
|
+
|
122
|
+
context 'when subscription payments present' do
|
123
|
+
context 'with renewals' do
|
124
|
+
let(:subscription_mock) { double('subscription', status: 'active', start: 1383672652) }
|
125
|
+
let(:subscriptions) { double('subscriptions', retrieve: subscription_mock) }
|
126
|
+
|
127
|
+
before { Stripe::Customer.should_receive(:retrieve).and_return(double('customer', subscriptions: subscriptions)) }
|
128
|
+
|
129
|
+
it 'assigns the existing customer, if exists' do
|
130
|
+
post :stripe, event_hash
|
131
|
+
assigns(:customer).should eq buyer
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should invoke subscription_renewed_callback' do
|
135
|
+
controller.should_receive(:subscription_renewed_callback).with(kind_of(Stripe::Event)).once
|
136
|
+
post :stripe, event_hash
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'without renewals' do
|
141
|
+
let(:subscription_mock) { double('subscription', status: 'active', start: 1383759053) } # start and period.start are equal
|
142
|
+
let(:subscriptions) { double('subscriptions', retrieve: subscription_mock) }
|
143
|
+
|
144
|
+
before { Stripe::Customer.should_receive(:retrieve).and_return(double('customer', subscriptions: subscriptions)) }
|
145
|
+
|
146
|
+
it 'should not invoke subscription_renewed_callback' do
|
147
|
+
controller.should_not_receive(:subscription_renewed_callback)
|
148
|
+
post :stripe, event_hash
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'when no subscription payments' do
|
154
|
+
let(:event) { StripeMock.mock_webhook_event('invoice.payment_succeeded.without_renewals') }
|
155
|
+
|
156
|
+
it 'should not invoke subscription_renewed_callback' do
|
157
|
+
controller.should_not_receive(:subscription_renewed_callback)
|
158
|
+
post :stripe, event_hash
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when customer does not exist' do
|
164
|
+
it 'should not invoke subscription_renewed_callback' do
|
165
|
+
controller.should_not_receive(:subscription_renewed_callback)
|
166
|
+
post :stripe, event_hash
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
79
170
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
{
|
2
|
+
"created": 1326853478,
|
3
|
+
"livemode": false,
|
4
|
+
"id": "evt_00000000000000",
|
5
|
+
"type": "invoice.payment_succeeded",
|
6
|
+
"object": "event",
|
7
|
+
"data": {
|
8
|
+
"object": {
|
9
|
+
"date": 1394018368,
|
10
|
+
"id": "in_00000000000000",
|
11
|
+
"period_start": 1394018368,
|
12
|
+
"period_end": 1394018368,
|
13
|
+
"lines": {
|
14
|
+
"object": "list",
|
15
|
+
"count": 3,
|
16
|
+
"url": "/v1/invoices/in_00000000000000/lines",
|
17
|
+
"data": [
|
18
|
+
{
|
19
|
+
"id": "ii_00000000000000",
|
20
|
+
"object": "line_item",
|
21
|
+
"type": "invoiceitem",
|
22
|
+
"livemode": false,
|
23
|
+
"amount": 19000,
|
24
|
+
"currency": "usd",
|
25
|
+
"proration": true,
|
26
|
+
"period": {
|
27
|
+
"start": 1393765661,
|
28
|
+
"end": 1393765661
|
29
|
+
},
|
30
|
+
"quantity": null,
|
31
|
+
"plan": null,
|
32
|
+
"description": "Remaining time on Platinum after 02 Mar 2014",
|
33
|
+
"metadata": {}
|
34
|
+
},
|
35
|
+
{
|
36
|
+
"id": "ii_00000000000001",
|
37
|
+
"object": "line_item",
|
38
|
+
"type": "invoiceitem",
|
39
|
+
"livemode": false,
|
40
|
+
"amount": -9000,
|
41
|
+
"currency": "usd",
|
42
|
+
"proration": true,
|
43
|
+
"period": {
|
44
|
+
"start": 1393765661,
|
45
|
+
"end": 1393765661
|
46
|
+
},
|
47
|
+
"quantity": null,
|
48
|
+
"plan": null,
|
49
|
+
"description": "Unused time on Gold after 05 Mar 2014",
|
50
|
+
"metadata": {}
|
51
|
+
}
|
52
|
+
]
|
53
|
+
},
|
54
|
+
"subtotal": 30000,
|
55
|
+
"total": 30000,
|
56
|
+
"customer": "cus_00000000000000",
|
57
|
+
"object": "invoice",
|
58
|
+
"attempted": true,
|
59
|
+
"closed": true,
|
60
|
+
"paid": true,
|
61
|
+
"livemode": false,
|
62
|
+
"attempt_count": 1,
|
63
|
+
"amount_due": 0,
|
64
|
+
"currency": "usd",
|
65
|
+
"starting_balance": 0,
|
66
|
+
"ending_balance": 0,
|
67
|
+
"next_payment_attempt": null,
|
68
|
+
"charge": "ch_00000000000000",
|
69
|
+
"discount": null,
|
70
|
+
"application_fee": null,
|
71
|
+
"subscription": "su_00000000000000",
|
72
|
+
"metadata": {},
|
73
|
+
"description": null
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_orders
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -463,6 +463,7 @@ files:
|
|
463
463
|
- spec/dummy/public/422.html
|
464
464
|
- spec/dummy/public/500.html
|
465
465
|
- spec/dummy/public/favicon.ico
|
466
|
+
- spec/fixtures/stripe_webhooks/invoice.payment_succeeded.without_renewals.json
|
466
467
|
- spec/helpers/effective_orders_helper_spec.rb
|
467
468
|
- spec/models/acts_as_purchasable_spec.rb
|
468
469
|
- spec/models/customer_spec.rb
|
@@ -545,6 +546,7 @@ test_files:
|
|
545
546
|
- spec/dummy/public/favicon.ico
|
546
547
|
- spec/dummy/Rakefile
|
547
548
|
- spec/dummy/README.rdoc
|
549
|
+
- spec/fixtures/stripe_webhooks/invoice.payment_succeeded.without_renewals.json
|
548
550
|
- spec/helpers/effective_orders_helper_spec.rb
|
549
551
|
- spec/models/acts_as_purchasable_spec.rb
|
550
552
|
- spec/models/customer_spec.rb
|