solidus_six_saferpay 0.1.3 → 0.2.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.
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