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: a8b46b9f926b8ab975a3e81e57164dc222f14a36
4
- data.tar.gz: 4107592428dbfde1afe5247d6a813923f5a90f1d
3
+ metadata.gz: b754cd5d2aeb5e4000ee3b4c2fc1c16278f320e3
4
+ data.tar.gz: 0270f46b3bbef65baa6dbc4ac7167d8ca6871d05
5
5
  SHA512:
6
- metadata.gz: d65f51de361cb78dcc07dc27cae84ae0e11a1946240e5cf5bdb9638e2e7ba6482d8eda7156df9659304f1423ec6f2313515068ce7c0400b407f77897c0533d02
7
- data.tar.gz: b2e93919ec0839a2cbb1b84e343cf3a0a0ce20c6b7b33adf0e08d046eb961bad72783afc44e0312c041011fb5881a53619ab0873380b897987763e8aea47abee
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 :except => [:stripe]
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) and return) if (params[:livemode] == false && Rails.env.production?) || params[:object] != 'event' || params[:id].blank?
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) and return)
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' ; stripe_customer_created(@event)
17
- when 'customer.deleted' ; stripe_customer_deleted(@event)
18
- when 'customer.subscription.created' ; stripe_subscription_created(@event)
19
- when 'customer.subscription.deleted' ; stripe_subscription_deleted(@event)
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(:email => stripe_customer.email).first
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(:email => stripe_customer.email).first
46
+ user = ::User.where(email: stripe_customer.email).first
46
47
 
47
48
  if user.present?
48
- customer = Effective::Customer.where(:user_id => user.id).first
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(:stripe_customer_id => stripe_subscription.customer).first
56
+ @customer = Effective::Customer.where(stripe_customer_id: stripe_subscription.customer).first
56
57
 
57
58
  if @customer.present?
58
- subscription = @customer.subscriptions.where(:stripe_plan_id => stripe_subscription.plan.id).first_or_initialize
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(:stripe_customer_id => stripe_subscription.customer).first
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
@@ -1,3 +1,3 @@
1
1
  module EffectiveOrders
2
- VERSION = '1.3.13'.freeze
2
+ VERSION = '1.4.0'.freeze
3
3
  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
- before(:each) do
49
- buyer.update_attributes(:stripe_customer_id => event.data.object.customer)
50
- end
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.3.13
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-24 00:00:00.000000000 Z
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