activemerchant-payrix 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b5f27c2329b7dd97eea8fa718529e9cfe446496aec74279f3ded59b760a70d0c
4
+ data.tar.gz: e18c98fc51a9e46d4da61555ae51913e2c402a9ab17e5f1175d3129aecfa6c34
5
+ SHA512:
6
+ metadata.gz: aae551c3f73eac29a2537d8bbfc5dd4e78cf79fea954a699de6ad3b6364d95b5e34cd78f38e67e398ce95a4e336fb10ce8fc19095089d2bb85ab38b34c231be6
7
+ data.tar.gz: 8da97305ef6a13caa2844619446eee91016389ad40b655db10568495b7e05f5fb1f7408bfad0c6cbca718874a5413cdf0ff1af95c3562d21e0bc80424607b64f
@@ -0,0 +1,24 @@
1
+ on:
2
+ push:
3
+ branches: [main]
4
+
5
+ jobs:
6
+ push:
7
+ name: Push gem to RubyGems.org
8
+ runs-on: ubuntu-latest
9
+
10
+ permissions:
11
+ id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
12
+ contents: write # IMPORTANT: this permission is required for `rake release` to push the release tag
13
+
14
+ steps:
15
+ # Set up
16
+ - uses: actions/checkout@v4
17
+ - name: Set up Ruby
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ bundler-cache: true
21
+ ruby-version: ruby
22
+
23
+ # Release
24
+ - uses: rubygems/release-gem@v1
@@ -0,0 +1,20 @@
1
+ on:
2
+ push:
3
+ branches: [main]
4
+ pull_request:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+ - uses: actions/checkout@v3
13
+ - name: Set up Ruby
14
+ uses: ruby/setup-ruby@359bebbc29cbe6c87da6bc9ea3bc930432750108
15
+ with:
16
+ ruby-version: '3.1'
17
+ - name: Install dependencies
18
+ run: bundle install
19
+ - name: Run tests
20
+ run: bundle exec rake test:units
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ spec/test_credentials.rb
6
+ .vscode
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use @activemerchant-payrix --create
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2022 Mark Haussmann
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
2
+ require 'activemerchant/payrix/version'
3
+
4
+ begin
5
+ require 'bundler'
6
+ Bundler.setup
7
+ rescue LoadError => e
8
+ puts "Error loading bundler (#{e.message}): \"gem install bundler\" for bundler support."
9
+ require 'rubygems'
10
+ end
11
+
12
+ require 'rake'
13
+ require 'rake/testtask'
14
+ require 'bundler/gem_tasks'
15
+
16
+ task :tag_release do
17
+ system "git tag 'v#{ActiveMerchant::Payrix::VERSION}'"
18
+ system 'git push --tags'
19
+ end
20
+
21
+ desc 'Run the unit test suite'
22
+ task default: 'test:units'
23
+ task test: 'test:units'
24
+
25
+ namespace :test do
26
+ Rake::TestTask.new(:units) do |t|
27
+ t.pattern = 'test/unit/**/*_test.rb'
28
+ t.libs << 'test'
29
+ t.verbose = false
30
+ end
31
+
32
+ desc 'Run all tests that do not require network access'
33
+ task local: %w[test:units]
34
+
35
+ Rake::TestTask.new(:remote) do |t|
36
+ t.pattern = 'test/remote/**/*_test.rb'
37
+ t.libs << 'test'
38
+ t.verbose = true
39
+ end
40
+ end
data/Readme.md ADDED
@@ -0,0 +1,52 @@
1
+ # activemerchant-payrix
2
+
3
+ ActiveMerchant Payrix is an add-on for ActiveMerchant which provides a gateway
4
+ for [Payrix's](https://www.payrix.com/)
5
+ [HPP service](https://docs.rest.paymentsapi.io/#5bd000e6-e156-4242-962b-3b93e9ed8f9e).
6
+
7
+ ## Installation
8
+
9
+ Before installing the gem you should have a Payrix account ready to use. If not
10
+ then [Contact Payrix for more info.](https://www.payrix.com/)
11
+
12
+ To install simply add the following line to your `Gemfile` and then run
13
+ `bundle install`:
14
+
15
+ ```ruby
16
+ gem 'activemerchant-payrix'
17
+ ```
18
+
19
+ The gateway can be initialised by passing your login details like so:
20
+
21
+ ```ruby
22
+ gateway = ActiveMerchant::Billing::PayrixGateway.new(:login => 'login', :password => 'pass', :business_id => 'num', :service => 'hpp')
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ Once you have an initialised gateway, you can use the `setup_purchase` method:
28
+
29
+ ```ruby
30
+ amount = 1000 # 1000 cents is $10.00 AUD
31
+ options = { return_url: return_url } # Pass the return url to Payrix
32
+
33
+ response = gateway.purchase(amount, options)
34
+
35
+ if response.sucess?
36
+ puts "All OK!"
37
+ else
38
+ puts response.message # Output the error message
39
+ end
40
+ ```
41
+
42
+ ## License
43
+
44
+ activemerchant-payrix is distributed under a standard MIT license, see
45
+ [LICENSE](https://github.com/mhssmnn/activemerchant-payrix/blob/master/LICENSE)
46
+ for further information.
47
+
48
+ ## Contributing
49
+
50
+ Fork on GitHub and after you’ve committed tested patches, send a pull request.
51
+
52
+ To get tests running simply run `bundle install` and then `rake test:units`.
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'activemerchant/payrix/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'activemerchant-payrix'
7
+ s.version = ActiveMerchant::Payrix::VERSION
8
+ s.authors = ['Mark Haussmann']
9
+ s.email = ['mark.haussmann@gmail.com']
10
+ s.homepage = ''
11
+ s.summary = 'ActiveMerchant Payrix Plugin'
12
+ s.description = 'An ActiveMerchant plugin that provides a Payrix gateway'
13
+
14
+ s.rubyforge_project = 'activemerchant-payrix'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables =
19
+ `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
20
+ s.require_paths = ['lib']
21
+
22
+ s.add_development_dependency('test-unit', '~> 3')
23
+ s.add_development_dependency('mocha', '~> 2')
24
+ s.add_development_dependency('rake')
25
+ s.add_runtime_dependency 'activemerchant', '>= 1.20.0'
26
+ end
@@ -0,0 +1,396 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class PayrixGateway < Gateway
4
+ self.test_url = 'https://sandbox.rest.paymentsapi.io'
5
+ self.live_url = 'https://rest.paymentsapi.io'
6
+
7
+ class_attribute :test_auth_url
8
+ self.test_auth_url = 'https://sandbox.auth.paymentsapi.io/login'
9
+
10
+ class_attribute :auth_url
11
+ self.auth_url = 'https://auth.paymentsapi.io/login'
12
+
13
+ self.supported_countries = %w[US AU NZ]
14
+ self.default_currency = 'USD'
15
+ self.supported_cardtypes = %i[visa master american_express discover]
16
+ self.money_format = :dollars
17
+
18
+ self.homepage_url = 'https://www.payrix.com/'
19
+ self.display_name = 'Payrix'
20
+
21
+ STANDARD_ERROR_CODE_MAPPING = {
22
+ 'EXPIRED' => STANDARD_ERROR_CODE[:expired_card],
23
+ 'FRAUD_CHECK_DECLINE' => STANDARD_ERROR_CODE[:invalid_cvc],
24
+ 'FRAUD_CHECK_ERROR' => STANDARD_ERROR_CODE[:processing_error],
25
+ 'ERROR' => STANDARD_ERROR_CODE[:processing_error],
26
+ 'BadRequest' => STANDARD_ERROR_CODE[:processing_error],
27
+ 'FunctionNotAllowed' => STANDARD_ERROR_CODE[:unsupported_feature],
28
+ 'InternalServerError' => STANDARD_ERROR_CODE[:processing_error],
29
+ 'InvalidApiToken' => STANDARD_ERROR_CODE[:config_error]
30
+ }
31
+
32
+ TRANSACTION_TYPES = {
33
+ # Full sale - Funds are fully collected and ready to be settled to your business
34
+ purchase: 'COMPLETE',
35
+ # Pre-authorisation only - Funds are reserved on the person's card and will not be collected until you use the Capture function. Pre-auths that aren't captured automatically expire (usually occurs within 2-3 days)
36
+ authorize: 'PREAUTH',
37
+ # This allows you to perform a zero-dollar pre-authorisation for the purpose of checking that a particular card is valid and active.
38
+ # It also assists in meeting card-on-file storage obligations, and customer-initiated-transaction/merchant-initiated-transaction mandates, by allowing you to verify a card using customer authentication before storage, and obtain a reference that can be provided with future recurring transactions on that card to link them to the initial authorisation.
39
+ verify: 'VERIFY'
40
+ }
41
+
42
+ ENDPOINTS = {
43
+ hpp: 'hpp/',
44
+ eddr: 'eddr/',
45
+ vault: 'vault/',
46
+ access_token: 'login'
47
+ }
48
+
49
+ TOKEN_STATUS = {
50
+ waiting: 'WAITING',
51
+ validated: 'VALIDATED',
52
+ processed_successful: 'PROCESSED_SUCCESSFUL',
53
+ processed_rejected: 'PROCESSED_REJECTED',
54
+ cancelled: 'CANCELLED',
55
+ error: 'ERROR',
56
+ fraud_check_decline: 'FRAUD_CHECK_DECLINE',
57
+ fraud_check_error: 'FRAUD_CHECK_ERROR',
58
+ expired: 'EXPIRED'
59
+ }
60
+
61
+ TOKEN_STATUS_DESCRIPTIONS = {
62
+ 'WAITING' => 'Token URL not yet accessed',
63
+ 'VALIDATED' => 'Token URL loaded',
64
+ 'PROCESSED_SUCCESSFUL' => 'URL completed successfully',
65
+ 'PROCESSED_REJECTED' => 'URL Opened, not completed and closed',
66
+ 'CANCELLED' => 'URL Completed but cancelled on confirmation page',
67
+ 'ERROR' => 'Internal error received',
68
+ 'FRAUD_CHECK_DECLINE' =>
69
+ 'Payment attempted but declined by Fraud check',
70
+ 'FRAUD_CHECK_ERROR' =>
71
+ 'Payment attempted but Fraud Check error received',
72
+ 'EXPIRED' => 'Token has expired and is no longer useable'
73
+ }
74
+
75
+ TRANSACTION_STATUS = { cleared: 'C', settled: 'S', rejected: 'R' }
76
+
77
+ REJECTION_REASONS = {
78
+ 'R1' => 'Insufficient funds',
79
+ 'R2' => 'Invalid bank account number',
80
+ 'R3' => 'Invalid credit card',
81
+ 'R4' => 'Expired credit card',
82
+ 'R5' => 'Invalid transaction',
83
+ 'R6' => 'Transaction declined',
84
+ 'R7' => 'Authority revoked by payer',
85
+ 'R8' => 'Payer deceased',
86
+ 'R9' => 'Invalid bank account',
87
+ 'R10' => 'Bank account closed',
88
+ 'R11' => 'Invalid payer contact details',
89
+ 'R12' => 'Direct debit claim',
90
+ 'R13' => 'Credit card chargeback',
91
+ 'R14' => 'Stolen/pick up card',
92
+ 'R15' => 'Limits exceeded',
93
+ 'R16' => 'Pre-auth expired',
94
+ 'R17' => 'Not processed (payer inactive)',
95
+ 'R18' => 'Fraud protection triggered',
96
+ 'R19' => 'Voided',
97
+ 'R20' => 'Fraud Check / 3-D Secure: Authentication Failed',
98
+ 'R21' => 'Fraud Check / 3-D Secure: Unable to Authenticate',
99
+ 'R22' => 'Fraud Check / 3-D Secure: Transaction Abandoned',
100
+ 'R23' => 'Fraud Check / 3-D Secure: Error Occurred',
101
+ 'RF' => 'Partially refunded',
102
+ 'UR' => 'Under review'
103
+ }
104
+
105
+ def initialize(options = {})
106
+ requires!(options, :login, :password, :business_id)
107
+
108
+ @business_id = options[:business_id]
109
+ @service = (options[:service]&.to_sym || :hpp)
110
+ @token = nil
111
+
112
+ unless ENDPOINTS.key?(@service)
113
+ raise ArgumentError, "Unsupported service `#{@service}'."
114
+ end
115
+
116
+ super
117
+ end
118
+
119
+ def setup_purchase(money, options = {})
120
+ requires!(options, :return_url, :transaction_reference)
121
+ requires!(options, :unique_reference, :name) if store?
122
+
123
+ post = new_post
124
+
125
+ add_transaction(post, money, options)
126
+ add_customer_data(post, options)
127
+ add_address(post, options)
128
+ add_template(post, options)
129
+ add_audit(post, options)
130
+ add_return_url(post, options)
131
+
132
+ MultiResponse.run do |r|
133
+ r.process { commit :access_token, create_access_token_request }
134
+ r.process { commit :purchase, post, access_token: access_token(r) }
135
+ end.primary_response
136
+ end
137
+
138
+ def setup_authorize(money, options = {})
139
+ requires!(options, :return_url, :transaction_reference)
140
+ requires!(options, :unique_reference, :name) if store?
141
+
142
+ post = new_post
143
+
144
+ add_transaction(post, money, options)
145
+ add_customer_data(post, options)
146
+ add_address(post, options)
147
+ add_template(post, options)
148
+ add_audit(post, options)
149
+ add_return_url(post, options)
150
+
151
+ MultiResponse.run do |r|
152
+ r.process { commit :access_token, create_access_token_request }
153
+ r.process { commit :authorize, post, access_token: access_token(r) }
154
+ end.primary_response
155
+ end
156
+
157
+ def setup_verify(options = {})
158
+ requires!(options, :return_url, :transaction_reference)
159
+ requires!(options, :unique_reference, :name) if store?
160
+
161
+ post = new_post
162
+
163
+ # add_transaction(post, money, options)
164
+ add_customer_data(post, options)
165
+ add_address(post, options)
166
+ add_template(post, options)
167
+ add_audit(post, options)
168
+ add_return_url(post, options)
169
+
170
+ MultiResponse.run do |r|
171
+ r.process { commit :access_token, create_access_token_request }
172
+ r.process { commit :verify, post, access_token: access_token(r) }
173
+ end.primary_response
174
+ end
175
+
176
+ # Swap token for details about success / failure of transaction
177
+ def details_for(token_id)
178
+ payload = { id: token_id }
179
+
180
+ MultiResponse.run do |r|
181
+ r.process { commit :access_token, create_access_token_request }
182
+ r.process { commit :token, payload, access_token: access_token(r) }
183
+ end.primary_response
184
+ end
185
+
186
+ private
187
+
188
+ def new_post
189
+ { payer: {}, transaction: {} }
190
+ end
191
+
192
+ def add_transaction(post, money, options)
193
+ t = post[:transaction]
194
+
195
+ t[:reference] = trim(options[:transaction_reference])
196
+ t[:description] = options[:description] || ''
197
+ t[:amount] = amount(money)
198
+ t[:currency_code] = (options[:currency] || currency(money))
199
+
200
+ post[:transaction] = t
201
+ end
202
+
203
+ def add_customer_data(post, options)
204
+ payer = post[:payer]
205
+
206
+ payer[:save_payer] = (options[:store] || false)
207
+ payer[:unique_reference] = trim(options[:customer_reference]) if store?
208
+ payer[:group_reference] = trim(options[:group_reference]) if store?
209
+ payer[:family_or_business_name] = options[:name] if store?
210
+ payer[:email] = options[:email]
211
+ payer[:phone] = options[:phone]
212
+ payer[:mobile] = options[:mobile]
213
+ payer[:date_of_birth] = options[:date_of_birth]
214
+
215
+ post[:payer] = payer
216
+ end
217
+
218
+ def add_address(post, options)
219
+ if (address = (options[:billing_address] || options[:address]))
220
+ post[:payer].tap do |h|
221
+ h[:address] = {}
222
+ h[:address][:line1] = address[:address1] if address[:address1]
223
+ h[:address][:line2] = address[:address2] if address[:address2]
224
+ h[:address][:state] = address[:state] if address[:state]
225
+ h[:address][:country] = address[:country] if address[:country]
226
+ h[:address][:post_code] = address[:zip] if address[:zip]
227
+ end
228
+ end
229
+ end
230
+
231
+ def add_template(post, options)
232
+ post[:template] = (options[:template] || 'Basic')
233
+ end
234
+
235
+ def add_audit(post, options)
236
+ return unless options[:ip].present?
237
+
238
+ post[:audit] = {}
239
+ post[:audit][:user_i_p] = options[:ip]
240
+ end
241
+
242
+ def add_return_url(post, options)
243
+ post[:return_url] = options[:return_url]
244
+ end
245
+
246
+ def parse(body)
247
+ JSON.parse(body).deep_transform_keys { |key| key.underscore.to_sym }
248
+ end
249
+
250
+ def headers(options = {})
251
+ headers = {}
252
+ headers['Authorization'] =
253
+ "Bearer #{options[:access_token]}" if options[:access_token]
254
+ headers['Content-Type'] = 'application/json'
255
+ headers
256
+ end
257
+
258
+ def commit(action, parameters, options = {})
259
+ url =
260
+ build_url(
261
+ action,
262
+ parameters.merge(service: options[:service] || @service)
263
+ )
264
+
265
+ begin
266
+ response =
267
+ parse(
268
+ ssl_request(
269
+ verb(action),
270
+ url,
271
+ post_data(action, parameters),
272
+ headers(options)
273
+ )
274
+ )
275
+ rescue ResponseError => e
276
+ # No gateway error message so we throw
277
+ raise if e.response.body.blank?
278
+
279
+ response = parse(e.response.body)
280
+ end
281
+
282
+ if action == :token
283
+ PayrixResponse.new(
284
+ token_success_from(response),
285
+ token_message_from(response),
286
+ response,
287
+ error_code: token_error_code_from(response),
288
+ fraud_review: token_fraud_review_from(response),
289
+ test: test?
290
+ )
291
+ else
292
+ PayrixResponse.new(
293
+ success_from(response),
294
+ message_from(response),
295
+ response,
296
+ error_code: error_code_from(response),
297
+ test: test?
298
+ )
299
+ end
300
+ end
301
+
302
+ def create_access_token_request
303
+ { username: options[:login], password: options[:password] }
304
+ end
305
+
306
+ def verb(action)
307
+ return :get if action == :token
308
+
309
+ :post
310
+ end
311
+
312
+ def build_url(action, parameters)
313
+ return test? ? test_auth_url : auth_url if action == :access_token
314
+
315
+ base_url = (test? ? test_url : live_url)
316
+ endpoint = ENDPOINTS[@service]
317
+ endpoint = parameters[:id] if parameters[:id] && action == :token
318
+
319
+ "#{base_url}/businesses/#{@business_id}/services/tokens/#{endpoint}"
320
+ end
321
+
322
+ def success_from(response)
323
+ !response.key?(:error_code)
324
+ end
325
+
326
+ def message_from(response)
327
+ success_from(response) ? 'Succeeded' : response[:error_message]
328
+ end
329
+
330
+ def authorization_from(response)
331
+ nil
332
+ end
333
+
334
+ def error_code_from(response)
335
+ unless success_from(response)
336
+ STANDARD_ERROR_CODE_MAPPING[response[:error_code]] ||
337
+ response[:error_code].to_s.underscore
338
+ end
339
+ end
340
+
341
+ def token_error_code_from(response)
342
+ unless token_success_from(response)
343
+ STANDARD_ERROR_CODE_MAPPING[response[:status]] || response[:status]
344
+ end
345
+ end
346
+
347
+ def token_success_from(response)
348
+ response[:status] == TOKEN_STATUS[:processed_successful]
349
+ end
350
+
351
+ def token_message_from(response)
352
+ if response[:transaction].nil?
353
+ TOKEN_STATUS_DESCRIPTIONS[response[:status_description]]
354
+ else
355
+ REJECTION_REASONS[response[:transaction][:sub_status_code]]
356
+ end
357
+ end
358
+
359
+ def token_fraud_review_from(response)
360
+ response[:status] == TOKEN_STATUS[:fraud_check_decline]
361
+ end
362
+
363
+ def access_token(r)
364
+ r.params.dig('access_token')
365
+ end
366
+
367
+ def post_data(action, parameters = {})
368
+ return nil if verb(action) == :get
369
+
370
+ if TRANSACTION_TYPES[action]
371
+ parameters[:transaction][:process_type] = TRANSACTION_TYPES[action]
372
+ end
373
+
374
+ parameters.deep_transform_keys { |key| key.to_s.camelize }.to_json
375
+ end
376
+
377
+ def trim(str, length = 100)
378
+ truncate(str, length)
379
+ end
380
+
381
+ def store?
382
+ !!@options[:store]
383
+ end
384
+
385
+ class PayrixResponse < Response
386
+ def token
387
+ @params['token']
388
+ end
389
+
390
+ def redirect_url
391
+ @params['redirect_to_url']
392
+ end
393
+ end
394
+ end
395
+ end
396
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveMerchant
2
+ module Payrix
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ require 'active_merchant'
2
+ require 'activemerchant/payrix/version'
3
+ require 'activemerchant/billing/gateways/payrix'
data/test/comm_stub.rb ADDED
@@ -0,0 +1,57 @@
1
+ module CommStub
2
+ class Stub
3
+ def initialize(gateway, method_to_stub, action)
4
+ @gateway = gateway
5
+ @action = action
6
+ @complete = false
7
+ @method_to_stub = method_to_stub
8
+ @check = nil
9
+ end
10
+
11
+ def check_request(&block)
12
+ @check = block
13
+ self
14
+ end
15
+
16
+ def respond_with(*responses)
17
+ @complete = true
18
+ check = @check
19
+ singleton_class =
20
+ (
21
+ class << @gateway
22
+ self
23
+ end
24
+ )
25
+ singleton_class.send(:undef_method, @method_to_stub)
26
+ singleton_class.send(:define_method, @method_to_stub) do |*args|
27
+ check&.call(*args)
28
+ (responses.size == 1 ? responses.last : responses.shift)
29
+ end
30
+ @action.call
31
+ end
32
+
33
+ def complete?
34
+ @complete
35
+ end
36
+
37
+ class Complete
38
+ def complete?
39
+ true
40
+ end
41
+ end
42
+ end
43
+
44
+ def last_comm_stub
45
+ @last_comm_stub ||= Stub::Complete.new
46
+ end
47
+
48
+ def stub_comms(gateway = @gateway, method_to_stub = :ssl_post, &action)
49
+ assert last_comm_stub.complete?,
50
+ "Tried to stub communications when there's a stub already in progress."
51
+ @last_comm_stub = Stub.new(gateway, method_to_stub, action)
52
+ end
53
+
54
+ def teardown
55
+ assert(last_comm_stub.complete?)
56
+ end
57
+ end
data/test/fixtures.yml ADDED
@@ -0,0 +1,5 @@
1
+ payrix:
2
+ login: 90024.1456
3
+ password: PASSWORD
4
+ business_id: 90024
5
+ service: hpp