solidus_six_saferpay 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +35 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.gitignore +18 -0
  6. data/.rspec +2 -0
  7. data/.rubocop.yml +2 -0
  8. data/.travis.yml +12 -0
  9. data/Gemfile +33 -0
  10. data/LICENSE +26 -0
  11. data/README.md +36 -20
  12. data/Rakefile +4 -54
  13. data/app/assets/config/solidus_six_saferpay_manifest.js +1 -0
  14. data/app/assets/images/solidus_six_saferpay/.keep +0 -0
  15. data/app/assets/javascripts/spree/backend/solidus_six_saferpay.js +2 -0
  16. data/app/assets/javascripts/spree/frontend/solidus_six_saferpay.js +2 -0
  17. data/app/assets/stylesheets/solidus_six_saferpay/loading_animation.scss +0 -27
  18. data/app/assets/stylesheets/solidus_six_saferpay/payments.scss +4 -1
  19. data/app/assets/stylesheets/spree/backend/solidus_six_saferpay.css +4 -0
  20. data/app/assets/stylesheets/spree/frontend/solidus_six_saferpay.css +4 -0
  21. data/app/controllers/spree/solidus_six_saferpay/checkout_controller.rb +56 -10
  22. data/app/services/spree/solidus_six_saferpay/inquire_payment.rb +1 -0
  23. data/app/views/spree/checkout/payment/_saferpay_payment.html.erb +1 -1
  24. data/app/views/spree/six_saferpay_payments/_six_saferpay_payment.html.erb +2 -2
  25. data/bin/console +17 -0
  26. data/bin/rails +18 -0
  27. data/bin/rake +7 -0
  28. data/bin/setup +8 -0
  29. data/config/initializers/assets.rb +3 -0
  30. data/config/locales/de.yml +1 -1
  31. data/config/locales/en.yml +1 -1
  32. data/config/locales/fr.yml +1 -1
  33. data/config/routes.rb +6 -6
  34. data/lib/generators/solidus_six_saferpay/install/install_generator.rb +15 -3
  35. data/lib/solidus_six_saferpay.rb +6 -3
  36. data/lib/solidus_six_saferpay/configuration.rb +4 -7
  37. data/lib/solidus_six_saferpay/engine.rb +19 -10
  38. data/lib/solidus_six_saferpay/gateway.rb +5 -4
  39. data/lib/solidus_six_saferpay/payment_page_gateway.rb +8 -9
  40. data/lib/solidus_six_saferpay/transaction_gateway.rb +8 -9
  41. data/lib/solidus_six_saferpay/version.rb +3 -1
  42. data/solidus_six_saferpay.gemspec +42 -0
  43. data/spec/controllers/spree/solidus_six_saferpay/checkout_controller_spec.rb +41 -0
  44. data/spec/controllers/spree/solidus_six_saferpay/payment_page/checkout_controller_spec.rb +206 -0
  45. data/spec/controllers/spree/solidus_six_saferpay/transaction/checkout_controller_spec.rb +229 -0
  46. data/spec/factories/payment_methods.rb +23 -0
  47. data/spec/factories/payments.rb +11 -0
  48. data/spec/factories/spree/six_saferpay_payments.rb +118 -0
  49. data/spec/models/spree/six_saferpay_payment_spec.rb +203 -0
  50. data/spec/rails_helper.rb +73 -0
  51. data/spec/services/spree/solidus_six_saferpay/assert_payment_page_spec.rb +148 -0
  52. data/spec/services/spree/solidus_six_saferpay/authorize_payment_spec.rb +39 -0
  53. data/spec/services/spree/solidus_six_saferpay/authorize_transaction_spec.rb +148 -0
  54. data/spec/services/spree/solidus_six_saferpay/initialize_payment_page_spec.rb +83 -0
  55. data/spec/services/spree/solidus_six_saferpay/initialize_payment_spec.rb +40 -0
  56. data/spec/services/spree/solidus_six_saferpay/initialize_transaction_spec.rb +85 -0
  57. data/spec/services/spree/solidus_six_saferpay/inquire_payment_page_payment_spec.rb +116 -0
  58. data/spec/services/spree/solidus_six_saferpay/inquire_payment_spec.rb +39 -0
  59. data/spec/services/spree/solidus_six_saferpay/inquire_transaction_payment_spec.rb +117 -0
  60. data/spec/services/spree/solidus_six_saferpay/payment_validator_spec.rb +100 -0
  61. data/spec/services/spree/solidus_six_saferpay/process_authorized_payment_spec.rb +39 -0
  62. data/spec/services/spree/solidus_six_saferpay/process_payment_page_payment_spec.rb +225 -0
  63. data/spec/services/spree/solidus_six_saferpay/process_transaction_payment_spec.rb +219 -0
  64. data/spec/solidus_six_saferpay/configuration_spec.rb +15 -0
  65. data/spec/solidus_six_saferpay/error_handler_spec.rb +65 -0
  66. data/spec/solidus_six_saferpay/gateway_response_spec.rb +70 -0
  67. data/spec/solidus_six_saferpay/gateway_spec.rb +365 -0
  68. data/spec/solidus_six_saferpay/payment_page_gateway_spec.rb +392 -0
  69. data/spec/solidus_six_saferpay/transaction_gateway_spec.rb +390 -0
  70. data/spec/spec_helper.rb +21 -0
  71. data/spec/support/route_access.rb +6 -0
  72. data/spec/support/uses_payment_page_gateway.rb +29 -0
  73. data/spec/support/uses_transaction_gateway.rb +28 -0
  74. metadata +240 -99
@@ -0,0 +1,73 @@
1
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
2
+ require 'spec_helper'
3
+ ENV['RAILS_ENV'] ||= 'test'
4
+ require File.expand_path('../dummy/config/environment', __FILE__)
5
+ # Prevent database truncation if the environment is production
6
+ abort("The Rails environment is running in production mode!") if Rails.env.production?
7
+ require 'rspec/rails'
8
+ require 'rails-controller-testing'
9
+ Rails::Controller::Testing.install
10
+ # Add additional requires below this line. Rails is not loaded until this point!
11
+
12
+ # require 'active_support/core_ext/string/deep_symbolize_keys'
13
+
14
+ require 'shoulda/matchers'
15
+
16
+ # Requires supporting ruby files with custom matchers and macros, etc, in
17
+ # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
18
+ # run as spec files by default. This means that files in spec/support that end
19
+ # in _spec.rb will both be required and run as specs, causing the specs to be
20
+ # run twice. It is recommended that you do not name files matching this glob to
21
+ # end with _spec.rb. You can configure this pattern with the --pattern
22
+ # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
23
+ #
24
+ # The following line is provided for convenience purposes. It has the downside
25
+ # of increasing the boot-up time by auto-requiring all files in the support
26
+ # directory. Alternatively, in the individual `*_spec.rb` files, manually
27
+ # require only the support files necessary.
28
+ #
29
+ Dir[SolidusSixSaferpay::Engine.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
30
+
31
+
32
+ # Set route host
33
+ Spree::Core::Engine.routes.default_url_options = {
34
+ host: 'shop.localhost:3000'
35
+ }
36
+
37
+ RSpec.configure do |config|
38
+ Shoulda::Matchers.configure do |c|
39
+ c.integrate do |with|
40
+ with.test_framework :rspec
41
+ with.library :rails
42
+ end
43
+
44
+ # include url_helpers in specs
45
+ include Spree::Core::Engine.routes.url_helpers
46
+ end
47
+
48
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
49
+ # examples within a transaction, remove the following line or assign false
50
+ # instead of true.
51
+ config.use_transactional_fixtures = true
52
+
53
+ # RSpec Rails can automatically mix in different behaviours to your tests
54
+ # based on their file location, for example enabling you to call `get` and
55
+ # `post` in specs under `spec/controllers`.
56
+ #
57
+ # You can disable this behaviour by removing the line below, and instead
58
+ # explicitly tag your specs with their type, e.g.:
59
+ #
60
+ # RSpec.describe UsersController, :type => :controller do
61
+ # # ...
62
+ # end
63
+ #
64
+ # The different available types are documented in the features, such as in
65
+ # https://relishapp.com/rspec/rspec-rails/docs
66
+ config.infer_spec_type_from_file_location!
67
+
68
+ # Filter lines from Rails gems in backtraces.
69
+ config.filter_rails_from_backtrace!
70
+ # arbitrary gems may also be filtered via:
71
+ # config.filter_gems_from_backtrace("gem name")
72
+ end
73
+
@@ -0,0 +1,148 @@
1
+ require 'rails_helper'
2
+
3
+ module Spree
4
+ module SolidusSixSaferpay
5
+ RSpec.describe AssertPaymentPage do
6
+
7
+ let(:payment) { create(:six_saferpay_payment) }
8
+
9
+ subject { described_class.new(payment) }
10
+
11
+
12
+ describe '#gateway' do
13
+ it_behaves_like "it uses the payment page gateway"
14
+ end
15
+
16
+ describe '#call' do
17
+ let(:transaction_status) { "AUTHORIZED" }
18
+ let(:transaction_id) { "723n4MAjMdhjSAhAKEUdA8jtl9jb" }
19
+ let(:transaction_date) { "2015-01-30T12:45:22.258+01:00" }
20
+ let(:amount_value) { "100" }
21
+ let(:amount_currency) { "USD" }
22
+ let(:brand_name) { 'PaymentBrand' }
23
+ let(:display_text) { "xxxx xxxx xxxx 1234" }
24
+ let(:six_transaction_reference) { "0:0:3:723n4MAjMdhjSAhAKEUdA8jtl9jb" }
25
+
26
+ let(:payment_means) do
27
+ SixSaferpay::ResponsePaymentMeans.new(
28
+ brand: SixSaferpay::Brand.new(name: brand_name),
29
+ display_text: display_text
30
+ )
31
+ end
32
+
33
+ # https://saferpay.github.io/jsonapi/#Payment_v1_PaymentPage_Initialize
34
+ let(:api_response) do
35
+ SixSaferpay::SixPaymentPage::AssertResponse.new(
36
+ response_header: SixSaferpay::ResponseHeader.new(request_id: 'test', spec_version: 'test'),
37
+ transaction: SixSaferpay::Transaction.new(
38
+ type: "PAYMENT",
39
+ status: transaction_status,
40
+ id: transaction_id,
41
+ date: transaction_date,
42
+ amount: SixSaferpay::Amount.new(value: amount_value, currency_code: amount_currency),
43
+ six_transaction_reference: six_transaction_reference,
44
+ ),
45
+ payment_means: payment_means
46
+ )
47
+ end
48
+
49
+ let(:gateway_response) do
50
+ ::SolidusSixSaferpay::GatewayResponse.new(
51
+ gateway_success,
52
+ "initialize success: #{gateway_success}",
53
+ api_response
54
+ )
55
+ end
56
+
57
+ # stub gateway to return our mock response
58
+ before do
59
+ allow(subject).to receive(:gateway).
60
+ and_return(double('gateway', authorize: gateway_response))
61
+ end
62
+
63
+ context 'when not successful' do
64
+ let(:gateway_success) { false }
65
+
66
+ it 'indicates failure' do
67
+ subject.call
68
+
69
+ expect(subject).not_to be_success
70
+ end
71
+
72
+ it 'does not update the payment attributes' do
73
+ expect { subject.call }.not_to change { payment.transaction_id }
74
+ expect { subject.call }.not_to change { payment.transaction_status }
75
+ expect { subject.call }.not_to change { payment.transaction_date }
76
+ expect { subject.call }.not_to change { payment.six_transaction_reference }
77
+ expect { subject.call }.not_to change { payment.display_text }
78
+ expect { subject.call }.not_to change { payment.response_hash }
79
+ end
80
+ end
81
+
82
+ context 'when successful' do
83
+ let(:gateway_success) { true }
84
+
85
+ it 'updates the transaction_id' do
86
+ expect { subject.call }.to change { payment.transaction_id }.from(nil).to(transaction_id)
87
+ end
88
+
89
+ it 'updates the transaction status' do
90
+ expect { subject.call }.to change { payment.transaction_status }.from(nil).to(transaction_status)
91
+ end
92
+
93
+ it 'updates the transaction date' do
94
+ expect { subject.call }.to change { payment.transaction_date }.from(nil).to(DateTime.parse(transaction_date))
95
+ end
96
+
97
+ it 'updates the six_transaction_reference' do
98
+ expect { subject.call }.to change { payment.six_transaction_reference }.from(nil).to(six_transaction_reference)
99
+ end
100
+
101
+ it 'updates the display_text' do
102
+ expect { subject.call }.to change { payment.display_text }.from(nil).to(display_text)
103
+ end
104
+
105
+ it 'updates the response hash' do
106
+ expect { subject.call }.to change { payment.response_hash }.from(payment.response_hash).to(api_response.to_h)
107
+ end
108
+
109
+ context 'when the payment was made with a card' do
110
+ let(:masked_number) { "xxxx xxxx xxxx 5555" }
111
+ let(:exp_year) { "19" }
112
+ let(:exp_month) { "5" }
113
+ let(:payment_means) do
114
+ SixSaferpay::ResponsePaymentMeans.new(
115
+ brand: SixSaferpay::Brand.new(name: brand_name),
116
+ display_text: display_text,
117
+ card: SixSaferpay::ResponseCard.new(
118
+ masked_number: masked_number,
119
+ exp_year: exp_year,
120
+ exp_month: exp_month
121
+ )
122
+ )
123
+ end
124
+
125
+ it 'updates the masked number' do
126
+ expect { subject.call }.to change { payment.masked_number }.from(nil).to(masked_number)
127
+ end
128
+
129
+ it 'updates the expiry year' do
130
+ expect { subject.call }.to change { payment.expiration_year }.from(nil).to(exp_year)
131
+ end
132
+
133
+ it 'updates the expiry month' do
134
+ expect { subject.call }.to change { payment.expiration_month }.from(nil).to(exp_month)
135
+ end
136
+ end
137
+
138
+ it 'indicates success' do
139
+ subject.call
140
+
141
+ expect(subject).to be_success
142
+ end
143
+ end
144
+ end
145
+
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,39 @@
1
+ require 'rails_helper'
2
+
3
+ module Spree
4
+ module SolidusSixSaferpay
5
+ RSpec.describe AuthorizePayment do
6
+
7
+ let(:payment) { create(:six_saferpay_payment) }
8
+
9
+ let(:service) { described_class.new(payment) }
10
+
11
+ describe '.call' do
12
+ it 'calls an initialized service with given order and payment method' do
13
+ expect(described_class).to receive(:new).with(payment).and_return(service)
14
+ expect(service).to receive(:call)
15
+
16
+ described_class.call(payment)
17
+ end
18
+ end
19
+
20
+ describe '#call' do
21
+ it 'fails because gateway raises an error' do
22
+ expect { service.call }.to raise_error(NotImplementedError)
23
+ end
24
+ end
25
+
26
+ describe '#gateway' do
27
+ it 'raises an error because the gateway must be defined in subclasses' do
28
+ expect { service.gateway }.to raise_error(NotImplementedError)
29
+ end
30
+ end
31
+
32
+ describe '#success?' do
33
+ it 'is initially false' do
34
+ expect(service).not_to be_success
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,148 @@
1
+ require 'rails_helper'
2
+
3
+ module Spree
4
+ module SolidusSixSaferpay
5
+ RSpec.describe AuthorizeTransaction do
6
+
7
+ let(:payment) { create(:six_saferpay_payment) }
8
+
9
+ subject { described_class.new(payment) }
10
+
11
+
12
+ describe '#gateway' do
13
+ it_behaves_like "it uses the transaction gateway"
14
+ end
15
+
16
+ describe '#call' do
17
+ let(:transaction_status) { "AUTHORIZED" }
18
+ let(:transaction_id) { "723n4MAjMdhjSAhAKEUdA8jtl9jb" }
19
+ let(:transaction_date) { "2015-01-30T12:45:22.258+01:00" }
20
+ let(:amount_value) { "100" }
21
+ let(:amount_currency) { "USD" }
22
+ let(:brand_name) { 'PaymentBrand' }
23
+ let(:display_text) { "xxxx xxxx xxxx 1234" }
24
+ let(:six_transaction_reference) { "0:0:3:723n4MAjMdhjSAhAKEUdA8jtl9jb" }
25
+
26
+ let(:payment_means) do
27
+ SixSaferpay::ResponsePaymentMeans.new(
28
+ brand: SixSaferpay::Brand.new(name: brand_name),
29
+ display_text: display_text
30
+ )
31
+ end
32
+
33
+ # https://saferpay.github.io/jsonapi/#Payment_v1_PaymentPage_Initialize
34
+ let(:api_response) do
35
+ SixSaferpay::SixPaymentPage::AssertResponse.new(
36
+ response_header: SixSaferpay::ResponseHeader.new(request_id: 'test', spec_version: 'test'),
37
+ transaction: SixSaferpay::Transaction.new(
38
+ type: "PAYMENT",
39
+ status: transaction_status,
40
+ id: transaction_id,
41
+ date: transaction_date,
42
+ amount: SixSaferpay::Amount.new(value: amount_value, currency_code: amount_currency),
43
+ six_transaction_reference: six_transaction_reference,
44
+ ),
45
+ payment_means: payment_means
46
+ )
47
+ end
48
+
49
+ let(:gateway_response) do
50
+ ::SolidusSixSaferpay::GatewayResponse.new(
51
+ gateway_success,
52
+ "initialize success: #{gateway_success}",
53
+ api_response
54
+ )
55
+ end
56
+
57
+ # stub gateway to return our mock response
58
+ before do
59
+ allow(subject).to receive(:gateway).
60
+ and_return(double('gateway', authorize: gateway_response))
61
+ end
62
+
63
+ context 'when not successful' do
64
+ let(:gateway_success) { false }
65
+
66
+ it 'indicates failure' do
67
+ subject.call
68
+
69
+ expect(subject).not_to be_success
70
+ end
71
+
72
+ it 'does not update the payment attributes' do
73
+ expect { subject.call }.not_to change { payment.transaction_id }
74
+ expect { subject.call }.not_to change { payment.transaction_status }
75
+ expect { subject.call }.not_to change { payment.transaction_date }
76
+ expect { subject.call }.not_to change { payment.six_transaction_reference }
77
+ expect { subject.call }.not_to change { payment.display_text }
78
+ expect { subject.call }.not_to change { payment.response_hash }
79
+ end
80
+ end
81
+
82
+ context 'when successful' do
83
+ let(:gateway_success) { true }
84
+
85
+ it 'updates the transaction_id' do
86
+ expect { subject.call }.to change { payment.transaction_id }.from(nil).to(transaction_id)
87
+ end
88
+
89
+ it 'updates the transaction status' do
90
+ expect { subject.call }.to change { payment.transaction_status }.from(nil).to(transaction_status)
91
+ end
92
+
93
+ it 'updates the transaction date' do
94
+ expect { subject.call }.to change { payment.transaction_date }.from(nil).to(DateTime.parse(transaction_date))
95
+ end
96
+
97
+ it 'updates the six_transaction_reference' do
98
+ expect { subject.call }.to change { payment.six_transaction_reference }.from(nil).to(six_transaction_reference)
99
+ end
100
+
101
+ it 'updates the display_text' do
102
+ expect { subject.call }.to change { payment.display_text }.from(nil).to(display_text)
103
+ end
104
+
105
+ it 'updates the response hash' do
106
+ expect { subject.call }.to change { payment.response_hash }.from(payment.response_hash).to(api_response.to_h)
107
+ end
108
+
109
+ context 'when the payment was made with a card' do
110
+ let(:masked_number) { "xxxx xxxx xxxx 5555" }
111
+ let(:exp_year) { "19" }
112
+ let(:exp_month) { "5" }
113
+ let(:payment_means) do
114
+ SixSaferpay::ResponsePaymentMeans.new(
115
+ brand: SixSaferpay::Brand.new(name: brand_name),
116
+ display_text: display_text,
117
+ card: SixSaferpay::ResponseCard.new(
118
+ masked_number: masked_number,
119
+ exp_year: exp_year,
120
+ exp_month: exp_month
121
+ )
122
+ )
123
+ end
124
+
125
+ it 'updates the masked number' do
126
+ expect { subject.call }.to change { payment.masked_number }.from(nil).to(masked_number)
127
+ end
128
+
129
+ it 'updates the expiry year' do
130
+ expect { subject.call }.to change { payment.expiration_year }.from(nil).to(exp_year)
131
+ end
132
+
133
+ it 'updates the expiry month' do
134
+ expect { subject.call }.to change { payment.expiration_month }.from(nil).to(exp_month)
135
+ end
136
+ end
137
+
138
+ it 'indicates success' do
139
+ subject.call
140
+
141
+ expect(subject).to be_success
142
+ end
143
+ end
144
+ end
145
+
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,83 @@
1
+ require 'rails_helper'
2
+
3
+ module Spree
4
+ module SolidusSixSaferpay
5
+ RSpec.describe InitializePaymentPage do
6
+
7
+ let(:order) { create(:order) }
8
+ let(:payment_method) { create(:saferpay_payment_method) }
9
+
10
+ subject { described_class.new(order, payment_method) }
11
+
12
+
13
+ describe '#gateway' do
14
+ it_behaves_like "it uses the payment page gateway"
15
+ end
16
+
17
+ describe '#call' do
18
+ let(:token) { '234uhfh78234hlasdfh8234e1234' }
19
+ let(:expiration) { '2015-01-30T12:45:22.258+01:00' }
20
+ let(:redirect_url) { '/saferpay/redirect/url' }
21
+
22
+ # https://saferpay.github.io/jsonapi/#Payment_v1_PaymentPage_Initialize
23
+ let(:api_response) do
24
+ SixSaferpay::SixPaymentPage::InitializeResponse.new(
25
+ response_header: SixSaferpay::ResponseHeader.new(request_id: 'test', spec_version: 'test'),
26
+ token: token,
27
+ expiration: expiration,
28
+ redirect_url: redirect_url
29
+ )
30
+ end
31
+
32
+ let(:gateway_response) do
33
+ ::SolidusSixSaferpay::GatewayResponse.new(
34
+ gateway_success,
35
+ "initialize success: #{gateway_success}",
36
+ api_response
37
+ )
38
+ end
39
+
40
+ # stub gateway to return our mock response
41
+ before do
42
+ allow(subject).to receive(:gateway).
43
+ and_return(double('gateway', initialize_payment: gateway_response))
44
+ end
45
+
46
+ context 'when not successful' do
47
+ let(:gateway_success) { false }
48
+
49
+ it 'indicates failure' do
50
+ subject.call
51
+
52
+ expect(subject).not_to be_success
53
+ end
54
+
55
+ it 'does not create a saferpay payment' do
56
+ expect { subject.call }.not_to change { Spree::SixSaferpayPayment.count }
57
+ end
58
+ end
59
+
60
+ context 'when successful' do
61
+ let(:gateway_success) { true }
62
+
63
+ it 'creates a new saferpay payment' do
64
+ expect { subject.call }.to change { Spree::SixSaferpayPayment.count }.from(0).to(1)
65
+ end
66
+
67
+ it 'sets the redirect_url' do
68
+ subject.call
69
+
70
+ expect(subject.redirect_url).to eq(redirect_url)
71
+ end
72
+
73
+ it 'indicates success' do
74
+ subject.call
75
+
76
+ expect(subject).to be_success
77
+ end
78
+ end
79
+ end
80
+
81
+ end
82
+ end
83
+ end