solidus_six_saferpay 0.1.8 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/README.md +3 -0
  4. data/app/assets/javascripts/solidus_six_saferpay/saferpay_payment.js +4 -1
  5. data/app/controllers/spree/solidus_six_saferpay/checkout_controller.rb +65 -41
  6. data/app/controllers/spree/solidus_six_saferpay/transaction/checkout_controller.rb +1 -1
  7. data/app/models/spree/payment_method/saferpay_payment_method.rb +1 -1
  8. data/app/models/spree/payment_method/saferpay_payment_page.rb +2 -2
  9. data/app/models/spree/payment_method/saferpay_transaction.rb +2 -2
  10. data/app/services/spree/solidus_six_saferpay/cancel_authorized_payment.rb +33 -0
  11. data/app/services/spree/solidus_six_saferpay/initialize_payment.rb +0 -1
  12. data/app/services/spree/solidus_six_saferpay/initialize_transaction.rb +0 -1
  13. data/app/services/spree/solidus_six_saferpay/inquire_payment.rb +27 -1
  14. data/app/services/spree/solidus_six_saferpay/order_not_found_handler.rb +28 -0
  15. data/app/services/spree/solidus_six_saferpay/payment_not_found_handler.rb +28 -0
  16. data/app/services/spree/solidus_six_saferpay/payment_processing_success_handler.rb +26 -0
  17. data/app/views/spree/checkout/payment/_saferpay_payment.html.erb +2 -2
  18. data/app/views/spree/solidus_six_saferpay/checkout/{iframe_breakout_redirect.html.erb → iframe_breakout_redirect.erb} +1 -1
  19. data/config/locales/de.yml +3 -0
  20. data/config/locales/en.yml +3 -0
  21. data/config/locales/fr.yml +3 -0
  22. data/config/routes.rb +6 -6
  23. data/lib/solidus_six_saferpay/configuration.rb +0 -2
  24. data/lib/solidus_six_saferpay/gateway.rb +11 -11
  25. data/lib/solidus_six_saferpay/payment_page_gateway.rb +8 -9
  26. data/lib/solidus_six_saferpay/transaction_gateway.rb +8 -9
  27. data/lib/solidus_six_saferpay/version.rb +1 -1
  28. data/solidus_six_saferpay.gemspec +2 -1
  29. data/spec/controllers/spree/solidus_six_saferpay/payment_page/checkout_controller_spec.rb +8 -197
  30. data/spec/controllers/spree/solidus_six_saferpay/transaction/checkout_controller_spec.rb +8 -220
  31. data/spec/services/spree/solidus_six_saferpay/assert_payment_page_spec.rb +2 -128
  32. data/spec/services/spree/solidus_six_saferpay/authorize_transaction_spec.rb +3 -127
  33. data/spec/services/spree/solidus_six_saferpay/cancel_authorized_payment_spec.rb +58 -0
  34. data/spec/services/spree/solidus_six_saferpay/initialize_payment_page_spec.rb +0 -2
  35. data/spec/services/spree/solidus_six_saferpay/initialize_transaction_spec.rb +0 -1
  36. data/spec/services/spree/solidus_six_saferpay/inquire_payment_page_payment_spec.rb +2 -98
  37. data/spec/services/spree/solidus_six_saferpay/inquire_transaction_payment_spec.rb +2 -98
  38. data/spec/services/spree/solidus_six_saferpay/order_not_found_handler_spec.rb +30 -0
  39. data/spec/services/spree/solidus_six_saferpay/payment_not_found_handler_spec.rb +30 -0
  40. data/spec/services/spree/solidus_six_saferpay/payment_processing_success_handler_spec.rb +34 -0
  41. data/spec/services/spree/solidus_six_saferpay/process_payment_page_payment_spec.rb +1 -206
  42. data/spec/services/spree/solidus_six_saferpay/process_transaction_payment_spec.rb +1 -200
  43. data/spec/solidus_six_saferpay/configuration_spec.rb +0 -3
  44. data/spec/solidus_six_saferpay/gateway_spec.rb +1 -14
  45. data/spec/solidus_six_saferpay/payment_page_gateway_spec.rb +16 -14
  46. data/spec/solidus_six_saferpay/transaction_gateway_spec.rb +17 -14
  47. data/spec/support/shared_examples/authorize_payment.rb +132 -0
  48. data/spec/support/shared_examples/checkout_controller.rb +294 -0
  49. data/spec/support/shared_examples/inquire_payment.rb +118 -0
  50. data/spec/support/shared_examples/process_authorized_payment.rb +202 -0
  51. metadata +41 -10
  52. data/app/services/spree/solidus_six_saferpay/inquire_transaction.rb +0 -7
  53. data/spec/controllers/spree/solidus_six_saferpay/checkout_controller_spec.rb +0 -41
@@ -0,0 +1,294 @@
1
+ RSpec.shared_examples 'checkout_controller' do
2
+
3
+ routes { Spree::Core::Engine.routes }
4
+
5
+ subject { described_class.new }
6
+
7
+ let(:user) { create(:user) }
8
+ let(:order) { create(:order) }
9
+ let(:order_number) { order.number }
10
+ let(:payment_method) { create(:saferpay_payment_method_payment_page) }
11
+
12
+ before do
13
+ allow(controller).to receive_messages try_spree_current_user: user
14
+ allow(controller).to receive_messages current_order: order
15
+ allow(Spree::Order).to receive(:find_by).with(number: order_number).and_return(order)
16
+ end
17
+
18
+ describe 'GET init' do
19
+ let(:success) { false }
20
+ let(:redirect_url) { '/saferpay/redirect/url' }
21
+ let(:initialized_payment) { instance_double("Spree::SolidusSixSaferpay::InitializePayment", success?: success, redirect_url: redirect_url) }
22
+
23
+ context 'when the current order for this user is not the one for which payment is initialized' do
24
+ it 'returns an error and redirects to the cart page' do
25
+ allow(Spree::Order).to receive(:find_by).with(number: order_number).and_return(nil)
26
+
27
+ get :init, params: { order_number: order_number, payment_method_id: payment_method.id }
28
+
29
+ body = JSON.parse(response.body)
30
+ expect(body['errors']).to match(/modified/)
31
+ expect(body['redirect_url']).to eq('/cart')
32
+ expect(response.status).to eq(422)
33
+ end
34
+ end
35
+
36
+ it 'tries to initialize the saferpay payment' do
37
+ expect(initialize_payment_service_class).to receive(:call).with(order, payment_method).and_return(initialized_payment)
38
+
39
+ get :init, params: { order_number: order_number, payment_method_id: payment_method.id }
40
+ end
41
+
42
+
43
+ context 'when payment initialize succeeds' do
44
+ let(:success) { true }
45
+
46
+ before do
47
+ allow(initialize_payment_service_class).to receive(:call).with(order, payment_method).and_return(initialized_payment)
48
+ end
49
+
50
+ it 'returns the redirect_url' do
51
+ get :init, params: { order_number: order_number, payment_method_id: payment_method.id }
52
+
53
+ body = JSON.parse(response.body)
54
+ expect(body["redirect_url"]).to eq(redirect_url)
55
+ end
56
+ end
57
+
58
+ context 'when payment initialize fails' do
59
+ let(:success) { false }
60
+
61
+ before do
62
+ allow(initialize_payment_service_class).to receive(:call).with(order, payment_method).and_return(initialized_payment)
63
+ end
64
+
65
+
66
+ it 'returns an error and redirects to the cart page' do
67
+ get :init, params: { order_number: order_number, payment_method_id: payment_method.id }
68
+
69
+ body = JSON.parse(response.body)
70
+ expect(body['errors']).to match(/could not be initialized/)
71
+ expect(body['redirect_url']).to eq('/cart')
72
+ expect(response.status).to eq(422)
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+
79
+ describe 'GET success' do
80
+ context 'when the order is not found' do
81
+ let(:order) { nil }
82
+ let(:order_number) { "not_found" }
83
+
84
+ it 'calls the relevant handler service' do
85
+ expect(Spree::SolidusSixSaferpay::OrderNotFoundHandler).to receive(:call).with(controller_context: @controller, order_number: order_number)
86
+
87
+ get :success, params: { order_number: order_number }
88
+ end
89
+
90
+ it 'redirects to the cart page via iframe breakout' do
91
+ get :success, params: { order_number: order_number }
92
+ expect(assigns(:redirect_path)).to eq(routes.cart_path)
93
+ expect(response).to render_template :iframe_breakout_redirect
94
+ end
95
+ end
96
+
97
+ context 'when payment could not be created' do
98
+ # We are not creating a payment so there is none to be found in the
99
+ # controller action
100
+ let!(:payment) { nil }
101
+
102
+ it 'calls the relevant handler service' do
103
+ expect(Spree::SolidusSixSaferpay::PaymentNotFoundHandler).to receive(:call).with(controller_context: @controller, order: order)
104
+
105
+ get :success, params: { order_number: order_number }
106
+ end
107
+
108
+ it 'redirects to the cart page via iframe breakout' do
109
+ get :success, params: { order_number: order_number }
110
+ expect(assigns(:redirect_path)).to eq(routes.cart_path)
111
+ expect(response).to render_template :iframe_breakout_redirect
112
+ end
113
+ end
114
+
115
+
116
+ context 'when the order is already completed' do
117
+ let(:order) { create(:order_ready_to_ship) }
118
+
119
+ it 'redirects to the cart page via iframe breakout' do
120
+ get :success, params: { order_number: order_number }
121
+ expect(assigns(:redirect_path)).to eq(routes.cart_path)
122
+ expect(response).to render_template :iframe_breakout_redirect
123
+ end
124
+ end
125
+
126
+ context 'when payment create was successful' do
127
+ let!(:payment) { create(:six_saferpay_payment, order: order) }
128
+ let(:assert_success) { false }
129
+ let(:payment_assert) { instance_double("Spree::SolidusSixSaferpay::AssertPaymentPage", success?: assert_success) }
130
+ let(:payment_inquiry) { instance_double("Spree::SolidusSixSaferpay::InquirePaymentPagePayment", user_message: "payment inquiry message") }
131
+
132
+ it 'asserts the payment' do
133
+ expect(authorize_payment_service_class).to receive(:call).with(payment).and_return(payment_assert)
134
+ expect(inquire_payment_service_class).to receive(:call).with(payment).and_return(payment_inquiry)
135
+
136
+ get :success, params: { order_number: order_number }
137
+ end
138
+
139
+ context 'when the payment assert is successful' do
140
+ let(:assert_success) { true }
141
+ let(:process_success) { false }
142
+ let(:processed_payment) { instance_double("Spree::SolidusSixSaferpay::ProcessPaymentPagePayment", success?: process_success, user_message: "payment processing message") }
143
+
144
+ before do
145
+ allow(authorize_payment_service_class).to receive(:call).with(payment).and_return(payment_assert)
146
+ end
147
+
148
+ it 'processes the asserted payment' do
149
+ expect(process_authorization_service_class).to receive(:call).with(payment).and_return(processed_payment)
150
+
151
+ get :success, params: { order_number: order_number }
152
+ end
153
+
154
+ context 'when the processing is successful' do
155
+ let(:process_success) { true }
156
+
157
+ before do
158
+ allow(process_authorization_service_class).to receive(:call).with(payment).and_return(processed_payment)
159
+ end
160
+
161
+ it 'calls the custom success processing handler' do
162
+ expect(Spree::SolidusSixSaferpay::PaymentProcessingSuccessHandler).to receive(:call).with(controller_context: @controller, order: order)
163
+
164
+ get :success, params: { order_number: order_number }
165
+ end
166
+
167
+
168
+ context 'when order is in payment state' do
169
+ let(:order) { create(:order, state: :payment) }
170
+
171
+ it 'moves order to next state' do
172
+ expect(order).to receive(:next!)
173
+
174
+ get :success, params: { order_number: order_number }
175
+ end
176
+ end
177
+
178
+ context 'when order is already in complete state' do
179
+ let(:order) { create(:order, state: :complete) }
180
+
181
+ it 'does not modify the order state' do
182
+ expect(order).not_to receive(:next!)
183
+
184
+ get :success, params: { order_number: order_number }
185
+ end
186
+ end
187
+ end
188
+
189
+ context 'when the processing fails' do
190
+ let(:process_success) { false }
191
+
192
+ before do
193
+ allow(process_authorization_service_class).to receive(:call).with(payment).and_return(processed_payment)
194
+ end
195
+
196
+ it 'displays an error message' do
197
+ get :success, params: { order_number: order_number }
198
+
199
+ expect(flash[:error]).to eq("payment processing message")
200
+ end
201
+ end
202
+
203
+ end
204
+
205
+ context 'when the payment assert fails' do
206
+ let(:assert_success) { false }
207
+
208
+ before do
209
+ allow(authorize_payment_service_class).to receive(:call).with(payment).and_return(payment_assert)
210
+ end
211
+
212
+ it 'inquires the payment' do
213
+ expect(inquire_payment_service_class).to receive(:call).with(payment).and_return(payment_inquiry)
214
+
215
+ get :success, params: { order_number: order_number }
216
+ end
217
+
218
+ it 'displays an error message' do
219
+ expect(inquire_payment_service_class).to receive(:call).with(payment).and_return(payment_inquiry)
220
+ get :success, params: { order_number: order_number }
221
+
222
+ expect(flash[:error]).to eq("payment inquiry message")
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+ describe 'GET fail' do
229
+
230
+ context 'when the order is not found' do
231
+ let(:order) { nil }
232
+ let(:order_number) { "not_found" }
233
+
234
+
235
+ it 'calls the relevant handler service' do
236
+ expect(Spree::SolidusSixSaferpay::OrderNotFoundHandler).to receive(:call).with(controller_context: @controller, order_number: order_number)
237
+
238
+ get :fail, params: { order_number: order_number }
239
+ end
240
+
241
+ it 'redirects to the cart page via iframe breakout' do
242
+ get :fail, params: { order_number: order_number }
243
+ expect(assigns(:redirect_path)).to eq(routes.cart_path)
244
+ expect(response).to render_template :iframe_breakout_redirect
245
+ end
246
+ end
247
+
248
+ context 'when payment could not be created' do
249
+ # We are not creating a payment so there is none to be found in the
250
+ # controller action
251
+ let!(:payment) { nil }
252
+
253
+ it 'calls the relevant handler service' do
254
+ expect(Spree::SolidusSixSaferpay::PaymentNotFoundHandler).to receive(:call).with(controller_context: @controller, order: order)
255
+
256
+ get :fail, params: { order_number: order_number }
257
+ end
258
+
259
+ it 'redirects to the cart page via iframe breakout' do
260
+ get :fail, params: { order_number: order_number }
261
+ expect(assigns(:redirect_path)).to eq(routes.cart_path)
262
+ expect(response).to render_template :iframe_breakout_redirect
263
+ end
264
+ end
265
+
266
+ context 'when payment create was successful' do
267
+ let!(:payment) { create(:six_saferpay_payment, order: order) }
268
+ let(:payment_inquiry) { instance_double("Spree::SolidusSixSaferpay::InquirePaymentPagePayment", user_message: "payment inquiry message") }
269
+
270
+ it 'inquires the payment' do
271
+ expect(inquire_payment_service_class).to receive(:call).with(payment).and_return(payment_inquiry)
272
+
273
+ get :fail, params: { order_number: order_number }
274
+ end
275
+
276
+ it 'displays an error message' do
277
+ expect(inquire_payment_service_class).to receive(:call).with(payment).and_return(payment_inquiry)
278
+
279
+ get :fail, params: { order_number: order_number }
280
+
281
+ expect(flash[:error]).to eq("payment inquiry message")
282
+ end
283
+
284
+ it 'redirects to the cart page via iframe breakout' do
285
+ expect(inquire_payment_service_class).to receive(:call).with(payment).and_return(payment_inquiry)
286
+
287
+ get :fail, params: { order_number: order_number }
288
+
289
+ expect(assigns(:redirect_path)).to eq(routes.checkout_state_path(:payment))
290
+ expect(response).to render_template :iframe_breakout_redirect
291
+ end
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,118 @@
1
+ RSpec.shared_examples 'inquire_payment' do
2
+
3
+ before do
4
+ allow(subject).to receive(:gateway).and_return(double('gateway', inquire: gateway_response))
5
+ end
6
+
7
+ context 'when gateway response is not successful' do
8
+ let(:gateway_success) { false }
9
+ let(:error_behaviour) { "ABORT" }
10
+ let(:error_name) { "VALIDATION_FAILED" }
11
+ let(:error_message) { "Request validation failed" }
12
+ let(:api_response) { nil }
13
+ let(:translated_general_error) { "General Error" }
14
+ let(:translated_user_message) { "User Message" }
15
+
16
+ let(:gateway_response) do
17
+ ::SolidusSixSaferpay::GatewayResponse.new(
18
+ gateway_success,
19
+ "initialize success: #{gateway_success}",
20
+ api_response,
21
+ error_name: error_name,
22
+ )
23
+ end
24
+
25
+ it 'still indicates success' do
26
+ subject.call
27
+
28
+ expect(subject).to be_success
29
+ end
30
+
31
+ it 'adds the error message to the response hash' do
32
+ expect { subject.call }.to change { payment.response_hash }.from({}).to({error: error_name})
33
+ end
34
+
35
+ it 'sets the user message according to the api error code' do
36
+ expect(I18n).to receive(:t).with(:general_error, scope: [:solidus_six_saferpay, :errors]).once.and_return(translated_general_error)
37
+ expect(I18n).to receive(:t).with(error_name, scope: [:six_saferpay, :error_names]).once.and_return(translated_user_message)
38
+
39
+ subject.call
40
+
41
+ expect(subject.user_message).to eq("#{translated_general_error}: #{translated_user_message}")
42
+ end
43
+ end
44
+
45
+ context 'when gateway response is successful' do
46
+ let(:transaction_status) { "AUTHORIZED" }
47
+ let(:transaction_id) { "723n4MAjMdhjSAhAKEUdA8jtl9jb" }
48
+ let(:transaction_date) { "2015-01-30T12:45:22.258+01:00" }
49
+ let(:amount_value) { "100" }
50
+ let(:amount_currency) { "USD" }
51
+ let(:brand_name) { 'PaymentBrand' }
52
+ let(:display_text) { "xxxx xxxx xxxx 1234" }
53
+ let(:six_transaction_reference) { "0:0:3:723n4MAjMdhjSAhAKEUdA8jtl9jb" }
54
+
55
+ let(:payment_means) do
56
+ SixSaferpay::ResponsePaymentMeans.new(
57
+ brand: SixSaferpay::Brand.new(name: brand_name),
58
+ display_text: display_text
59
+ )
60
+ end
61
+
62
+ # https://saferpay.github.io/jsonapi/#Payment_v1_PaymentPage_Assert
63
+ # https://saferpay.github.io/jsonapi/#Payment_v1_Transaction_Authorize
64
+ let(:api_response) do
65
+ api_response_class.new(
66
+ response_header: SixSaferpay::ResponseHeader.new(request_id: 'test', spec_version: 'test'),
67
+ transaction: SixSaferpay::Transaction.new(
68
+ type: "PAYMENT",
69
+ status: transaction_status,
70
+ id: transaction_id,
71
+ date: transaction_date,
72
+ amount: SixSaferpay::Amount.new(value: amount_value, currency_code: amount_currency),
73
+ six_transaction_reference: six_transaction_reference,
74
+ ),
75
+ payment_means: payment_means
76
+ )
77
+ end
78
+
79
+ let(:gateway_success) { true }
80
+ let(:gateway_response) do
81
+ ::SolidusSixSaferpay::GatewayResponse.new(
82
+ gateway_success,
83
+ "initialize success: #{gateway_success}",
84
+ api_response
85
+ )
86
+ end
87
+
88
+ it 'updates the transaction_id' do
89
+ expect { subject.call }.to change { payment.transaction_id }.from(nil).to(transaction_id)
90
+ end
91
+
92
+ it 'updates the transaction status' do
93
+ expect { subject.call }.to change { payment.transaction_status }.from(nil).to(transaction_status)
94
+ end
95
+
96
+ it 'updates the transaction date' do
97
+ expect { subject.call }.to change { payment.transaction_date }.from(nil).to(DateTime.parse(transaction_date))
98
+ end
99
+
100
+ it 'updates the six_transaction_reference' do
101
+ expect { subject.call }.to change { payment.six_transaction_reference }.from(nil).to(six_transaction_reference)
102
+ end
103
+
104
+ it 'updates the display_text' do
105
+ expect { subject.call }.to change { payment.display_text }.from(nil).to(display_text)
106
+ end
107
+
108
+ it 'updates the response hash' do
109
+ expect { subject.call }.to change { payment.response_hash }.from(payment.response_hash).to(api_response.to_h)
110
+ end
111
+
112
+ it 'indicates success' do
113
+ subject.call
114
+
115
+ expect(subject).to be_success
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,202 @@
1
+ RSpec.shared_examples 'process_authorized_payment' do
2
+ before do
3
+ allow(subject).to receive(:gateway).and_return(double('gateway'))
4
+ end
5
+
6
+ context 'liability_shift check' do
7
+
8
+ before do
9
+ # ensure other methods don't modify outcome
10
+ allow(subject).to receive(:validate_payment!)
11
+ allow(subject).to receive(:cancel_old_solidus_payments)
12
+ allow(payment).to receive(:create_solidus_payment!)
13
+ end
14
+
15
+ context 'when liability shift is required' do
16
+ context 'and liability shift is not granted' do
17
+
18
+ let(:payment) { create(:six_saferpay_payment, :authorized, :without_liability_shift) }
19
+
20
+ it 'cancels the payment' do
21
+ expect(payment.payment_method.preferred_require_liability_shift).to be true
22
+ expect(payment.liability.liability_shift).to be false
23
+
24
+ expect(subject.gateway).to receive(:void).with(payment.transaction_id)
25
+
26
+ subject.call
27
+ end
28
+
29
+ it 'indicates failure' do
30
+ expect(payment.payment_method.preferred_require_liability_shift).to be true
31
+ expect(payment.liability.liability_shift).to be false
32
+
33
+ expect(subject.gateway).to receive(:void).with(payment.transaction_id)
34
+
35
+ subject.call
36
+
37
+ expect(subject).not_to be_success
38
+ end
39
+
40
+ end
41
+
42
+ context 'and liability shift is granted' do
43
+ it "doesn't cancel the payment" do
44
+ expect(payment.payment_method.preferred_require_liability_shift).to be true
45
+ expect(payment.liability.liability_shift).to be true
46
+
47
+ expect(subject.gateway).not_to receive(:void)
48
+
49
+ subject.call
50
+ end
51
+
52
+ it 'passes the liability shift check' do
53
+ expect(payment.payment_method.preferred_require_liability_shift).to be true
54
+ expect(payment.liability.liability_shift).to be true
55
+
56
+ subject.call
57
+
58
+ expect(subject).to be_success
59
+ end
60
+ end
61
+ end
62
+
63
+ context 'when liability shift is not required' do
64
+ let(:payment_method) { create(:saferpay_payment_method, :no_require_liability_shift) }
65
+
66
+ context 'and liability shift is not granted' do
67
+ let(:payment) { create(:six_saferpay_payment, :authorized, :without_liability_shift, payment_method: payment_method) }
68
+
69
+ it "doesn't cancel the payment" do
70
+ expect(payment.payment_method.preferred_require_liability_shift).to be false
71
+ expect(payment.liability.liability_shift).to be false
72
+
73
+ expect(subject.gateway).not_to receive(:void)
74
+
75
+ subject.call
76
+ end
77
+
78
+ it 'passes the liability shift check' do
79
+ expect(payment.payment_method.preferred_require_liability_shift).to be false
80
+ expect(payment.liability.liability_shift).to be false
81
+ subject.call
82
+
83
+ expect(subject).to be_success
84
+ end
85
+ end
86
+
87
+ context 'and liability shift is granted' do
88
+ let(:payment) { create(:six_saferpay_payment, :authorized, payment_method: payment_method) }
89
+ it "doesn't cancel the payment" do
90
+ expect(payment.payment_method.preferred_require_liability_shift).to be false
91
+ expect(payment.liability.liability_shift).to be true
92
+
93
+ expect(subject.gateway).not_to receive(:void)
94
+
95
+ subject.call
96
+ end
97
+
98
+ it 'passes the liability shift check' do
99
+ expect(payment.payment_method.preferred_require_liability_shift).to be false
100
+ expect(payment.liability.liability_shift).to be true
101
+ subject.call
102
+
103
+ expect(subject).to be_success
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ context 'payment validation' do
110
+ before do
111
+ allow(subject).to receive(:gateway).and_return(double('gateway'))
112
+
113
+
114
+ # ensure other methods don't modify outcome
115
+ allow(subject).to receive(:check_liability_shift_requirements!)
116
+ allow(subject).to receive(:cancel_old_solidus_payments)
117
+ allow(payment).to receive(:create_solidus_payment!)
118
+ end
119
+
120
+ it 'validates the payment' do
121
+ expect(Spree::SolidusSixSaferpay::PaymentValidator).to receive(:call).with(payment)
122
+ subject.call
123
+ end
124
+
125
+ context 'when the payment is invalid' do
126
+ it 'cancels the payment' do
127
+ expect(subject.gateway).to receive(:void).with(payment.transaction_id)
128
+
129
+ subject.call
130
+ end
131
+
132
+ it 'indicates failure' do
133
+ allow(subject.gateway).to receive(:void).with(payment.transaction_id)
134
+
135
+ subject.call
136
+
137
+ expect(subject).not_to be_success
138
+ end
139
+ end
140
+
141
+ context 'when the payment is valid' do
142
+ before do
143
+ allow(Spree::SolidusSixSaferpay::PaymentValidator).to receive(:call).with(payment).and_return(true)
144
+ end
145
+
146
+ it "doesn't cancel the payment" do
147
+ expect(subject.gateway).not_to receive(:void)
148
+
149
+ subject.call
150
+ end
151
+
152
+ it 'indicates success' do
153
+ subject.call
154
+
155
+ expect(subject).to be_success
156
+ end
157
+ end
158
+ end
159
+
160
+ context 'when the payment has passed all validations' do
161
+ before do
162
+ allow(subject).to receive(:check_liability_shift_requirements!).and_return(true)
163
+ allow(subject).to receive(:validate_payment!).and_return(true)
164
+ end
165
+
166
+ context 'when previous solidus payments exist for this order' do
167
+ let(:order) { payment.order }
168
+ let!(:previous_payment_invalid) { create(:payment_using_saferpay, order: order) }
169
+ let!(:previous_payment_checkout) { create(:payment_using_saferpay, order: order) }
170
+
171
+ before do
172
+ # This is bad practice because we mock which payments are invalidated here.
173
+ # The reason is that you can't stub methods on AR objects that
174
+ # are loaded from the DB and because #solidus_payments_to_cancel
175
+ # is just AR scopes, I prefer this test over using stuff like
176
+ # #expect_any_instance_of
177
+ allow(subject).to receive(:solidus_payments_to_cancel).and_return([previous_payment_checkout])
178
+ end
179
+
180
+ it 'cancels old solidus payments' do
181
+ expect(previous_payment_invalid).not_to receive(:cancel!)
182
+ expect(previous_payment_checkout).to receive(:cancel!)
183
+
184
+ subject.call
185
+ end
186
+ end
187
+
188
+ it 'creates a new solidus payment' do
189
+ expect(payment).to receive(:create_solidus_payment!)
190
+
191
+ subject.call
192
+ end
193
+
194
+ it 'indicates success' do
195
+ allow(payment).to receive(:create_solidus_payment!)
196
+
197
+ subject.call
198
+
199
+ expect(subject).to be_success
200
+ end
201
+ end
202
+ end