solidus_stripe 3.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +5 -0
  4. data/CHANGELOG.md +58 -2
  5. data/Gemfile +7 -0
  6. data/LICENSE +2 -2
  7. data/README.md +26 -8
  8. data/Rakefile +1 -1
  9. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-cart-page-checkout.js +42 -9
  10. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment-intents.js +3 -2
  11. data/app/assets/javascripts/spree/frontend/solidus_stripe/stripe-payment-request-button-shared.js +56 -20
  12. data/app/controllers/solidus_stripe/intents_controller.rb +23 -18
  13. data/app/decorators/models/spree/refund_decorator.rb +9 -0
  14. data/app/models/solidus_stripe/address_from_params_service.rb +5 -2
  15. data/app/models/solidus_stripe/create_intents_payment_service.rb +113 -0
  16. data/app/models/spree/payment_method/stripe_credit_card.rb +16 -1
  17. data/bin/r +13 -0
  18. data/bin/rake +7 -0
  19. data/bin/sandbox +84 -0
  20. data/bin/sandbox_rails +18 -0
  21. data/bin/setup +1 -1
  22. data/config/routes.rb +4 -1
  23. data/lib/generators/solidus_stripe/install/install_generator.rb +7 -3
  24. data/lib/solidus_stripe/engine.rb +2 -2
  25. data/lib/solidus_stripe/factories.rb +4 -0
  26. data/lib/solidus_stripe/version.rb +1 -1
  27. data/lib/views/frontend/spree/checkout/payment/v3/_form_elements.html.erb +0 -1
  28. data/solidus_stripe.gemspec +34 -37
  29. data/spec/features/stripe_checkout_spec.rb +101 -48
  30. data/spec/models/solidus_stripe/address_from_params_service_spec.rb +19 -5
  31. data/spec/models/solidus_stripe/create_intents_payment_service_spec.rb +127 -0
  32. data/spec/models/spree/payment_method/stripe_credit_card_spec.rb +44 -1
  33. data/spec/spec_helper.rb +4 -1
  34. metadata +23 -16
  35. data/LICENSE.md +0 -26
  36. data/app/models/solidus_stripe/create_intents_order_service.rb +0 -70
@@ -217,7 +217,7 @@ RSpec.describe "Stripe checkout", type: :feature do
217
217
  end
218
218
  end
219
219
 
220
- context 'when using Stripe V3 API libarary with Elements', :js do
220
+ context 'when using Stripe V3 API library with Elements', :js do
221
221
  let(:preferred_v3_elements) { true }
222
222
  let(:preferred_v3_intents) { false }
223
223
 
@@ -240,60 +240,95 @@ RSpec.describe "Stripe checkout", type: :feature do
240
240
  expect(page).to have_content("Your order has been processed successfully")
241
241
  end
242
242
 
243
- it "can re-use saved cards" do
244
- within_frame find('#card_number iframe') do
245
- '4242 4242 4242 4242'.split('').each { |n| find_field('cardnumber').native.send_keys(n) }
246
- end
247
- within_frame(find '#card_cvc iframe') { fill_in 'cvc', with: '123' }
248
- within_frame(find '#card_expiry iframe') do
249
- '0132'.split('').each { |n| find_field('exp-date').native.send_keys(n) }
250
- end
251
- click_button "Save and Continue"
252
- expect(page).to have_current_path("/checkout/confirm")
253
- click_button "Place Order"
254
- expect(page).to have_content("Your order has been processed successfully")
243
+ context "when reusing saved cards" do
244
+ stub_authorization!
255
245
 
256
- visit spree.root_path
257
- click_link "DL-44"
258
- click_button "Add To Cart"
246
+ it "completes the order, captures the payment and cancels the order" do
247
+ within_frame find('#card_number iframe') do
248
+ '4242 4242 4242 4242'.split('').each { |n| find_field('cardnumber').native.send_keys(n) }
249
+ end
250
+ within_frame(find '#card_cvc iframe') { fill_in 'cvc', with: '123' }
251
+ within_frame(find '#card_expiry iframe') do
252
+ '0132'.split('').each { |n| find_field('exp-date').native.send_keys(n) }
253
+ end
254
+ click_button "Save and Continue"
255
+ expect(page).to have_current_path("/checkout/confirm")
256
+ click_button "Place Order"
257
+ expect(page).to have_content("Your order has been processed successfully")
259
258
 
260
- expect(page).to have_current_path("/cart")
261
- click_button "Checkout"
259
+ visit spree.root_path
260
+ click_link "DL-44"
261
+ click_button "Add To Cart"
262
262
 
263
- # Address
264
- expect(page).to have_current_path("/checkout/address")
263
+ expect(page).to have_current_path("/cart")
264
+ click_button "Checkout"
265
265
 
266
- within("#billing") do
267
- fill_in_name
268
- fill_in "Street Address", with: "YT-1300"
269
- fill_in "City", with: "Mos Eisley"
270
- select "United States of America", from: "Country"
271
- select country.states.first.name, from: "order_bill_address_attributes_state_id"
272
- fill_in "Zip", with: "12010"
273
- fill_in "Phone", with: "(555) 555-5555"
274
- end
275
- click_on "Save and Continue"
266
+ # Address
267
+ expect(page).to have_current_path("/checkout/address")
276
268
 
277
- # Delivery
278
- expect(page).to have_current_path("/checkout/delivery")
279
- expect(page).to have_content("UPS Ground")
280
- click_on "Save and Continue"
269
+ within("#billing") do
270
+ fill_in_name
271
+ fill_in "Street Address", with: "YT-1300"
272
+ fill_in "City", with: "Mos Eisley"
273
+ select "United States of America", from: "Country"
274
+ select country.states.first.name, from: "order_bill_address_attributes_state_id"
275
+ fill_in "Zip", with: "12010"
276
+ fill_in "Phone", with: "(555) 555-5555"
277
+ end
278
+ click_on "Save and Continue"
281
279
 
282
- # Payment
283
- expect(page).to have_current_path("/checkout/payment")
284
- choose "Use an existing card on file"
285
- click_button "Save and Continue"
280
+ # Delivery
281
+ expect(page).to have_current_path("/checkout/delivery")
282
+ expect(page).to have_content("UPS Ground")
283
+ click_on "Save and Continue"
286
284
 
287
- # Confirm
288
- expect(page).to have_current_path("/checkout/confirm")
289
- click_button "Place Order"
290
- expect(page).to have_content("Your order has been processed successfully")
285
+ # Payment
286
+ expect(page).to have_current_path("/checkout/payment")
287
+ choose "Use an existing card on file"
288
+ click_button "Save and Continue"
289
+
290
+ # Confirm
291
+ expect(page).to have_current_path("/checkout/confirm")
292
+ click_button "Place Order"
293
+ expect(page).to have_content("Your order has been processed successfully")
294
+
295
+ Spree::Order.complete.each do |order|
296
+ # Capture in backend
297
+
298
+ visit spree.admin_path
299
+
300
+ expect(page).to have_selector("#listing_orders tbody tr", count: 2)
301
+
302
+ click_link order.number
303
+
304
+ click_link "Payments"
305
+ find(".fa-capture").click
306
+
307
+ expect(page).to have_content "Payment Updated"
308
+ expect(find("table#payments")).to have_content "Completed"
309
+
310
+ # Order cancel, after capture
311
+ click_link "Cart"
312
+
313
+ within "#sidebar" do
314
+ expect(page).to have_content "Completed"
315
+ end
316
+
317
+ find('input[value="Cancel"]').click
318
+
319
+ expect(page).to have_content "Order canceled"
320
+
321
+ within "#sidebar" do
322
+ expect(page).to have_content "Canceled"
323
+ end
324
+ end
325
+ end
291
326
  end
292
327
 
293
328
  it_behaves_like "Stripe Elements invalid payments"
294
329
  end
295
330
 
296
- context "when using Stripe V3 API libarary with Intents", :js do
331
+ context "when using Stripe V3 API library with Intents", :js do
297
332
  let(:preferred_v3_elements) { false }
298
333
  let(:preferred_v3_intents) { true }
299
334
 
@@ -400,8 +435,9 @@ RSpec.describe "Stripe checkout", type: :feature do
400
435
  click_button "Place Order"
401
436
  expect(page).to have_content("Your order has been processed successfully")
402
437
 
403
- # Capture in backend
404
438
  Spree::Order.complete.each do |order|
439
+ # Capture in backend
440
+
405
441
  visit spree.admin_path
406
442
 
407
443
  expect(page).to have_selector("#listing_orders tbody tr", count: 2)
@@ -413,6 +449,21 @@ RSpec.describe "Stripe checkout", type: :feature do
413
449
 
414
450
  expect(page).to have_content "Payment Updated"
415
451
  expect(find("table#payments")).to have_content "Completed"
452
+
453
+ # Order cancel, after capture
454
+ click_link "Cart"
455
+
456
+ within "#sidebar" do
457
+ expect(page).to have_content "Completed"
458
+ end
459
+
460
+ find('input[value="Cancel"]').click
461
+
462
+ expect(page).to have_content "Order canceled"
463
+
464
+ within "#sidebar" do
465
+ expect(page).to have_content "Canceled"
466
+ end
416
467
  end
417
468
  end
418
469
  end
@@ -487,9 +538,11 @@ RSpec.describe "Stripe checkout", type: :feature do
487
538
  end
488
539
 
489
540
  def within_3d_secure_modal
490
- within_frame "__privateStripeFrame10" do
491
- within_frame "challengeFrame" do
492
- yield
541
+ within_frame "__privateStripeFrame11" do
542
+ within_frame "__stripeJSChallengeFrame" do
543
+ within_frame "acsFrame" do
544
+ yield
545
+ end
493
546
  end
494
547
  end
495
548
  end
@@ -505,7 +558,7 @@ RSpec.describe "Stripe checkout", type: :feature do
505
558
  click_button "Save and Continue"
506
559
 
507
560
  within_3d_secure_modal do
508
- expect(page).to have_content '$19.99 using 3D Secure'
561
+ expect(page).to have_content '$19.99 USD using 3D Secure'
509
562
 
510
563
  click_button 'Complete authentication'
511
564
  end
@@ -14,7 +14,8 @@ RSpec.describe SolidusStripe::AddressFromParamsService do
14
14
  recipient: 'Clark Kent',
15
15
  city: 'Metropolis',
16
16
  postalCode: '12345',
17
- addressLine: [ '12, Lincoln Rd']
17
+ addressLine: [ '12, Lincoln Rd'],
18
+ phone: '555-555-0199'
18
19
  }
19
20
  end
20
21
 
@@ -39,7 +40,8 @@ RSpec.describe SolidusStripe::AddressFromParamsService do
39
40
  firstname: 'Clark',
40
41
  lastname: 'Kent',
41
42
  address1: params[:addressLine].first,
42
- address2: nil
43
+ address2: nil,
44
+ phone: '555-555-0199'
43
45
  )
44
46
  end
45
47
 
@@ -50,11 +52,23 @@ RSpec.describe SolidusStripe::AddressFromParamsService do
50
52
 
51
53
  context "when no user's address is compatible with the params" do
52
54
  before do
53
- user.addresses << create(:address)
55
+ user.addresses << create(:address, state: state)
54
56
  end
55
57
 
56
- it "returns a non-persisted address model" do
57
- expect(subject).to be_new_record
58
+ it "returns a non-persisted valid address" do
59
+ aggregate_failures do
60
+ expect(subject).to be_new_record
61
+ expect(subject).to be_valid
62
+ expect(subject.state).to eq state
63
+ end
64
+ end
65
+
66
+ context "when the region is the state name" do
67
+ before { params[:region] = state.name }
68
+
69
+ it "still can set the address state attribute" do
70
+ expect(subject.state).to eq state
71
+ end
58
72
  end
59
73
  end
60
74
  end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe SolidusStripe::CreateIntentsPaymentService do
6
+ let(:service) { described_class.new(intent_id, stripe, controller) }
7
+
8
+ let(:stripe) {
9
+ Spree::PaymentMethod::StripeCreditCard.create!(
10
+ name: "Stripe",
11
+ preferred_secret_key: "sk_test_VCZnDv3GLU15TRvn8i2EsaAN",
12
+ preferred_publishable_key: "pk_test_Cuf0PNtiAkkMpTVC2gwYDMIg",
13
+ preferred_v3_elements: false,
14
+ preferred_v3_intents: true
15
+ )
16
+ }
17
+
18
+ let(:order) { create :order, state: :payment, total: 19.99 }
19
+
20
+ let(:intent_id) { "pi_123123ABC" }
21
+ let(:controller) { double(current_order: order.reload, params: params, request: spy) }
22
+
23
+ let(:params) do
24
+ {
25
+ spree_payment_method_id: stripe.id,
26
+ stripe_payment_intent_id: intent_id,
27
+ form_data: {
28
+ addressLine: ["31 Cotton Rd"],
29
+ city: "San Diego",
30
+ country: "US",
31
+ phone: "+188836412312",
32
+ postalCode: "12345",
33
+ recipient: "James Edwards",
34
+ region: "CA"
35
+ }
36
+ }
37
+ end
38
+
39
+ let(:intent) do
40
+ double(params: {
41
+ "id" => intent_id,
42
+ "charges" => {
43
+ "data" => [{
44
+ "billing_details" => {
45
+ "name" => "John Doe"
46
+ },
47
+ "payment_method_details" => {
48
+ "card" => {
49
+ "brand" => "visa",
50
+ "exp_month" => 1,
51
+ "exp_year" => 2022,
52
+ "last4" => "4242"
53
+ },
54
+ }
55
+ }]
56
+ }
57
+ })
58
+ end
59
+
60
+ describe '#call' do
61
+ subject { service.call }
62
+
63
+ before do
64
+ allow(stripe).to receive(:show_intent) { intent }
65
+ allow_any_instance_of(Spree::CreditCard).to receive(:require_card_numbers?) { false }
66
+ allow_any_instance_of(Spree::PaymentMethod::StripeCreditCard).to receive(:create_profile) { true }
67
+ end
68
+
69
+ it { expect(subject).to be true }
70
+
71
+ it "creates a new pending payment" do
72
+ expect { subject }.to change { order.payments.count }
73
+ expect(order.payments.last.reload).to be_pending
74
+ end
75
+
76
+ it "creates a credit card with the correct information" do
77
+ expect { subject }.to change { Spree::CreditCard.count }
78
+ card = Spree::CreditCard.last
79
+
80
+ aggregate_failures do
81
+ expect(card.name).to eq "John Doe"
82
+ expect(card.cc_type).to eq "visa"
83
+ expect(card.month).to eq "1"
84
+ expect(card.year).to eq "2022"
85
+ expect(card.last_digits).to eq "4242"
86
+ end
87
+ end
88
+
89
+ context "when for any reason the payment could not be created" do
90
+ before { params[:form_data].delete(:city) }
91
+
92
+ it "returns false" do
93
+ expect(subject).to be false
94
+ end
95
+ end
96
+
97
+ context "when there are previous pending payments" do
98
+ let!(:payment) do
99
+ create(:payment, order: order).tap do |payment|
100
+ payment.update!(state: :pending)
101
+ end
102
+ end
103
+
104
+ before do
105
+ response = double(success?: true, authorization: payment.response_code)
106
+ allow_any_instance_of(Spree::PaymentMethod::StripeCreditCard).to receive(:void) { response }
107
+ end
108
+
109
+ context "when one of them is a Payment Intent" do
110
+ before do
111
+ payment.update!(payment_method: stripe)
112
+ payment.source.update!(payment_method: stripe)
113
+ end
114
+
115
+ it "invalidates it" do
116
+ expect { subject }.to change { payment.reload.state }.to 'void'
117
+ end
118
+ end
119
+
120
+ context "when none is a Payment Intent" do
121
+ it "does not invalidate them" do
122
+ expect { subject }.not_to change { payment.reload.state }
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -22,7 +22,8 @@ describe Spree::PaymentMethod::StripeCreditCard do
22
22
  let(:payment) {
23
23
  double('Spree::Payment',
24
24
  source: source,
25
- order: order
25
+ order: order,
26
+ amount: order.total
26
27
  )
27
28
  }
28
29
 
@@ -241,4 +242,46 @@ describe Spree::PaymentMethod::StripeCreditCard do
241
242
  expect(gateway).to receive(:capture).with(9855, '12345', anything).and_return(success_response)
242
243
  end
243
244
  end
245
+
246
+ describe '#try_void' do
247
+ let(:payment) { create :payment, amount: order.total }
248
+
249
+ shared_examples 'voids the payment transaction' do
250
+ it 'voids the payment transaction' do
251
+ expect(gateway).to receive(:void)
252
+
253
+ subject.try_void(payment)
254
+ end
255
+ end
256
+
257
+ context 'when using Payment Intents' do
258
+ before { subject.preferred_v3_intents = true }
259
+
260
+ context 'when the payment is completed' do
261
+ before do
262
+ allow(payment).to receive(:completed?) { true }
263
+ end
264
+
265
+ it 'creates a refund' do
266
+ expect { subject.try_void(payment) }.to change { Spree::Refund.count }.by(1)
267
+ end
268
+ end
269
+
270
+ context 'when the payment is not completed' do
271
+ it_behaves_like 'voids the payment transaction'
272
+ end
273
+ end
274
+
275
+ context 'when not using Payment Intents' do
276
+ before { subject.preferred_v3_intents = false }
277
+
278
+ context 'when the payment is completed' do
279
+ it_behaves_like 'voids the payment transaction'
280
+ end
281
+
282
+ context 'when the payment is not completed' do
283
+ it_behaves_like 'voids the payment transaction'
284
+ end
285
+ end
286
+ end
244
287
  end
@@ -13,7 +13,10 @@ require 'solidus_dev_support/rspec/feature_helper'
13
13
 
14
14
  # Requires supporting ruby files with custom matchers and macros, etc,
15
15
  # in spec/support/ and its subdirectories.
16
- Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].each { |f| require f }
16
+ Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require f }
17
+
18
+ # Requires factories defined in lib/solidus_stripe/factories.rb
19
+ require 'solidus_stripe/factories'
17
20
 
18
21
  RSpec.configure do |config|
19
22
  config.infer_spec_type_from_file_location!
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidus_stripe
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Solidus Team
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-10 00:00:00.000000000 Z
11
+ date: 2020-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: solidus_core
@@ -36,14 +36,14 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 0.4.0
39
+ version: '0.5'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: 0.4.0
46
+ version: '0.5'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: activemerchant
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -88,7 +88,6 @@ files:
88
88
  - CHANGELOG.md
89
89
  - Gemfile
90
90
  - LICENSE
91
- - LICENSE.md
92
91
  - README.md
93
92
  - Rakefile
94
93
  - app/assets/javascripts/spree/frontend/solidus_stripe.js
@@ -103,13 +102,18 @@ files:
103
102
  - app/controllers/spree/stripe_controller.rb
104
103
  - app/decorators/models/spree/order_update_attributes_decorator.rb
105
104
  - app/decorators/models/spree/payment_decorator.rb
105
+ - app/decorators/models/spree/refund_decorator.rb
106
106
  - app/models/solidus_stripe/address_from_params_service.rb
107
- - app/models/solidus_stripe/create_intents_order_service.rb
107
+ - app/models/solidus_stripe/create_intents_payment_service.rb
108
108
  - app/models/solidus_stripe/prepare_order_for_payment_service.rb
109
109
  - app/models/solidus_stripe/shipping_rates_service.rb
110
110
  - app/models/spree/payment_method/stripe_credit_card.rb
111
111
  - bin/console
112
+ - bin/r
112
113
  - bin/rails
114
+ - bin/rake
115
+ - bin/sandbox
116
+ - bin/sandbox_rails
113
117
  - bin/setup
114
118
  - config/routes.rb
115
119
  - db/migrate/20181010123508_update_stripe_payment_method_type_to_credit_card.rb
@@ -118,6 +122,7 @@ files:
118
122
  - lib/generators/solidus_stripe/install/install_generator.rb
119
123
  - lib/solidus_stripe.rb
120
124
  - lib/solidus_stripe/engine.rb
125
+ - lib/solidus_stripe/factories.rb
121
126
  - lib/solidus_stripe/version.rb
122
127
  - lib/tasks/solidus_stripe/db/seed.rake
123
128
  - lib/views/api/spree/api/payments/source_views/_stripe.json.jbuilder
@@ -135,40 +140,42 @@ files:
135
140
  - solidus_stripe.gemspec
136
141
  - spec/features/stripe_checkout_spec.rb
137
142
  - spec/models/solidus_stripe/address_from_params_service_spec.rb
143
+ - spec/models/solidus_stripe/create_intents_payment_service_spec.rb
138
144
  - spec/models/solidus_stripe/prepare_order_for_payment_service_spec.rb
139
145
  - spec/models/solidus_stripe/shipping_rates_service_spec.rb
140
146
  - spec/models/spree/payment_method/stripe_credit_card_spec.rb
141
147
  - spec/spec_helper.rb
142
148
  - spec/support/solidus_address_helper.rb
143
- homepage: https://solidus.io
149
+ homepage: https://github.com/solidusio/solidus_stripe#readme
144
150
  licenses:
145
151
  - BSD-3
146
152
  metadata:
147
- homepage_uri: https://solidus.io
148
- source_code_uri: https://solidus.io
149
- post_install_message:
153
+ homepage_uri: https://github.com/solidusio/solidus_stripe#readme
154
+ source_code_uri: https://github.com/solidusio/solidus_stripe
155
+ changelog_uri: https://github.com/solidusio/solidus_stripe/blob/master/CHANGELOG.md
156
+ post_install_message:
150
157
  rdoc_options: []
151
158
  require_paths:
152
159
  - lib
153
160
  required_ruby_version: !ruby/object:Gem::Requirement
154
161
  requirements:
155
- - - ">="
162
+ - - "~>"
156
163
  - !ruby/object:Gem::Version
157
- version: '2.2'
164
+ version: '2.4'
158
165
  required_rubygems_version: !ruby/object:Gem::Requirement
159
166
  requirements:
160
167
  - - ">="
161
168
  - !ruby/object:Gem::Version
162
169
  version: '0'
163
- requirements:
164
- - none
170
+ requirements: []
165
171
  rubygems_version: 3.0.3
166
- signing_key:
172
+ signing_key:
167
173
  specification_version: 4
168
174
  summary: Stripe Payment Method for Solidus
169
175
  test_files:
170
176
  - spec/features/stripe_checkout_spec.rb
171
177
  - spec/models/solidus_stripe/address_from_params_service_spec.rb
178
+ - spec/models/solidus_stripe/create_intents_payment_service_spec.rb
172
179
  - spec/models/solidus_stripe/prepare_order_for_payment_service_spec.rb
173
180
  - spec/models/solidus_stripe/shipping_rates_service_spec.rb
174
181
  - spec/models/spree/payment_method/stripe_credit_card_spec.rb