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,40 @@
1
+ require 'rails_helper'
2
+
3
+ module Spree
4
+ module SolidusSixSaferpay
5
+ RSpec.describe InitializePayment do
6
+
7
+ let(:order) { create(:order) }
8
+ let(:payment_method) { create(:saferpay_payment_method) }
9
+
10
+ let(:service) { described_class.new(order, payment_method) }
11
+
12
+ describe '.call' do
13
+ it 'calls an initialized service with given order and payment method' do
14
+ expect(described_class).to receive(:new).with(order, payment_method).and_return(service)
15
+ expect(service).to receive(:call)
16
+
17
+ described_class.call(order, payment_method)
18
+ end
19
+ end
20
+
21
+ describe '#call' do
22
+ it 'fails because gateway raises an error' do
23
+ expect { service.call }.to raise_error(NotImplementedError)
24
+ end
25
+ end
26
+
27
+ describe '#gateway' do
28
+ it 'raises an error because the gateway must be defined in subclasses' do
29
+ expect { service.gateway }.to raise_error(NotImplementedError)
30
+ end
31
+ end
32
+
33
+ describe '#success?' do
34
+ it 'is initially false' do
35
+ expect(service.success).to be false
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,85 @@
1
+ require 'rails_helper'
2
+
3
+ module Spree
4
+ module SolidusSixSaferpay
5
+ RSpec.describe InitializeTransaction 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 transaction 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_Transaction_Initialize
23
+ let(:api_response) do
24
+ SixSaferpay::SixTransaction::InitializeResponse.new(
25
+ response_header: SixSaferpay::ResponseHeader.new(request_id: 'test', spec_version: 'test'),
26
+ token: token,
27
+ expiration: expiration,
28
+ liability_shift: nil, # this is empty because we don't submit PaymentMeans on initialize already
29
+ redirect_required: true,
30
+ redirect: SixSaferpay::Redirect.new(redirect_url: redirect_url, payment_means_required: true) # since we don't provide PaymentMeans on initialize, we must always redirect
31
+ )
32
+ end
33
+
34
+ let(:gateway_response) do
35
+ ::SolidusSixSaferpay::GatewayResponse.new(
36
+ gateway_success,
37
+ "initialize success: #{gateway_success}",
38
+ api_response
39
+ )
40
+ end
41
+
42
+ # stub gateway to return our mock response
43
+ before do
44
+ allow(subject).to receive(:gateway).
45
+ and_return(double('gateway', initialize_payment: gateway_response))
46
+ end
47
+
48
+ context 'when not successful' do
49
+ let(:gateway_success) { false }
50
+
51
+ it 'indicates failure' do
52
+ subject.call
53
+
54
+ expect(subject).not_to be_success
55
+ end
56
+
57
+ it 'does not create a saferpay payment' do
58
+ expect { subject.call }.not_to change { Spree::SixSaferpayPayment.count }
59
+ end
60
+ end
61
+
62
+ context 'when successful' do
63
+ let(:gateway_success) { true }
64
+
65
+ it 'creates a new saferpay payment' do
66
+ expect { subject.call }.to change { Spree::SixSaferpayPayment.count }.from(0).to(1)
67
+ end
68
+
69
+ it 'sets the redirect_url' do
70
+ subject.call
71
+
72
+ expect(subject.redirect_url).to eq(redirect_url)
73
+ end
74
+
75
+ it 'indicates success' do
76
+ subject.call
77
+
78
+ expect(subject).to be_success
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,116 @@
1
+ require 'rails_helper'
2
+
3
+ module Spree
4
+ module SolidusSixSaferpay
5
+ RSpec.describe InquirePaymentPagePayment 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
+
17
+ describe '#call' do
18
+
19
+ before do
20
+ allow(subject).to receive(:gateway).and_return(double('gateway', inquire: gateway_response))
21
+ end
22
+
23
+ context 'when gateway response is not successful' do
24
+ let(:gateway_success) { false }
25
+ let(:error_behaviour) { "ABORT" }
26
+ let(:error_name) { "VALIDATION_FAILED" }
27
+ let(:error_message) { "Request validation failed" }
28
+ let(:api_response) { nil }
29
+ let(:translated_general_error) { "General Error" }
30
+ let(:translated_user_message) { "User Message" }
31
+
32
+ let(:gateway_response) do
33
+ ::SolidusSixSaferpay::GatewayResponse.new(
34
+ gateway_success,
35
+ "initialize success: #{gateway_success}",
36
+ api_response,
37
+ error_name: error_name,
38
+ )
39
+ end
40
+
41
+ it 'still indicates success' do
42
+ subject.call
43
+
44
+ expect(subject).to be_success
45
+ end
46
+
47
+ it 'adds the error message to the response hash' do
48
+ expect { subject.call }.to change { payment.response_hash }.from({}).to({error: error_name})
49
+ end
50
+
51
+ it 'sets the user message according to the api error code' do
52
+ expect(I18n).to receive(:t).with(:general_error, scope: [:solidus_six_saferpay, :errors]).and_return(translated_general_error)
53
+ expect(I18n).to receive(:t).with(error_name, scope: [:six_saferpay, :error_names]).and_return(translated_user_message)
54
+ subject.call
55
+
56
+ expect(subject.user_message).to eq("#{translated_general_error}: #{translated_user_message}")
57
+ end
58
+ end
59
+
60
+ context 'when successful' do
61
+ let(:transaction_status) { "AUTHORIZED" }
62
+ let(:transaction_id) { "723n4MAjMdhjSAhAKEUdA8jtl9jb" }
63
+ let(:transaction_date) { "2015-01-30T12:45:22.258+01:00" }
64
+ let(:amount_value) { "100" }
65
+ let(:amount_currency) { "USD" }
66
+ let(:brand_name) { 'PaymentBrand' }
67
+ let(:display_text) { "xxxx xxxx xxxx 1234" }
68
+ let(:six_transaction_reference) { "0:0:3:723n4MAjMdhjSAhAKEUdA8jtl9jb" }
69
+
70
+ let(:payment_means) do
71
+ SixSaferpay::ResponsePaymentMeans.new(
72
+ brand: SixSaferpay::Brand.new(name: brand_name),
73
+ display_text: display_text
74
+ )
75
+ end
76
+
77
+ # https://saferpay.github.io/jsonapi/#Payment_v1_PaymentPage_Assert
78
+ let(:api_response) do
79
+ SixSaferpay::SixPaymentPage::AssertResponse.new(
80
+ response_header: SixSaferpay::ResponseHeader.new(request_id: 'test', spec_version: 'test'),
81
+ transaction: SixSaferpay::Transaction.new(
82
+ type: "PAYMENT",
83
+ status: transaction_status,
84
+ id: transaction_id,
85
+ date: transaction_date,
86
+ amount: SixSaferpay::Amount.new(value: amount_value, currency_code: amount_currency),
87
+ six_transaction_reference: six_transaction_reference,
88
+ ),
89
+ payment_means: payment_means
90
+ )
91
+ end
92
+
93
+ let(:gateway_success) { true }
94
+ let(:gateway_response) do
95
+ ::SolidusSixSaferpay::GatewayResponse.new(
96
+ gateway_success,
97
+ "initialize success: #{gateway_success}",
98
+ api_response
99
+ )
100
+ end
101
+
102
+ it 'updates the response hash' do
103
+ expect { subject.call }.to change { payment.response_hash }.from(payment.response_hash).to(api_response.to_h)
104
+ end
105
+
106
+ it 'indicates success' do
107
+ subject.call
108
+
109
+ expect(subject).to be_success
110
+ end
111
+ end
112
+ end
113
+
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,39 @@
1
+ require 'rails_helper'
2
+
3
+ module Spree
4
+ module SolidusSixSaferpay
5
+ RSpec.describe InquirePayment do
6
+
7
+ let(:payment) { create(:six_saferpay_payment, :authorized) }
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,117 @@
1
+ require 'rails_helper'
2
+
3
+ module Spree
4
+ module SolidusSixSaferpay
5
+ RSpec.describe InquireTransactionPayment 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
+
17
+ describe '#call' do
18
+
19
+ before do
20
+ allow(subject).to receive(:gateway).and_return(double('gateway', inquire: gateway_response))
21
+ end
22
+
23
+ context 'when gateway response is not successful' do
24
+ let(:gateway_success) { false }
25
+ let(:error_behaviour) { "ABORT" }
26
+ let(:error_name) { "VALIDATION_FAILED" }
27
+ let(:error_message) { "Request validation failed" }
28
+ let(:api_response) { nil }
29
+ let(:translated_general_error) { "General Error" }
30
+ let(:translated_user_message) { "User Message" }
31
+
32
+ let(:gateway_response) do
33
+ ::SolidusSixSaferpay::GatewayResponse.new(
34
+ gateway_success,
35
+ "initialize success: #{gateway_success}",
36
+ api_response,
37
+ error_name: error_name,
38
+ )
39
+ end
40
+
41
+ it 'still indicates success' do
42
+ subject.call
43
+
44
+ expect(subject).to be_success
45
+ end
46
+
47
+ it 'adds the error message to the response hash' do
48
+ expect { subject.call }.to change { payment.response_hash }.from({}).to({error: error_name})
49
+ end
50
+
51
+ it 'sets the user message according to the api error code' do
52
+ expect(I18n).to receive(:t).with(:general_error, scope: [:solidus_six_saferpay, :errors]).once.and_return(translated_general_error)
53
+ expect(I18n).to receive(:t).with(error_name, scope: [:six_saferpay, :error_names]).once.and_return(translated_user_message)
54
+
55
+ subject.call
56
+
57
+ expect(subject.user_message).to eq("#{translated_general_error}: #{translated_user_message}")
58
+ end
59
+ end
60
+
61
+ context 'when successful' do
62
+ let(:transaction_status) { "AUTHORIZED" }
63
+ let(:transaction_id) { "723n4MAjMdhjSAhAKEUdA8jtl9jb" }
64
+ let(:transaction_date) { "2015-01-30T12:45:22.258+01:00" }
65
+ let(:amount_value) { "100" }
66
+ let(:amount_currency) { "USD" }
67
+ let(:brand_name) { 'PaymentBrand' }
68
+ let(:display_text) { "xxxx xxxx xxxx 1234" }
69
+ let(:six_transaction_reference) { "0:0:3:723n4MAjMdhjSAhAKEUdA8jtl9jb" }
70
+
71
+ let(:payment_means) do
72
+ SixSaferpay::ResponsePaymentMeans.new(
73
+ brand: SixSaferpay::Brand.new(name: brand_name),
74
+ display_text: display_text
75
+ )
76
+ end
77
+
78
+ # https://saferpay.github.io/jsonapi/#Payment_v1_PaymentPage_Assert
79
+ let(:api_response) do
80
+ SixSaferpay::SixPaymentPage::AssertResponse.new(
81
+ response_header: SixSaferpay::ResponseHeader.new(request_id: 'test', spec_version: 'test'),
82
+ transaction: SixSaferpay::Transaction.new(
83
+ type: "PAYMENT",
84
+ status: transaction_status,
85
+ id: transaction_id,
86
+ date: transaction_date,
87
+ amount: SixSaferpay::Amount.new(value: amount_value, currency_code: amount_currency),
88
+ six_transaction_reference: six_transaction_reference,
89
+ ),
90
+ payment_means: payment_means
91
+ )
92
+ end
93
+
94
+ let(:gateway_success) { true }
95
+ let(:gateway_response) do
96
+ ::SolidusSixSaferpay::GatewayResponse.new(
97
+ gateway_success,
98
+ "initialize success: #{gateway_success}",
99
+ api_response
100
+ )
101
+ end
102
+
103
+ it 'updates the response hash' do
104
+ expect { subject.call }.to change { payment.response_hash }.from(payment.response_hash).to(api_response.to_h)
105
+ end
106
+
107
+ it 'indicates success' do
108
+ subject.call
109
+
110
+ expect(subject).to be_success
111
+ end
112
+ end
113
+ end
114
+
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,100 @@
1
+ require 'rails_helper'
2
+
3
+ module Spree
4
+ module SolidusSixSaferpay
5
+ RSpec.describe PaymentValidator do
6
+
7
+ let(:payment) { create(:six_saferpay_payment, :authorized) }
8
+
9
+ let(:service) { described_class.new(payment) }
10
+
11
+ describe '.call' do
12
+ it 'calls an initialized service with given saferpay payment' 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 'performs multiple validations on the payment' do
22
+ expect(service).to receive(:validate_payment_authorized).with(payment.transaction)
23
+ expect(service).to receive(:validate_order_reference).with(payment.transaction)
24
+ expect(service).to receive(:validate_order_amount).with(payment.transaction)
25
+
26
+ service.call
27
+ end
28
+ end
29
+
30
+ describe '#validate_payment_authorized' do
31
+ let(:saferpay_transaction) { instance_double("SixSaferpay::Transaction", status: "AUTHORIZED") }
32
+
33
+ context 'when the saferpay status is AUTHORIZED' do
34
+ it 'passes validation' do
35
+ expect(service.validate_payment_authorized(saferpay_transaction)).to be true
36
+ end
37
+ end
38
+
39
+ context 'when the saferpay status is CAPTURED' do
40
+ let(:saferpay_transaction) { instance_double("SixSaferpay::Transaction", status: "CAPTURED") }
41
+ it 'raises an error' do
42
+ expect{ service.validate_payment_authorized(saferpay_transaction) }.to raise_error(::SolidusSixSaferpay::InvalidSaferpayPayment)
43
+ end
44
+ end
45
+
46
+ context 'when the saferpay status is PENDING' do
47
+ let(:saferpay_transaction) { instance_double("SixSaferpay::Transaction", status: "PENDING") }
48
+ it 'raises an error' do
49
+ expect{ service.validate_payment_authorized(saferpay_transaction) }.to raise_error(::SolidusSixSaferpay::InvalidSaferpayPayment)
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '#validate_order_reference' do
55
+ context 'when the saferpay order reference matches the solidus order' do
56
+ let(:saferpay_transaction) { instance_double("SixSaferpay::Transaction", order_id: payment.order.number) }
57
+
58
+ it 'passes validation' do
59
+ expect(service.validate_order_reference(saferpay_transaction)).to be true
60
+ end
61
+ end
62
+
63
+ context 'when the saferpay order reference does not match the solidus order' do
64
+ let(:saferpay_transaction) { instance_double("SixSaferpay::Transaction", order_id: "OTHER") }
65
+
66
+ it 'raises an error' do
67
+ expect{ service.validate_order_reference(saferpay_transaction) }.to raise_error(::SolidusSixSaferpay::InvalidSaferpayPayment)
68
+ end
69
+ end
70
+ end
71
+
72
+ describe '#validate_order_amount' do
73
+ let(:saferpay_transaction) { instance_double("SixSaferpay::Transaction", amount: saferpay_amount) }
74
+ context 'when the saferpay payment values match the solidus order values' do
75
+ let(:saferpay_amount) { instance_double("SixSaferpay::Amount", value: (payment.order.amount * 100).to_s, currency_code: payment.order.currency) }
76
+
77
+ it 'passes validation' do
78
+ expect(service.validate_order_amount(saferpay_transaction)).to be true
79
+ end
80
+ end
81
+
82
+ context 'when the saferpay payment currency does not match the solidus order currency' do
83
+ let(:saferpay_amount) { instance_double("SixSaferpay::Amount", value: (payment.order.amount * 100).to_s, currency_code: "OTHER") }
84
+
85
+ it 'raises an error' do
86
+ expect{ service.validate_order_amount(saferpay_transaction) }.to raise_error(::SolidusSixSaferpay::InvalidSaferpayPayment)
87
+ end
88
+ end
89
+
90
+ context 'when the saferpay payment value does not match the solidus order value' do
91
+ let(:saferpay_amount) { instance_double("SixSaferpay::Amount", value: ((payment.order.amount + 5) * 100).to_s, currency_code: payment.order.currency) }
92
+
93
+ it 'raises an error' do
94
+ expect{ service.validate_order_amount(saferpay_transaction) }.to raise_error(::SolidusSixSaferpay::InvalidSaferpayPayment)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end