barzahlen 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/barzahlen.rb +7 -0
- data/lib/barzahlen/configuration.rb +32 -0
- data/lib/barzahlen/error.rb +116 -0
- data/lib/barzahlen/middleware.rb +69 -0
- data/lib/barzahlen/slip.rb +113 -0
- data/lib/barzahlen/version.rb +3 -0
- metadata +28 -77
- data/Gemfile +0 -3
- data/README.md +0 -207
- data/Rakefile +0 -3
- data/bin/test.rb +0 -30
- data/lib/barzahlen/api/online.rb +0 -58
- data/lib/barzahlen/api/online/api.rb +0 -67
- data/lib/barzahlen/api/online/hash_builder.rb +0 -43
- data/lib/barzahlen/api/online/http.rb +0 -31
- data/lib/barzahlen/api/online/notification_handler.rb +0 -50
- data/lib/barzahlen/api/online/response_parser.rb +0 -26
- data/lib/barzahlen/api/online/transaction.rb +0 -57
- data/lib/barzahlen/api/online/version.rb +0 -9
- data/lib/ruby_sdk.rb +0 -5
- data/lib/ruby_sdk/version.rb +0 -3
- data/spec/barzahlen/api/online/api_spec.rb +0 -86
- data/spec/barzahlen/api/online/hash_builder_spec.rb +0 -15
- data/spec/barzahlen/api/online/http_spec.rb +0 -13
- data/spec/barzahlen/api/online/notification_handler_spec.rb +0 -240
- data/spec/barzahlen/api/online/response_parser_spec.rb +0 -99
- data/spec/barzahlen/api/online/transaction_spec.rb +0 -108
- data/spec/barzahlen/api/online_spec.rb +0 -34
- data/spec/spec_helper.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba4379a6be0c31f8284c55d814bf82c97aa4a011
|
4
|
+
data.tar.gz: 9f28715903860a7685dc5fc32c0e734322b376ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 399821910a344a8568298987061ba410fc5a4917c89f0dcad08c8e395570546c2eca6f3f2abd5c99186221d7ae0e1db5fef121354f3cd0f7504ad3d8c8c671f0
|
7
|
+
data.tar.gz: 671aa7a285cbda33132585721adcee37c8002067dc18e2d7da076d8266ca518d41af087b0c9d74a22dfc9b47ea5080aa0f1df0fec618afd46a93ea4dfbc0ff1a
|
data/lib/barzahlen.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Barzahlen
|
2
|
+
class Configuration
|
3
|
+
API_HOST = "https://api.barzahlen.de/v2"
|
4
|
+
API_HOST_SANDBOX = "https://api-sandbox.barzahlen.de/v2"
|
5
|
+
|
6
|
+
attr_accessor :sandbox
|
7
|
+
attr_accessor :division_id
|
8
|
+
attr_accessor :payment_key
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@sandbox = false
|
12
|
+
@division_id = "not_valid_division_id"
|
13
|
+
@payment_key = "not_valid_payment_key"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
attr_accessor :configuration
|
19
|
+
|
20
|
+
def configuration
|
21
|
+
@configuration ||= Configuration.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset
|
25
|
+
@configuration = Configuration.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def configure
|
29
|
+
yield(configuration)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Barzahlen
|
4
|
+
module Error
|
5
|
+
class ClientError < StandardError
|
6
|
+
attr_reader :error_message
|
7
|
+
|
8
|
+
def initialize(error_message)
|
9
|
+
@error_message = error_message
|
10
|
+
end
|
11
|
+
|
12
|
+
def message
|
13
|
+
return @error_message
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method :to_s, :message
|
17
|
+
end
|
18
|
+
|
19
|
+
class SignatureError < ClientError; end
|
20
|
+
|
21
|
+
class ApiError < StandardError
|
22
|
+
attr_reader :error_class
|
23
|
+
attr_reader :error_code
|
24
|
+
attr_reader :error_message
|
25
|
+
attr_reader :documentation_url
|
26
|
+
attr_reader :request_id
|
27
|
+
|
28
|
+
def initialize(error_hash = {})
|
29
|
+
@error_class = error_hash[:error_class]
|
30
|
+
@error_code = error_hash[:error_code]
|
31
|
+
@error_message = error_hash[:message]
|
32
|
+
@documentation_url = error_hash[:documentation_url]
|
33
|
+
@request_id = error_hash[:request_id]
|
34
|
+
end
|
35
|
+
|
36
|
+
def message
|
37
|
+
return "Error occurred with: #{@error_message}"
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :to_s, :message
|
41
|
+
end
|
42
|
+
|
43
|
+
class AuthError < ApiError; end
|
44
|
+
class TransportError < ApiError; end
|
45
|
+
class IdempotencyError < ApiError; end
|
46
|
+
class RateLimitError < ApiError; end
|
47
|
+
class InvalidFormatError < ApiError; end
|
48
|
+
class InvalidStateError < ApiError; end
|
49
|
+
class InvalidParameterError < ApiError; end
|
50
|
+
class NotAllowedError < ApiError; end
|
51
|
+
class ServerError < ApiError; end
|
52
|
+
class UnexpectedError < ApiError; end
|
53
|
+
|
54
|
+
# This generates ApiErrors based on the response error classes of CPS
|
55
|
+
def self.generate_error_from_response(response_body)
|
56
|
+
error_hash = generate_error_hash_with_symbols(response_body)
|
57
|
+
|
58
|
+
case error_hash[:error_class]
|
59
|
+
when "auth"
|
60
|
+
return AuthError.new( error_hash )
|
61
|
+
when "transport"
|
62
|
+
return TransportError.new( error_hash )
|
63
|
+
when "idempotency"
|
64
|
+
return IdempotencyError.new( error_hash )
|
65
|
+
when "rate_limit"
|
66
|
+
return RateLimitError.new( error_hash )
|
67
|
+
when "invalid_format"
|
68
|
+
return InvalidFormatError.new( error_hash )
|
69
|
+
when "invalid_state"
|
70
|
+
return InvalidStateError.new( error_hash )
|
71
|
+
when "invalid_parameter"
|
72
|
+
return InvalidParameterError.new( error_hash )
|
73
|
+
when "not_allowed"
|
74
|
+
return NotAllowedError.new( error_hash )
|
75
|
+
when "server_error"
|
76
|
+
return ServerError.new( error_hash )
|
77
|
+
else
|
78
|
+
return UnexpectedError.new( error_hash )
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def self.parse_json(json)
|
86
|
+
begin
|
87
|
+
hash = JSON.parse(json)
|
88
|
+
rescue JSON::ParserError => e
|
89
|
+
return nil
|
90
|
+
end
|
91
|
+
self.symbolize_keys(hash)
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.generate_error_hash_with_symbols(body)
|
95
|
+
if body.is_a?(Hash)
|
96
|
+
error_hash = self.symbolize_keys(body)
|
97
|
+
elsif body.is_a?(String)
|
98
|
+
error_hash = parse_json(body) || {}
|
99
|
+
else
|
100
|
+
error_hash = Hash.new
|
101
|
+
end
|
102
|
+
|
103
|
+
error_hash[:error_class] ||= "Unexpected_Error"
|
104
|
+
error_hash[:error_code] ||= "Unknown error code (body): \"#{body.to_s}\""
|
105
|
+
error_hash[:message] ||= "Please contact CPS to help us fix that as soon as possible."
|
106
|
+
error_hash[:documentation_url] ||= "https://www.cashpaymentsolutions.com/de/geschaeftskunden/kontakt"
|
107
|
+
error_hash[:request_id] ||= "not_available"
|
108
|
+
|
109
|
+
error_hash
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.symbolize_keys(hash)
|
113
|
+
Hash[hash.map{ |k, v| [k.to_sym, v] }]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "openssl"
|
2
|
+
require "uri"
|
3
|
+
require "time"
|
4
|
+
|
5
|
+
module Barzahlen
|
6
|
+
module Middleware
|
7
|
+
class Signature
|
8
|
+
def initialize(request, config)
|
9
|
+
@request = request
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def call (opts, request_uri, method, params, body)
|
14
|
+
parsed_uri = URI.parse(request_uri)
|
15
|
+
request_host_header = parsed_uri.host + ":" + parsed_uri.port.to_s
|
16
|
+
request_method = method
|
17
|
+
request_host_path = parsed_uri.path
|
18
|
+
request_query_string = URI.encode_www_form(params)
|
19
|
+
request_idempotency_key = opts[:headers]["Idempotency-Key"]
|
20
|
+
request_date_header = Time.now.utc.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
21
|
+
|
22
|
+
signature = Barzahlen::Middleware.generate_bz_signature(
|
23
|
+
@config.payment_key,
|
24
|
+
request_host_header,
|
25
|
+
request_method,
|
26
|
+
request_date_header,
|
27
|
+
request_host_path,
|
28
|
+
request_query_string,
|
29
|
+
body,
|
30
|
+
request_idempotency_key
|
31
|
+
)
|
32
|
+
|
33
|
+
# Attach the Date, Authorization and Host to the request
|
34
|
+
new_headers = opts[:headers].merge(
|
35
|
+
{
|
36
|
+
Date: request_date_header,
|
37
|
+
Authorization: "BZ1-HMAC-SHA256 DivisionId=#{@config.division_id}, Signature=#{signature}",
|
38
|
+
Host: request_host_header,
|
39
|
+
}
|
40
|
+
)
|
41
|
+
|
42
|
+
return @request.call({headers: new_headers}, request_uri, method, params, body)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.generate_bz_signature(
|
47
|
+
payment_key,
|
48
|
+
request_host_header,
|
49
|
+
request_method,
|
50
|
+
request_date_header,
|
51
|
+
request_host_path = "",
|
52
|
+
request_query_string = "",
|
53
|
+
request_body = "",
|
54
|
+
request_idempotency_key = "")
|
55
|
+
|
56
|
+
request_body_digest = OpenSSL::Digest.hexdigest("SHA256", request_body.to_s || "")
|
57
|
+
|
58
|
+
raw_signature = "#{request_host_header}\n"\
|
59
|
+
"#{request_method.upcase}\n"\
|
60
|
+
"#{request_host_path}\n"\
|
61
|
+
"#{request_query_string}\n"\
|
62
|
+
"#{request_date_header}\n"\
|
63
|
+
"#{request_idempotency_key}\n"\
|
64
|
+
"#{request_body_digest}"
|
65
|
+
|
66
|
+
OpenSSL::HMAC.hexdigest("SHA256", payment_key, raw_signature)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Barzahlen
|
5
|
+
IDEMPOTENCY_ENABLED = true
|
6
|
+
|
7
|
+
# For idempotency purposes a class takes care of refund and payment
|
8
|
+
|
9
|
+
class CreateSlipRequest
|
10
|
+
def initialize(opts = {})
|
11
|
+
@request = Barzahlen.get_grac_client(Barzahlen::IDEMPOTENCY_ENABLED)
|
12
|
+
@request_hash = opts
|
13
|
+
end
|
14
|
+
|
15
|
+
def send
|
16
|
+
@request_hash.freeze
|
17
|
+
@request_hash.each do |key, value|
|
18
|
+
@request_hash[key].freeze
|
19
|
+
end
|
20
|
+
Barzahlen.execute_with_error_handling do
|
21
|
+
@request.path("/slips").post(@request_hash)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# If idempotency is not important a simple request is more than enough
|
27
|
+
|
28
|
+
def self.retrieve_slip(slip_id)
|
29
|
+
self.execute_with_error_handling do
|
30
|
+
self.get_grac_client.path("/slips/{id}", id: slip_id.to_s).get
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.update_slip(slip_id, opts = {})
|
35
|
+
self.execute_with_error_handling do
|
36
|
+
self.get_grac_client.path("/slips/{id}", id: slip_id.to_s).patch(opts)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.resend_email(slip_id)
|
41
|
+
self.execute_with_error_handling do
|
42
|
+
self.get_grac_client.path("/slips/{id}/resend/email", id: slip_id.to_s).post
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.resend_text_message(slip_id)
|
47
|
+
self.execute_with_error_handling do
|
48
|
+
self.get_grac_client.path("/slips/{id}/resend/text_message", id: slip_id.to_s).post
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.invalidate_slip(slip_id)
|
53
|
+
self.execute_with_error_handling do
|
54
|
+
self.get_grac_client.path("/slips/{id}/invalidate", id: slip_id.to_s).post
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Handle a webhook request
|
59
|
+
|
60
|
+
def self.webhook_request(request)
|
61
|
+
bz_hook_format = request["Bz-Hook-Format"]
|
62
|
+
|
63
|
+
#stop processing when bz-hook-format = v1 because it will be or was send as v2
|
64
|
+
if bz_hook_format.include? "v1"
|
65
|
+
return nil
|
66
|
+
end
|
67
|
+
|
68
|
+
signature = Barzahlen::Middleware.generate_bz_signature(
|
69
|
+
Barzahlen.configuration.payment_key,
|
70
|
+
request["Host"] + ":" + (request["Port"] || "443"),
|
71
|
+
request["Method"] ? request["Method"].upcase : "POST",
|
72
|
+
request["Date"],
|
73
|
+
request["Path"].split("?")[0] || request["Path"],
|
74
|
+
request["Path"].split("?")[1] || "",
|
75
|
+
request["Body"]
|
76
|
+
)
|
77
|
+
|
78
|
+
if request["Bz-Signature"].include? signature
|
79
|
+
return JSON.parse(request["Body"])
|
80
|
+
else
|
81
|
+
raise Barzahlen::Error::SignatureError.new("Signature not valid")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
@@grac_client = nil
|
89
|
+
|
90
|
+
def self.get_grac_client(idempotency = false)
|
91
|
+
@@grac_client ||= Grac::Client.new(
|
92
|
+
Barzahlen.configuration.sandbox ?
|
93
|
+
Barzahlen::Configuration::API_HOST_SANDBOX : Barzahlen::Configuration::API_HOST,
|
94
|
+
middleware: [ [ Barzahlen::Middleware::Signature, Barzahlen.configuration ] ]
|
95
|
+
)
|
96
|
+
|
97
|
+
if idempotency
|
98
|
+
return @@grac_client.set( headers: { "Idempotency-Key" => SecureRandom.uuid} )
|
99
|
+
else
|
100
|
+
return @@grac_client
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.execute_with_error_handling
|
105
|
+
begin
|
106
|
+
yield
|
107
|
+
rescue Grac::Exception::RequestFailed => e
|
108
|
+
raise Barzahlen::Error.generate_error_from_response("")
|
109
|
+
rescue Grac::Exception::ClientException => e
|
110
|
+
raise Barzahlen::Error.generate_error_from_response(e.body)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
metadata
CHANGED
@@ -1,126 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: barzahlen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- David Leib
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 1.3.5
|
19
|
+
version: 10.4.1
|
23
20
|
type: :development
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
24
|
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 1.3.5
|
26
|
+
version: 10.4.1
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
28
|
+
name: rspec
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
30
|
requirements:
|
37
31
|
- - "~>"
|
38
32
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
40
|
-
- - ">="
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: 10.0.4
|
33
|
+
version: 3.2.0
|
43
34
|
type: :development
|
44
35
|
prerelease: false
|
45
36
|
version_requirements: !ruby/object:Gem::Requirement
|
46
37
|
requirements:
|
47
38
|
- - "~>"
|
48
39
|
- !ruby/object:Gem::Version
|
49
|
-
version:
|
50
|
-
- - ">="
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: 10.0.4
|
40
|
+
version: 3.2.0
|
53
41
|
- !ruby/object:Gem::Dependency
|
54
|
-
name:
|
42
|
+
name: rack-test
|
55
43
|
requirement: !ruby/object:Gem::Requirement
|
56
44
|
requirements:
|
57
45
|
- - "~>"
|
58
46
|
- !ruby/object:Gem::Version
|
59
|
-
version:
|
60
|
-
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: 2.14.1
|
47
|
+
version: 0.6.3
|
63
48
|
type: :development
|
64
49
|
prerelease: false
|
65
50
|
version_requirements: !ruby/object:Gem::Requirement
|
66
51
|
requirements:
|
67
52
|
- - "~>"
|
68
53
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
70
|
-
- - ">="
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
version: 2.14.1
|
54
|
+
version: 0.6.3
|
73
55
|
- !ruby/object:Gem::Dependency
|
74
|
-
name:
|
56
|
+
name: grac
|
75
57
|
requirement: !ruby/object:Gem::Requirement
|
76
58
|
requirements:
|
77
59
|
- - "~>"
|
78
60
|
- !ruby/object:Gem::Version
|
79
|
-
version:
|
80
|
-
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: 3.0.0
|
83
|
-
type: :development
|
61
|
+
version: 2.2.1
|
62
|
+
type: :runtime
|
84
63
|
prerelease: false
|
85
64
|
version_requirements: !ruby/object:Gem::Requirement
|
86
65
|
requirements:
|
87
66
|
- - "~>"
|
88
67
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
90
|
-
|
91
|
-
- !ruby/object:Gem::Version
|
92
|
-
version: 3.0.0
|
93
|
-
description: The official Ruby-SDK for accessing the Barzalen Payment Service
|
68
|
+
version: 2.2.1
|
69
|
+
description: This is a ruby gem to access the Barzahlen API v2.
|
94
70
|
email:
|
95
|
-
-
|
96
|
-
executables:
|
97
|
-
- test.rb
|
71
|
+
- david.leib@barzahlen.de
|
72
|
+
executables: []
|
98
73
|
extensions: []
|
99
74
|
extra_rdoc_files: []
|
100
75
|
files:
|
101
|
-
-
|
102
|
-
-
|
103
|
-
-
|
104
|
-
-
|
105
|
-
- lib/barzahlen/
|
106
|
-
- lib/barzahlen/
|
107
|
-
|
108
|
-
- lib/barzahlen/api/online/http.rb
|
109
|
-
- lib/barzahlen/api/online/notification_handler.rb
|
110
|
-
- lib/barzahlen/api/online/response_parser.rb
|
111
|
-
- lib/barzahlen/api/online/transaction.rb
|
112
|
-
- lib/barzahlen/api/online/version.rb
|
113
|
-
- lib/ruby_sdk.rb
|
114
|
-
- lib/ruby_sdk/version.rb
|
115
|
-
- spec/barzahlen/api/online/api_spec.rb
|
116
|
-
- spec/barzahlen/api/online/hash_builder_spec.rb
|
117
|
-
- spec/barzahlen/api/online/http_spec.rb
|
118
|
-
- spec/barzahlen/api/online/notification_handler_spec.rb
|
119
|
-
- spec/barzahlen/api/online/response_parser_spec.rb
|
120
|
-
- spec/barzahlen/api/online/transaction_spec.rb
|
121
|
-
- spec/barzahlen/api/online_spec.rb
|
122
|
-
- spec/spec_helper.rb
|
123
|
-
homepage: https://www.barzahlen.de/
|
76
|
+
- lib/barzahlen.rb
|
77
|
+
- lib/barzahlen/configuration.rb
|
78
|
+
- lib/barzahlen/error.rb
|
79
|
+
- lib/barzahlen/middleware.rb
|
80
|
+
- lib/barzahlen/slip.rb
|
81
|
+
- lib/barzahlen/version.rb
|
82
|
+
homepage: ''
|
124
83
|
licenses:
|
125
84
|
- MIT
|
126
85
|
metadata: {}
|
@@ -143,13 +102,5 @@ rubyforge_project:
|
|
143
102
|
rubygems_version: 2.2.2
|
144
103
|
signing_key:
|
145
104
|
specification_version: 4
|
146
|
-
summary: Barzahlen
|
147
|
-
test_files:
|
148
|
-
- spec/barzahlen/api/online/api_spec.rb
|
149
|
-
- spec/barzahlen/api/online/hash_builder_spec.rb
|
150
|
-
- spec/barzahlen/api/online/http_spec.rb
|
151
|
-
- spec/barzahlen/api/online/notification_handler_spec.rb
|
152
|
-
- spec/barzahlen/api/online/response_parser_spec.rb
|
153
|
-
- spec/barzahlen/api/online/transaction_spec.rb
|
154
|
-
- spec/barzahlen/api/online_spec.rb
|
155
|
-
- spec/spec_helper.rb
|
105
|
+
summary: Client gem for API Barzahlen v2.
|
106
|
+
test_files: []
|