effective_orders 1.3.13 → 1.4.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
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
|