activemerchant-payrix 0.0.1
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.
- checksums.yaml +7 -0
- data/.github/workflows/release.yml +24 -0
- data/.github/workflows/run-tests.yml +20 -0
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/LICENSE +7 -0
- data/Rakefile +40 -0
- data/Readme.md +52 -0
- data/activemerchant-payrix.gemspec +26 -0
- data/lib/activemerchant/billing/gateways/payrix.rb +396 -0
- data/lib/activemerchant/payrix/version.rb +5 -0
- data/lib/activemerchant-payrix.rb +3 -0
- data/test/comm_stub.rb +57 -0
- data/test/fixtures.yml +5 -0
- data/test/remote/gateways/payrix_test.rb +92 -0
- data/test/test_helper.rb +404 -0
- data/test/unit/gateways/payrix_test.rb +158 -0
- metadata +115 -0
@@ -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
|
data/test/test_helper.rb
ADDED
@@ -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
|