activemerchant-payrix 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,92 @@
1
+ require 'test_helper'
2
+
3
+ class RemotePayrixTest < Test::Unit::TestCase
4
+ AMOUNTS = {
5
+ invalid_card: 31,
6
+ expired_card: 54,
7
+ declined: 51,
8
+ insufficient_funds: 61,
9
+ technical_failure: 96
10
+ }
11
+
12
+ def setup
13
+ @gateway = PayrixGateway.new(fixtures(:payrix))
14
+
15
+ @amount = 100_00
16
+ @credit_card = credit_card('4000100011112224')
17
+ @declined_card = credit_card('4000300011112220')
18
+
19
+ @options = {
20
+ billing_address: address,
21
+ description: 'Store Purchase',
22
+ return_url: 'https://app.black.test/payrix',
23
+ transaction_reference: SecureRandom.hex(16),
24
+ email: 'user@example.com'
25
+ }
26
+ end
27
+
28
+ def test_successful_setup_purchase
29
+ response = @gateway.setup_purchase(@amount, @options)
30
+ assert_success response
31
+ assert_equal 'Succeeded', response.message
32
+ end
33
+
34
+ def test_successful_setup_purchase_with_more_options
35
+ options = @options.merge({ ip: '127.0.0.1', phone: '021 902 123' })
36
+
37
+ response = @gateway.setup_purchase(@amount, options)
38
+ assert_success response
39
+ assert_equal 'Succeeded', response.message
40
+ end
41
+
42
+ def test_failed_setup_purchase
43
+ options = @options.merge({ transaction_reference: nil })
44
+ response = @gateway.setup_purchase(@amount, options)
45
+ assert_failure response
46
+ assert_equal 'Reference is required', response.message
47
+ end
48
+
49
+ def test_failed_setup_purchase_and_details_for_token
50
+ response =
51
+ @gateway.setup_purchase(@amount + AMOUNTS[:invalid_card], @options)
52
+ assert_success response
53
+ assert_equal 'Succeeded', response.message
54
+ assert response.params['token']
55
+
56
+ details_response = @gateway.details_for(response.params['token'])
57
+ assert_failure details_response
58
+ end
59
+
60
+ def test_successful_setup_authorize
61
+ response = @gateway.setup_authorize(@amount, @options)
62
+ assert_success response
63
+ assert_equal 'Succeeded', response.message
64
+ end
65
+
66
+ # def test_failed_setup_authorize
67
+ # response = @gateway.setup_authorize(@amount, @options)
68
+ # assert_failure response
69
+ # assert_equal 'REPLACE WITH FAILED AUTHORIZE MESSAGE', response.message
70
+ # end
71
+
72
+ # def test_successful_setup_verify
73
+ # response = @gateway.setup_verify(@options)
74
+ # assert_success response
75
+ # assert_match(/REPLACE WITH SUCCESS MESSAGE/, response.message)
76
+ # end
77
+
78
+ # def test_failed_setup_verify
79
+ # response = @gateway.setup_verify(@options)
80
+ # assert_failure response
81
+ # assert_match(/REPLACE WITH FAILED PURCHASE MESSAGE/, response.message)
82
+ # end
83
+
84
+ def test_invalid_login
85
+ gateway =
86
+ PayrixGateway.new(fixtures(:payrix).merge(login: '', password: ''))
87
+
88
+ response = gateway.setup_purchase(@amount, @options)
89
+ assert_failure response
90
+ assert_match(/The Password field is required./, response.message)
91
+ end
92
+ end
@@ -0,0 +1,404 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'bundler/setup'
4
+
5
+ require 'test/unit'
6
+ require 'mocha/test_unit'
7
+
8
+ require 'yaml'
9
+ require 'json'
10
+ require 'active_merchant'
11
+ require 'comm_stub'
12
+ require 'activemerchant/billing/gateways/payrix'
13
+
14
+ # require 'active_support/core_ext/integer/time'
15
+ # require 'active_support/core_ext/numeric/time'
16
+ # require 'active_support/core_ext/time/acts_like'
17
+
18
+ ActiveMerchant::Billing::Base.mode = :test
19
+
20
+ if ENV['DEBUG_ACTIVE_MERCHANT'] == 'true'
21
+ require 'logger'
22
+ ActiveMerchant::Billing::Gateway.logger = Logger.new(STDOUT)
23
+ ActiveMerchant::Billing::Gateway.wiredump_device = STDOUT
24
+ end
25
+
26
+ # Test gateways
27
+ class SimpleTestGateway < ActiveMerchant::Billing::Gateway
28
+ end
29
+
30
+ class SubclassGateway < SimpleTestGateway
31
+ end
32
+
33
+ module ActiveMerchant
34
+ module Assertions
35
+ ASSERTION_CLASS =
36
+ if defined?(Minitest)
37
+ MiniTest::Assertion
38
+ else
39
+ Test::Unit::AssertionFailedError
40
+ end
41
+
42
+ def assert_field(field, value)
43
+ clean_backtrace { assert_equal value, @helper.fields[field] }
44
+ end
45
+
46
+ # Allows testing of negative assertions:
47
+ #
48
+ # # Instead of
49
+ # assert !something_that_is_false
50
+ #
51
+ # # Do this
52
+ # assert_false something_that_should_be_false
53
+ #
54
+ # An optional +msg+ parameter is available to help you debug.
55
+ def assert_false(boolean, message = nil)
56
+ message = build_message message, '<?> is not false or nil.', boolean
57
+
58
+ clean_backtrace do
59
+ assert_block message do
60
+ not boolean
61
+ end
62
+ end
63
+ end
64
+
65
+ # An assertion of a successful response:
66
+ #
67
+ # # Instead of
68
+ # assert response.success?
69
+ #
70
+ # # DRY that up with
71
+ # assert_success response
72
+ #
73
+ # A message will automatically show the inspection of the response
74
+ # object if things go afoul.
75
+ def assert_success(response, message = nil)
76
+ clean_backtrace do
77
+ assert response.success?,
78
+ build_message(
79
+ nil,
80
+ "#{message + "\n" if message}Response expected to succeed: <?>",
81
+ response
82
+ )
83
+ end
84
+ end
85
+
86
+ # The negative of +assert_success+
87
+ def assert_failure(response, message = nil)
88
+ clean_backtrace do
89
+ assert !response.success?,
90
+ build_message(
91
+ nil,
92
+ "#{message + "\n" if message}Response expected to fail: <?>",
93
+ response
94
+ )
95
+ end
96
+ end
97
+
98
+ def assert_valid(model, message = nil)
99
+ errors = model.validate
100
+
101
+ clean_backtrace do
102
+ assert_equal({}, errors, (message || 'Expected to be valid'))
103
+ end
104
+
105
+ errors
106
+ end
107
+
108
+ def assert_not_valid(model)
109
+ errors = model.validate
110
+
111
+ clean_backtrace do
112
+ assert_not_equal({}, errors, 'Expected to not be valid')
113
+ end
114
+
115
+ errors
116
+ end
117
+
118
+ def assert_deprecation_warning(message = nil)
119
+ ActiveMerchant.expects(:deprecated).with(message || anything)
120
+ yield
121
+ end
122
+
123
+ def refute(value, message = nil)
124
+ assert(!value, message)
125
+ end
126
+
127
+ def silence_deprecation_warnings
128
+ ActiveMerchant.stubs(:deprecated)
129
+ yield
130
+ end
131
+
132
+ def assert_no_deprecation_warning
133
+ ActiveMerchant.expects(:deprecated).never
134
+ yield
135
+ end
136
+
137
+ def assert_scrubbed(unexpected_value, transcript)
138
+ regexp =
139
+ (
140
+ if Regexp === unexpected_value
141
+ unexpected_value
142
+ else
143
+ Regexp.new(Regexp.quote(unexpected_value.to_s))
144
+ end
145
+ )
146
+ refute_match regexp,
147
+ transcript,
148
+ 'Expected the value to be scrubbed out of the transcript'
149
+ end
150
+
151
+ private
152
+
153
+ def clean_backtrace(&block)
154
+ yield
155
+ rescue ASSERTION_CLASS => e
156
+ path = File.expand_path(__FILE__)
157
+ raise ASSERTION_CLASS,
158
+ e.message,
159
+ (
160
+ e.backtrace.reject { |line|
161
+ File.expand_path(line).match?(/#{path}/)
162
+ }
163
+ )
164
+ end
165
+ end
166
+
167
+ module Fixtures
168
+ HOME_DIR =
169
+ if RUBY_PLATFORM.match?('mswin32')
170
+ ENV['HOMEPATH']
171
+ else
172
+ ENV['HOME']
173
+ end unless defined?(HOME_DIR)
174
+ LOCAL_CREDENTIALS =
175
+ File.join(HOME_DIR.to_s, '.active_merchant/fixtures.yml') unless defined?(
176
+ LOCAL_CREDENTIALS
177
+ )
178
+ DEFAULT_CREDENTIALS =
179
+ File.join(File.dirname(__FILE__), 'fixtures.yml') unless defined?(
180
+ DEFAULT_CREDENTIALS
181
+ )
182
+
183
+ private
184
+
185
+ def default_expiration_date
186
+ @default_expiration_date ||= Date.new((Time.now.year + 1), 9, 30)
187
+ end
188
+
189
+ def formatted_expiration_date(credit_card)
190
+ credit_card.expiry_date.expiration.strftime('%Y-%m')
191
+ end
192
+
193
+ def credit_card(number = '4242424242424242', options = {})
194
+ defaults =
195
+ {
196
+ number: number,
197
+ month: default_expiration_date.month,
198
+ year: default_expiration_date.year,
199
+ first_name: 'Longbob',
200
+ last_name: 'Longsen',
201
+ verification_value: options[:verification_value] || '123',
202
+ brand: 'visa'
203
+ }.update(options)
204
+
205
+ Billing::CreditCard.new(defaults)
206
+ end
207
+
208
+ def credit_card_with_track_data(number = '4242424242424242', options = {})
209
+ exp_date = default_expiration_date.strftime('%y%m')
210
+
211
+ defaults =
212
+ {
213
+ track_data:
214
+ "%B#{number}^LONGSEN/L. ^#{exp_date}1200000000000000**123******?"
215
+ }.update(options)
216
+
217
+ Billing::CreditCard.new(defaults)
218
+ end
219
+
220
+ def network_tokenization_credit_card(
221
+ number = '4242424242424242',
222
+ options = {}
223
+ )
224
+ defaults =
225
+ {
226
+ number: number,
227
+ month: default_expiration_date.month,
228
+ year: default_expiration_date.year,
229
+ first_name: 'Longbob',
230
+ last_name: 'Longsen',
231
+ verification_value: '123',
232
+ brand: 'visa'
233
+ }.update(options)
234
+
235
+ Billing::NetworkTokenizationCreditCard.new(defaults)
236
+ end
237
+
238
+ def check(options = {})
239
+ defaults =
240
+ {
241
+ name: 'Jim Smith',
242
+ bank_name: 'Bank of Elbonia',
243
+ routing_number: '244183602',
244
+ account_number: '15378535',
245
+ account_holder_type: 'personal',
246
+ account_type: 'checking',
247
+ number: '1'
248
+ }.update(options)
249
+
250
+ Billing::Check.new(defaults)
251
+ end
252
+
253
+ def apple_pay_payment_token(options = {})
254
+ # apple_pay_json_raw should contain the JSON serialization of the object described here
255
+ # https://developer.apple.com/library/IOs//documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.htm
256
+ apple_pay_json_raw = '{"version":"EC_v1","data":"","signature":""}'
257
+ defaults =
258
+ {
259
+ payment_data: ActiveSupport::JSON.decode(apple_pay_json_raw),
260
+ payment_instrument_name: 'Visa 2424',
261
+ payment_network: 'Visa',
262
+ transaction_identifier: 'uniqueidentifier123'
263
+ }.update(options)
264
+
265
+ ActiveMerchant::Billing::ApplePayPaymentToken.new(
266
+ defaults[:payment_data],
267
+ payment_instrument_name: defaults[:payment_instrument_name],
268
+ payment_network: defaults[:payment_network],
269
+ transaction_identifier: defaults[:transaction_identifier]
270
+ )
271
+ end
272
+
273
+ def address(options = {})
274
+ {
275
+ name: 'Jim Smith',
276
+ address1: '456 My Street',
277
+ address2: 'Apt 1',
278
+ company: 'Widgets Inc',
279
+ city: 'Ottawa',
280
+ state: 'ON',
281
+ zip: 'K1C2N6',
282
+ country: 'CA',
283
+ phone: '(555)555-5555',
284
+ fax: '(555)555-6666'
285
+ }.update(options)
286
+ end
287
+
288
+ def statement_address(options = {})
289
+ {
290
+ address1: '456 My Street',
291
+ address2: 'Apt 1',
292
+ city: 'Ottawa',
293
+ state: 'ON',
294
+ zip: 'K1C2N6'
295
+ }.update(options)
296
+ end
297
+
298
+ def stored_credential(*args, **options)
299
+ id = options.delete(:id) || options.delete(:network_transaction_id)
300
+
301
+ stored_credential = {
302
+ network_transaction_id: id,
303
+ initial_transaction: false
304
+ }
305
+
306
+ stored_credential[:initial_transaction] = true if args.include?(:initial)
307
+
308
+ stored_credential[:reason_type] = 'recurring' if args.include?(:recurring)
309
+ stored_credential[:reason_type] = 'unscheduled' if args.include?(
310
+ :unscheduled
311
+ )
312
+ stored_credential[:reason_type] = 'installment' if args.include?(
313
+ :installment
314
+ )
315
+
316
+ stored_credential[:initiator] = 'cardholder' if args.include?(:cardholder)
317
+ stored_credential[:initiator] = 'merchant' if args.include?(:merchant)
318
+
319
+ stored_credential
320
+ end
321
+
322
+ def generate_unique_id
323
+ SecureRandom.hex(16)
324
+ end
325
+
326
+ def all_fixtures
327
+ @@fixtures ||= load_fixtures
328
+ end
329
+
330
+ def fixtures(key)
331
+ data =
332
+ all_fixtures[key] ||
333
+ raise(StandardError, "No fixture data was found for '#{key}'")
334
+
335
+ data.dup
336
+ end
337
+
338
+ def load_fixtures
339
+ [DEFAULT_CREDENTIALS, LOCAL_CREDENTIALS].inject(
340
+ {}
341
+ ) do |credentials, file_name|
342
+ if File.exist?(file_name)
343
+ yaml_data = YAML.safe_load(File.read(file_name), aliases: true)
344
+ credentials.merge!(symbolize_keys(yaml_data))
345
+ end
346
+ credentials
347
+ end
348
+ end
349
+
350
+ def symbolize_keys(hash)
351
+ return unless hash.is_a?(Hash)
352
+
353
+ hash.symbolize_keys!
354
+ hash.each { |_k, v| symbolize_keys(v) }
355
+ end
356
+ end
357
+ end
358
+
359
+ Test::Unit::TestCase.class_eval do
360
+ include ActiveMerchant::Billing
361
+ include ActiveMerchant::Assertions
362
+ include ActiveMerchant::Fixtures
363
+
364
+ def capture_transcript(gateway)
365
+ transcript = ''
366
+ gateway.class.wiredump_device = transcript
367
+
368
+ yield
369
+
370
+ transcript
371
+ end
372
+
373
+ def dump_transcript_and_fail(gateway, amount, credit_card, params)
374
+ transcript =
375
+ capture_transcript(gateway) do
376
+ gateway.purchase(amount, credit_card, params)
377
+ end
378
+
379
+ File.open('transcript.log', 'w') { |f| f.write(transcript) }
380
+ assert false,
381
+ 'A purchase transcript has been written to transcript.log for you to test scrubbing with.'
382
+ end
383
+ end
384
+
385
+ class MockResponse
386
+ attr_reader :code, :body, :message
387
+ attr_accessor :headers
388
+
389
+ def self.succeeded(body, message = '')
390
+ MockResponse.new(200, body, message)
391
+ end
392
+
393
+ def self.failed(body, http_status_code = 422, message = '')
394
+ MockResponse.new(http_status_code, body, message)
395
+ end
396
+
397
+ def initialize(code, body, message = '', headers = {})
398
+ @code, @body, @message, @headers = code, body, message, headers
399
+ end
400
+
401
+ def [](header)
402
+ @headers[header]
403
+ end
404
+ end
@@ -0,0 +1,158 @@
1
+ require 'test_helper'
2
+
3
+ class PayrixTest < Test::Unit::TestCase
4
+ include CommStub
5
+
6
+ def setup
7
+ @gateway =
8
+ PayrixGateway.new(
9
+ login: 'login',
10
+ password: 'password',
11
+ business_id: 1,
12
+ service: :hpp
13
+ )
14
+ @amount = 100_00
15
+
16
+ @options = {
17
+ address: address,
18
+ description: 'Store Purchase',
19
+ ip: '127.0.0.1',
20
+ return_url: 'https://example.net',
21
+ transaction_reference: '1234'
22
+ }
23
+ end
24
+
25
+ def test_failed_login
26
+ @gateway.expects(:ssl_request).returns(failed_login_response)
27
+ response = @gateway.setup_purchase(@amount, @options)
28
+
29
+ assert_failure response
30
+ assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error],
31
+ response.error_code
32
+ end
33
+
34
+ def test_hpp_successful_purchase
35
+ response =
36
+ stub_comms { @gateway.setup_purchase(@amount, @options) }
37
+ .check_request do |_verb, endpoint, _data, headers|
38
+ unless endpoint =~ /login$/
39
+ assert_equal 'Bearer ACCESS_TOKEN', headers['Authorization']
40
+ end
41
+ end
42
+ .respond_with(successful_login_response, successful_hpp_response)
43
+
44
+ assert_success response
45
+
46
+ assert_equal 'TOKEN', response.token
47
+ assert_match(/sandbox\.hosted\.paymentsapi\.io/, response.redirect_url)
48
+ assert response.test?
49
+ end
50
+
51
+ def test_hpp_failed_purchase
52
+ stub_response(failed_hpp_response)
53
+
54
+ response = @gateway.setup_purchase(@amount, @options)
55
+ assert_failure response
56
+ assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error],
57
+ response.error_code
58
+ end
59
+
60
+ def test_hpp_successful_authorize
61
+ response =
62
+ stub_comms { @gateway.setup_authorize(@amount, @options) }
63
+ .check_request do |_verb, endpoint, data, headers|
64
+ unless endpoint =~ /login$/
65
+ payload = JSON.parse(data)
66
+ assert_equal 'PREAUTH', payload['Transaction']['ProcessType']
67
+ end
68
+ end
69
+ .respond_with(successful_login_response, successful_hpp_response)
70
+
71
+ assert_success response
72
+
73
+ assert_equal 'TOKEN', response.token
74
+ assert_match(/sandbox\.hosted\.paymentsapi\.io/, response.redirect_url)
75
+ assert response.test?
76
+ end
77
+
78
+ def test_details_for_successful_token
79
+ stub_response(successful_details_for_token_response)
80
+
81
+ response = @gateway.details_for('TOKEN')
82
+
83
+ assert_success response
84
+
85
+ assert_equal 'TOKEN', response.token
86
+ assert response.test?
87
+ end
88
+
89
+ def test_details_for_waiting_token
90
+ stub_response(waiting_details_for_token_response)
91
+
92
+ response = @gateway.details_for('TOKEN')
93
+
94
+ assert_failure response
95
+
96
+ assert 'Token URL not yet accessed', response.message
97
+ assert_equal 'TOKEN', response.token
98
+ assert response.test?
99
+ end
100
+
101
+ def test_details_for_failed_token
102
+ stub_response(failed_details_for_token_response)
103
+
104
+ response = @gateway.details_for('TOKEN')
105
+
106
+ assert_failure response
107
+
108
+ assert response.test?
109
+ assert_equal 'TOKEN', response.token
110
+ assert_equal 'PROCESSED_REJECTED', response.error_code
111
+ assert_equal 'Invalid credit card', response.message
112
+ end
113
+
114
+ def test_scrub
115
+ assert_false @gateway.supports_scrubbing?
116
+ end
117
+
118
+ private
119
+
120
+ def successful_login_response
121
+ '{"access_token":"ACCESS_TOKEN","expires_in":3600,"token_type":"Bearer","scope":"integrapay.api.public"}'
122
+ end
123
+
124
+ def failed_login_response
125
+ '{"errorCode":"BadRequest","errorMessage":"The Password field is required.","errorDetail":"Password"}'
126
+ end
127
+
128
+ def successful_hpp_response
129
+ '{"token":"TOKEN","redirectToUrl":"https://sandbox.hosted.paymentsapi.io/ui/hpp/api/65026106-fd50-4c09-a43b-9c6bab4ab65f"}'
130
+ end
131
+
132
+ def failed_hpp_response
133
+ '{"errorCode":"BadRequest","errorMessage":"Reference is required","errorDetail":"Transaction.Reference"}'
134
+ end
135
+
136
+ def successful_details_for_token_response
137
+ '{"token":"TOKEN","type":"HPP","time":"2021-11-22T20:48:00+00:00","status":"PROCESSED_SUCCESSFUL","statusDescription":"PROCESSED_SUCCESSFUL","returnUrl":"https://app.black.test/public/client/e4xpJS48v/payment/success","redirectToUrl":"https://sandbox.hosted.paymentsapi.io/ui/hpp/api/TOKEN","template":"60357dc7-de7a-446a-a1c1-8d228eab89a0","templateName":"Basic","transaction":{"business":{"businessId":"90024","businessName":"Debtor Daddy Test"},"time":"2021-11-22T20:51:49.89+00:00","transactionId":"2272290","secondaryTransactionId":"RT732135","reference":"c76684ed583be031c58e1464819a6529","description":"Purchase","scheduleReference":null,"amount":61.87,"amountRequested":61.87,"amountRefunded":0.00,"currency":"AUD","type":"RT","typeDescription":"Realtime Payment - Website","statusCode":"S","subStatusCode":null,"statusDescription":"Settled","paymentMethod":"VISA","payer":null,"card":{"cardNumber":"411111xxxxxx1111","cardholderName":"TEST CARD","cardExpires":"2027-11-01T00:00:00","cardType":"Visa"},"bankAccount":null,"rejectionRecovery":null,"verification":null,"source":null,"recurringReference":null,"cardStorageType":null,"cardAuthorizationType":null,"cardAuthorizationReference":"TG-cd217b17-8278-4a3d-b1ab-5ff5b7118281","profile":null},"payer":null,"schedule":null,"requestHpp":{"returnUrl":"https://app.black.test/public/client/e4xpJS48v/payment/success","template":"Basic","transaction":{"processType":"COMPLETE","reference":"c76684ed583be031c58e1464819a6529","description":"Purchase","amount":61.87,"currencyCode":"USD"},"payer":{"savePayer":false,"uniqueReference":null,"groupReference":null,"familyOrBusinessName":null,"givenName":null,"email":null,"phone":"018005001","mobile":"017775001","address":null,"dateOfBirth":null,"extraInfo":null},"audit":null},"events":[{"event":"WAITING","time":"2021-11-22T20:48:00+00:00","description":null,"username":"API: ","ip":"120.136.2.157"},{"event":"VALIDATED","time":"2021-11-22T20:48:00+00:00","description":null,"username":null,"ip":""},{"event":"PROCESSED_SUCCESSFUL","time":"2021-11-22T20:52:00+00:00","description":null,"username":null,"ip":"120.136.2.157"},{"event":"EXPIRED","time":"2021-11-22T21:08:00+00:00","description":null,"username":null,"ip":null}]}'
138
+ end
139
+
140
+ def waiting_details_for_token_response
141
+ '{"token":"TOKEN","type":"HPP","time":"2021-11-21T23:24:00+00:00","status":"WAITING","statusDescription":"WAITING","returnUrl":"https://app.black.test/payrix","redirectToUrl":"https://sandbox.hosted.paymentsapi.io/ui/hpp/api/TOKEN","template":"60357dc7-de7a-446a-a1c1-8d228eab89a0","templateName":"Basic","transaction":null,"payer":null,"schedule":null,"requestHpp":{"returnUrl":"https://app.black.test/payrix","template":"Basic","transaction":{"processType":"COMPLETE","reference":"030ec6d893dabcf48bad2859a61735b5","description":"Store Purchase","amount":100.00,"currencyCode":"USD"},"payer":{"savePayer":false,"uniqueReference":null,"groupReference":null,"familyOrBusinessName":null,"givenName":null,"email":"user@example.com","phone":null,"mobile":null,"address":{"line1":"456 My Street","line2":"Apt 1","suburb":null,"state":"ON","postCode":"K1C2N6","country":"CA"},"dateOfBirth":null,"extraInfo":null},"audit":null},"events":[{"event":"WAITING","time":"2021-11-21T23:24:00+00:00","description":null,"username":"API: ","ip":"120.136.2.157"}]}'
142
+ end
143
+
144
+ def failed_details_for_token_response
145
+ '{"token":"TOKEN","type":"HPP","time":"2021-11-23T02:47:00+00:00","status":"PROCESSED_REJECTED","statusDescription":"PROCESSED_REJECTED","returnUrl":"https://app.black.test/payrix","redirectToUrl":"https://sandbox.hosted.paymentsapi.io/ui/hpp/api/TOKEN","template":"60357dc7-de7a-446a-a1c1-8d228eab89a0","templateName":"Basic","transaction":{"business":{"businessId":"90024","businessName":"Debtor Daddy Test"},"time":"2021-11-23T02:47:33.083+00:00","transactionId":"2272471","secondaryTransactionId":"RT732330","reference":"3632fa83cfcd4851137c2dec371717a8","description":"Store Purchase","scheduleReference":null,"amount":100.31,"amountRequested":100.31,"amountRefunded":0.00,"currency":"AUD","type":"RT","typeDescription":"Realtime Payment - Website","statusCode":"R","subStatusCode":"R3","statusDescription":"Rejected: Invalid Credit Card","paymentMethod":"VISA","payer":null,"card":{"cardNumber":"411111xxxxxx1111","cardholderName":"TEST CARD","cardExpires":"2027-03-01T00:00:00","cardType":"Visa"},"bankAccount":null,"rejectionRecovery":null,"verification":null,"source":null,"recurringReference":null,"cardStorageType":null,"cardAuthorizationType":null,"cardAuthorizationReference":"TG-491ea49f-ac45-43cb-a074-4305493e79c0","profile":null},"payer":null,"schedule":null,"requestHpp":{"returnUrl":"https://app.black.test/payrix","template":"Basic","transaction":{"processType":"COMPLETE","reference":"3632fa83cfcd4851137c2dec371717a8","description":"Store Purchase","amount":100.31,"currencyCode":"USD"},"payer":{"savePayer":false,"uniqueReference":null,"groupReference":null,"familyOrBusinessName":null,"givenName":null,"email":"user@example.com","phone":null,"mobile":null,"address":{"line1":"456 My Street","line2":"Apt 1","suburb":null,"state":"ON","postCode":"K1C2N6","country":"CA"},"dateOfBirth":null,"extraInfo":null},"audit":null},"events":[{"event":"WAITING","time":"2021-11-23T02:47:00+00:00","description":null,"username":"API: ","ip":"120.136.2.157"},{"event":"VALIDATED","time":"2021-11-23T02:47:00+00:00","description":null,"username":null,"ip":""},{"event":"PROCESSED_SUCCESSFUL","time":"2021-11-23T02:48:00+00:00","description":null,"username":null,"ip":"120.136.2.157"}]}'
146
+ end
147
+
148
+ def stub_comms(gateway = @gateway, method_to_stub = :ssl_request, &action)
149
+ super
150
+ end
151
+
152
+ def stub_response(response)
153
+ @gateway
154
+ .expects(:ssl_request)
155
+ .times(2)
156
+ .returns(successful_login_response, response)
157
+ end
158
+ end