docdata-order 1.0.3 → 2.0.0
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 +4 -4
- data/.rubocop.yml +22 -10
- data/.travis.yml +1 -1
- data/Gemfile +4 -1
- data/Gemfile.lock +37 -20
- data/README.md +99 -12
- data/docdata-order.gemspec +3 -3
- data/lib/docdata/order.rb +1 -1
- data/lib/docdata/order/amount.rb +38 -0
- data/lib/docdata/order/client.rb +23 -3
- data/lib/docdata/order/payment_method.rb +15 -1
- data/lib/docdata/order/request.rb +155 -26
- data/lib/docdata/order/response.rb +58 -9
- data/lib/docdata/order/urls.rb +2 -2
- data/lib/docdata/order/version.rb +1 -1
- metadata +6 -7
- data/CHANGELOG.md +0 -18
- data/lib/docdata/order/ideal.rb +0 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 42f2292f2551aa859832a6912c3f3902e7ff7f1712444416e4e3790a41a8fa5e
|
|
4
|
+
data.tar.gz: acaa5f6b5605d628040d448370d861b6a14b750012abfa5ab20df47938eacc7b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a61186b4caa42c8353bbafb01293855ac6227de46956678391b8190b4bfb4b4c144cc6ca68eb43a93824eb70b03fd9b3a24e9791ee838411a65bb33c771a2e5c
|
|
7
|
+
data.tar.gz: e8cb189d0bce6274e3717fb02d0008174b7c973c857b96d3f8031aa1937ff95a266dcfeed7b714810a55955c81e7ccc77d086af9bac0d5b18c249398a44f831f
|
data/.rubocop.yml
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
# Docdata-order RuboCop configuration
|
|
2
2
|
|
|
3
|
+
require:
|
|
4
|
+
- rubocop-performance
|
|
5
|
+
- rubocop-rake
|
|
6
|
+
- rubocop-rspec
|
|
7
|
+
|
|
3
8
|
AllCops:
|
|
9
|
+
NewCops: enable
|
|
4
10
|
TargetRubyVersion: 2.4
|
|
5
11
|
DisplayCopNames: true
|
|
6
12
|
DisplayStyleGuide: true
|
|
13
|
+
Exclude:
|
|
14
|
+
- 'tmp/**/*'
|
|
15
|
+
- 'vendor/**/*'
|
|
7
16
|
|
|
8
|
-
# We target 2.4, but still want to support 2.0.
|
|
9
|
-
Gemspec/RequiredRubyVersion:
|
|
10
|
-
Enabled: false
|
|
11
17
|
|
|
12
18
|
Layout/LineLength:
|
|
13
19
|
Enabled: false
|
|
14
20
|
|
|
21
|
+
|
|
15
22
|
Metrics/AbcSize:
|
|
16
|
-
Max:
|
|
23
|
+
Max: 58
|
|
17
24
|
|
|
18
25
|
Metrics/BlockLength:
|
|
19
26
|
Exclude:
|
|
@@ -25,19 +32,24 @@ Metrics/ClassLength:
|
|
|
25
32
|
Metrics/MethodLength:
|
|
26
33
|
Enabled: false
|
|
27
34
|
|
|
35
|
+
|
|
36
|
+
RSpec/DescribedClass:
|
|
37
|
+
EnforcedStyle: explicit
|
|
38
|
+
|
|
39
|
+
RSpec/ExampleLength:
|
|
40
|
+
Max: 41
|
|
41
|
+
|
|
42
|
+
RSpec/MultipleExpectations:
|
|
43
|
+
Max: 10
|
|
44
|
+
|
|
45
|
+
|
|
28
46
|
Style/BlockDelimiters:
|
|
29
47
|
Exclude:
|
|
30
48
|
- 'spec/**/*.rb'
|
|
31
49
|
|
|
32
|
-
Style/ExpandPathArguments:
|
|
33
|
-
Enabled: false
|
|
34
|
-
|
|
35
50
|
Style/GuardClause:
|
|
36
51
|
Enabled: false
|
|
37
52
|
|
|
38
|
-
Style/SafeNavigation:
|
|
39
|
-
Enabled: false
|
|
40
|
-
|
|
41
53
|
Style/StringLiterals:
|
|
42
54
|
Enabled: false
|
|
43
55
|
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
|
@@ -5,4 +5,7 @@ source 'https://rubygems.org'
|
|
|
5
5
|
# Specify your gem's dependencies in docdata-order.gemspec
|
|
6
6
|
gemspec
|
|
7
7
|
|
|
8
|
-
gem 'rubocop', '~>
|
|
8
|
+
gem 'rubocop', '~> 1.12.0'
|
|
9
|
+
gem 'rubocop-performance', '~> 1.10.2'
|
|
10
|
+
gem 'rubocop-rake', '~> 0.5.1'
|
|
11
|
+
gem 'rubocop-rspec', '~> 2.2.0'
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
docdata-order (
|
|
4
|
+
docdata-order (2.0.0)
|
|
5
5
|
savon (>= 2.0, < 3.0)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
@@ -13,28 +13,29 @@ GEM
|
|
|
13
13
|
gyoku (>= 0.4.0)
|
|
14
14
|
nokogiri
|
|
15
15
|
ast (2.4.2)
|
|
16
|
-
builder (3.2.
|
|
16
|
+
builder (3.2.4)
|
|
17
17
|
crack (0.4.3)
|
|
18
18
|
safe_yaml (~> 1.0.0)
|
|
19
19
|
diff-lcs (1.3)
|
|
20
20
|
gyoku (1.3.1)
|
|
21
21
|
builder (>= 2.1.2)
|
|
22
22
|
hashdiff (0.3.4)
|
|
23
|
-
httpi (2.4.
|
|
23
|
+
httpi (2.4.5)
|
|
24
24
|
rack
|
|
25
25
|
socksify
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
mini_portile2 (~> 2.3.0)
|
|
26
|
+
mini_portile2 (2.4.0)
|
|
27
|
+
nokogiri (1.10.10)
|
|
28
|
+
mini_portile2 (~> 2.4.0)
|
|
30
29
|
nori (2.6.0)
|
|
31
30
|
parallel (1.20.1)
|
|
32
|
-
parser (3.0.1.
|
|
31
|
+
parser (3.0.1.1)
|
|
33
32
|
ast (~> 2.4.1)
|
|
34
33
|
public_suffix (2.0.5)
|
|
35
|
-
rack (2.
|
|
34
|
+
rack (2.2.3)
|
|
36
35
|
rainbow (3.0.0)
|
|
37
36
|
rake (13.0.3)
|
|
37
|
+
regexp_parser (2.1.1)
|
|
38
|
+
rexml (3.2.5)
|
|
38
39
|
rspec (3.6.0)
|
|
39
40
|
rspec-core (~> 3.6.0)
|
|
40
41
|
rspec-expectations (~> 3.6.0)
|
|
@@ -48,26 +49,39 @@ GEM
|
|
|
48
49
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
49
50
|
rspec-support (~> 3.6.0)
|
|
50
51
|
rspec-support (3.6.0)
|
|
51
|
-
rubocop (
|
|
52
|
-
jaro_winkler (~> 1.5.1)
|
|
52
|
+
rubocop (1.12.1)
|
|
53
53
|
parallel (~> 1.10)
|
|
54
|
-
parser (>=
|
|
54
|
+
parser (>= 3.0.0.0)
|
|
55
55
|
rainbow (>= 2.2.2, < 4.0)
|
|
56
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
57
|
+
rexml
|
|
58
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
|
56
59
|
ruby-progressbar (~> 1.7)
|
|
57
|
-
unicode-display_width (>= 1.4.0, <
|
|
60
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
|
61
|
+
rubocop-ast (1.4.1)
|
|
62
|
+
parser (>= 2.7.1.5)
|
|
63
|
+
rubocop-performance (1.10.2)
|
|
64
|
+
rubocop (>= 0.90.0, < 2.0)
|
|
65
|
+
rubocop-ast (>= 0.4.0)
|
|
66
|
+
rubocop-rake (0.5.1)
|
|
67
|
+
rubocop
|
|
68
|
+
rubocop-rspec (2.2.0)
|
|
69
|
+
rubocop (~> 1.0)
|
|
70
|
+
rubocop-ast (>= 1.1.0)
|
|
58
71
|
ruby-progressbar (1.11.0)
|
|
59
72
|
safe_yaml (1.0.4)
|
|
60
|
-
savon (2.
|
|
73
|
+
savon (2.12.1)
|
|
61
74
|
akami (~> 1.2)
|
|
62
75
|
builder (>= 2.1.2)
|
|
63
76
|
gyoku (~> 1.2)
|
|
64
77
|
httpi (~> 2.3)
|
|
65
|
-
nokogiri (>= 1.
|
|
78
|
+
nokogiri (>= 1.8.1)
|
|
66
79
|
nori (~> 2.4)
|
|
67
80
|
wasabi (~> 3.4)
|
|
68
81
|
socksify (1.7.1)
|
|
69
|
-
unicode-display_width (
|
|
70
|
-
wasabi (3.
|
|
82
|
+
unicode-display_width (2.0.0)
|
|
83
|
+
wasabi (3.6.1)
|
|
84
|
+
addressable
|
|
71
85
|
httpi (~> 2.0)
|
|
72
86
|
nokogiri (>= 1.4.2)
|
|
73
87
|
webmock (2.3.2)
|
|
@@ -79,12 +93,15 @@ PLATFORMS
|
|
|
79
93
|
ruby
|
|
80
94
|
|
|
81
95
|
DEPENDENCIES
|
|
82
|
-
bundler (~>
|
|
96
|
+
bundler (~> 2.0)
|
|
83
97
|
docdata-order!
|
|
84
98
|
rake (~> 13.0)
|
|
85
99
|
rspec (~> 3.0)
|
|
86
|
-
rubocop (~>
|
|
100
|
+
rubocop (~> 1.12.0)
|
|
101
|
+
rubocop-performance (~> 1.10.2)
|
|
102
|
+
rubocop-rake (~> 0.5.1)
|
|
103
|
+
rubocop-rspec (~> 2.2.0)
|
|
87
104
|
webmock (~> 2.3, >= 2.3.2)
|
|
88
105
|
|
|
89
106
|
BUNDLED WITH
|
|
90
|
-
|
|
107
|
+
2.2.17
|
data/README.md
CHANGED
|
@@ -6,6 +6,25 @@
|
|
|
6
6
|
|
|
7
7
|
Docdata::Order is a Ruby client for the Docdata Order API version 1.3.
|
|
8
8
|
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Installation](#installation)
|
|
12
|
+
- [Usage](#usage)
|
|
13
|
+
- [Initialization](#initialization)
|
|
14
|
+
- [Subject merchant](#subject-merchant)
|
|
15
|
+
- [Create an order](#create-an-order)
|
|
16
|
+
- [Redirecting directly to the payment page](#redirecting-directly-to-the-payment-page)
|
|
17
|
+
- [Initial payment request](#initial-payment-request)
|
|
18
|
+
- [Start a payment order](#start-a-payment-order)
|
|
19
|
+
- [Recurring payment request](#recurring-payment-request)
|
|
20
|
+
- [Retrieve status of an order](#retrieve-status-of-an-order)
|
|
21
|
+
- [Retrieve payment methods](#retrieve-payment-methods)
|
|
22
|
+
- [Refund a payment](#refund-a-payment)
|
|
23
|
+
- [Development](#development)
|
|
24
|
+
- [Contributing](#contributing)
|
|
25
|
+
- [License](#license)
|
|
26
|
+
|
|
27
|
+
|
|
9
28
|
## Installation
|
|
10
29
|
|
|
11
30
|
Add this line to your application's Gemfile:
|
|
@@ -29,14 +48,25 @@ Or install it yourself as:
|
|
|
29
48
|
Create a Docdata Order client and configure it with your merchant name and password:
|
|
30
49
|
|
|
31
50
|
```ruby
|
|
32
|
-
|
|
51
|
+
client = Docdata::Order::Client.new("name", "password")
|
|
33
52
|
```
|
|
34
53
|
|
|
35
|
-
The client is configured
|
|
54
|
+
The client is configured to use the production environment by default. To use the Docdata test environment, add the parameter `test: true` when creating the client.
|
|
55
|
+
|
|
56
|
+
#### Subject merchant
|
|
57
|
+
|
|
58
|
+
If you want to use a merchant on whose behalf the requests should be executed (subject merchant), then you can add this to the parameters:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
client = Docdata::Order::Client.new("name", "password", subject_merchant: {
|
|
62
|
+
name: "subname",
|
|
63
|
+
token: "12345678"
|
|
64
|
+
})
|
|
65
|
+
```
|
|
36
66
|
|
|
37
67
|
### Create an order
|
|
38
68
|
|
|
39
|
-
Create a new order with the `create` method. You need to provide the following parameters to create the order:
|
|
69
|
+
Create a new order with the `create` method. You need to provide at least the following parameters to create the order:
|
|
40
70
|
|
|
41
71
|
```ruby
|
|
42
72
|
options = {
|
|
@@ -60,7 +90,7 @@ options = {
|
|
|
60
90
|
}
|
|
61
91
|
}
|
|
62
92
|
|
|
63
|
-
response =
|
|
93
|
+
response = client.create(options)
|
|
64
94
|
|
|
65
95
|
if response.success?
|
|
66
96
|
puts response.order_key
|
|
@@ -72,29 +102,47 @@ end
|
|
|
72
102
|
|
|
73
103
|
The `redirect_url` in the response will redirect the user to the Docdata Payment Menu (One Page Checkout).
|
|
74
104
|
|
|
75
|
-
|
|
105
|
+
#### Redirecting directly to the payment page
|
|
106
|
+
|
|
107
|
+
For some payment methods you can skip the Docdata One Page Checkout and redirect directly to the payment page of the specified payment method.
|
|
108
|
+
This works for the payment methods iDEAL, Sofort and PayPal. For iDEAL, you also need to provide the issuer:
|
|
76
109
|
|
|
77
110
|
```ruby
|
|
78
|
-
response =
|
|
111
|
+
response = client.create(options.merge(
|
|
79
112
|
payment_method: Docdata::Order::PaymentMethod::IDEAL,
|
|
80
|
-
issuer_id:
|
|
113
|
+
issuer_id: "INGBNL2A",
|
|
81
114
|
return_url: "http://yourwebshop.nl/payment_return"
|
|
82
115
|
))
|
|
83
116
|
```
|
|
84
117
|
|
|
118
|
+
#### Initial payment request
|
|
119
|
+
|
|
120
|
+
If you want to use this order to do recurring payments then you must first make an initial payment request and provide an unique merchant reference.
|
|
121
|
+
This reference should then be used when a making recurring payments.
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
response = client.create(options.merge(
|
|
125
|
+
initial: {
|
|
126
|
+
merchant_reference: "12345"
|
|
127
|
+
}
|
|
128
|
+
))
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
See [Recurring payment request](#recurring-payment-request) how to make recurring payment requests.
|
|
132
|
+
|
|
85
133
|
### Start a payment order
|
|
86
134
|
|
|
87
|
-
When
|
|
135
|
+
When the One Page Checkout is not used (i.e. WebDirect) then you need to use `start` to start a payment order.
|
|
88
136
|
|
|
89
137
|
```ruby
|
|
90
138
|
options = {
|
|
91
139
|
order_key: "12345",
|
|
92
140
|
payment_method: Docdata::Order::PaymentMethod::SEPA_DIRECT_DEBIT,
|
|
93
|
-
|
|
94
|
-
|
|
141
|
+
consumer_name: "Onderheuvel",
|
|
142
|
+
consumer_iban: "NL44RABO0123456789"
|
|
95
143
|
}
|
|
96
144
|
|
|
97
|
-
response =
|
|
145
|
+
response = client.start(options)
|
|
98
146
|
|
|
99
147
|
if response.success?
|
|
100
148
|
puts response.payment_id
|
|
@@ -103,12 +151,24 @@ else
|
|
|
103
151
|
end
|
|
104
152
|
```
|
|
105
153
|
|
|
154
|
+
#### Recurring payment request
|
|
155
|
+
|
|
156
|
+
To start a recurring payment request, you need to provide the unique merchant reference, used in the initial payment request:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
response = client.start(options.merge(
|
|
160
|
+
recurring: {
|
|
161
|
+
merchant_reference: "12345"
|
|
162
|
+
}
|
|
163
|
+
))
|
|
164
|
+
```
|
|
165
|
+
|
|
106
166
|
### Retrieve status of an order
|
|
107
167
|
|
|
108
168
|
To retrieve the status of an order, use `status` with the order key:
|
|
109
169
|
|
|
110
170
|
```ruby
|
|
111
|
-
response =
|
|
171
|
+
response = client.status(order_key: "12345")
|
|
112
172
|
|
|
113
173
|
if response.success?
|
|
114
174
|
puts response.paid?
|
|
@@ -117,6 +177,33 @@ else
|
|
|
117
177
|
end
|
|
118
178
|
```
|
|
119
179
|
|
|
180
|
+
### Retrieve payment methods
|
|
181
|
+
|
|
182
|
+
When an order has been created, you can retrieve the available payment methods (including issuers) by using `payment_methods` with the order key:
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
response = client.payment_methods(order_key: "12345")
|
|
186
|
+
|
|
187
|
+
if response.success?
|
|
188
|
+
puts response.payment_methods
|
|
189
|
+
else
|
|
190
|
+
puts response.error_message
|
|
191
|
+
end
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Refund a payment
|
|
195
|
+
|
|
196
|
+
To refund a payment, use `refund` with the payment ID:
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
response = client.refund(payment_id: "12345")
|
|
200
|
+
|
|
201
|
+
if !response.success?
|
|
202
|
+
puts response.error_message
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
|
|
120
207
|
## Development
|
|
121
208
|
|
|
122
209
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/docdata-order.gemspec
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
lib = File.expand_path('
|
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
5
|
require 'docdata/order/version'
|
|
6
6
|
|
|
@@ -21,9 +21,9 @@ Gem::Specification.new do |spec|
|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
22
22
|
spec.require_paths = ["lib"]
|
|
23
23
|
|
|
24
|
-
spec.required_ruby_version = ">= 2.
|
|
24
|
+
spec.required_ruby_version = ">= 2.4.0"
|
|
25
25
|
|
|
26
|
-
spec.add_development_dependency "bundler", "~>
|
|
26
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
|
27
27
|
spec.add_development_dependency "rake", "~> 13.0"
|
|
28
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
|
29
29
|
spec.add_development_dependency "webmock", "~> 2.3", ">= 2.3.2"
|
data/lib/docdata/order.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "docdata/order/amount"
|
|
3
4
|
require "docdata/order/client"
|
|
4
5
|
require "docdata/order/exception"
|
|
5
6
|
require "docdata/order/gender"
|
|
6
|
-
require "docdata/order/ideal"
|
|
7
7
|
require "docdata/order/payment_method"
|
|
8
8
|
require "docdata/order/request"
|
|
9
9
|
require "docdata/order/response"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bigdecimal'
|
|
4
|
+
|
|
5
|
+
module Docdata
|
|
6
|
+
module Order
|
|
7
|
+
# Helper for converting/formatting amounts.
|
|
8
|
+
class Amount
|
|
9
|
+
class << self
|
|
10
|
+
def from_cents(cents)
|
|
11
|
+
new(cents.to_i / 100.0)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize(amount)
|
|
16
|
+
@amount = BigDecimal(amount.to_s)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_d
|
|
20
|
+
@amount
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_amount
|
|
24
|
+
@amount / 100.0
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_cents
|
|
28
|
+
cents = @amount * 100
|
|
29
|
+
cents.to_i
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Convert the amount to a String with 2 decimals.
|
|
33
|
+
def to_s
|
|
34
|
+
format("%.2f", @amount)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/docdata/order/client.rb
CHANGED
|
@@ -18,7 +18,7 @@ module Docdata
|
|
|
18
18
|
|
|
19
19
|
response = client.call(:create, message: CreateRequest.new(params), attributes: { xmlns: XMLNS_DDP, version: DDP_VERSION })
|
|
20
20
|
|
|
21
|
-
raise Exception, response unless response.success?
|
|
21
|
+
raise Docdata::Order::Exception, response unless response.success?
|
|
22
22
|
|
|
23
23
|
CreateResponse.new(params, response)
|
|
24
24
|
end
|
|
@@ -28,7 +28,7 @@ module Docdata
|
|
|
28
28
|
|
|
29
29
|
response = client.call(:start, message: StartRequest.new(params), attributes: { xmlns: XMLNS_DDP, version: DDP_VERSION })
|
|
30
30
|
|
|
31
|
-
raise Exception, response unless response.success?
|
|
31
|
+
raise Docdata::Order::Exception, response unless response.success?
|
|
32
32
|
|
|
33
33
|
StartResponse.new(params, response)
|
|
34
34
|
end
|
|
@@ -38,11 +38,31 @@ module Docdata
|
|
|
38
38
|
|
|
39
39
|
response = client.call(:status_extended, message: ExtendedStatusRequest.new(params), attributes: { xmlns: XMLNS_DDP, version: DDP_VERSION })
|
|
40
40
|
|
|
41
|
-
raise Exception, response unless response.success?
|
|
41
|
+
raise Docdata::Order::Exception, response unless response.success?
|
|
42
42
|
|
|
43
43
|
ExtendedStatusResponse.new(params, response)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
def refund(options = {})
|
|
47
|
+
params = @options.merge(options)
|
|
48
|
+
|
|
49
|
+
response = client.call(:refund, message: RefundRequest.new(params), attributes: { xmlns: XMLNS_DDP, version: DDP_VERSION })
|
|
50
|
+
|
|
51
|
+
raise Docdata::Order::Exception, response unless response.success?
|
|
52
|
+
|
|
53
|
+
RefundResponse.new(params, response)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def payment_methods(options = {})
|
|
57
|
+
params = @options.merge(options)
|
|
58
|
+
|
|
59
|
+
response = client.call(:list_payment_methods, message: ListPaymentMethodsRequest.new(params), attributes: { xmlns: XMLNS_DDP, version: DDP_VERSION })
|
|
60
|
+
|
|
61
|
+
raise Docdata::Order::Exception, response unless response.success?
|
|
62
|
+
|
|
63
|
+
ListPaymentMethodsResponse.new(params, response)
|
|
64
|
+
end
|
|
65
|
+
|
|
46
66
|
private
|
|
47
67
|
|
|
48
68
|
def client
|
|
@@ -2,13 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
module Docdata
|
|
4
4
|
module Order
|
|
5
|
-
|
|
5
|
+
# Payment method in Docdata, optionally with issuers.
|
|
6
|
+
class PaymentMethod
|
|
6
7
|
IDEAL = "IDEAL"
|
|
7
8
|
VISA = "VISA"
|
|
8
9
|
MASTER_CARD = "MASTERCARD"
|
|
10
|
+
MAESTRO = "MAESTRO"
|
|
9
11
|
AMERICAN_EXPRESS = "AMEX"
|
|
10
12
|
PAYPAL = "PAYPAL_EXPRESS_CHECKOUT"
|
|
11
13
|
SEPA_DIRECT_DEBIT = "SEPA_DIRECT_DEBIT"
|
|
14
|
+
BANCONTACT = "MISTERCASH"
|
|
15
|
+
SOFORT = "EBANKING"
|
|
16
|
+
|
|
17
|
+
attr_accessor :payment_method, :issuers
|
|
18
|
+
|
|
19
|
+
def initialize(payment_method)
|
|
20
|
+
@payment_method = payment_method
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_s
|
|
24
|
+
payment_method
|
|
25
|
+
end
|
|
12
26
|
end
|
|
13
27
|
end
|
|
14
28
|
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "builder/xmlmarkup"
|
|
4
|
-
require "bigdecimal"
|
|
5
4
|
require "securerandom"
|
|
6
5
|
|
|
7
6
|
module Docdata
|
|
@@ -18,7 +17,22 @@ module Docdata
|
|
|
18
17
|
builder = Builder::XmlMarkup.new
|
|
19
18
|
|
|
20
19
|
# Merchant credentials.
|
|
21
|
-
|
|
20
|
+
if subject_merchant
|
|
21
|
+
builder.merchant(name: merchant_name, password: merchant_password) do |merchant|
|
|
22
|
+
# The merchant on whose behalf this request should be executed.
|
|
23
|
+
merchant.subjectMerchant(name: subject_merchant_name, token: subject_merchant_token) do |subject|
|
|
24
|
+
if subject_merchant_fee
|
|
25
|
+
# The fee to apply to the subject merchant. If the fee is zero, then it is ignored. A fee can only be applied to create-order requests.
|
|
26
|
+
subject.fee(moment: subject_merchant_fee_moment) do |fee|
|
|
27
|
+
fee.amount(subject_merchant_fee_amount, currency: subject_merchant_fee_currency)
|
|
28
|
+
fee.description(subject_merchant_fee_description) if subject_merchant_fee_description
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
else
|
|
34
|
+
builder.merchant(name: merchant_name, password: merchant_password)
|
|
35
|
+
end
|
|
22
36
|
|
|
23
37
|
build_request(builder)
|
|
24
38
|
|
|
@@ -57,6 +71,38 @@ module Docdata
|
|
|
57
71
|
options.fetch(:merchant).fetch(:password)
|
|
58
72
|
end
|
|
59
73
|
|
|
74
|
+
def subject_merchant
|
|
75
|
+
options[:subject_merchant]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def subject_merchant_name
|
|
79
|
+
subject_merchant.fetch(:name)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def subject_merchant_token
|
|
83
|
+
subject_merchant.fetch(:token)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def subject_merchant_fee
|
|
87
|
+
subject_merchant[:fee]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def subject_merchant_fee_moment
|
|
91
|
+
subject_merchant_fee[:moment] || "FULLY_PAID"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def subject_merchant_fee_description
|
|
95
|
+
subject_merchant_fee[:description]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def subject_merchant_fee_amount
|
|
99
|
+
Amount.new(subject_merchant_fee.fetch(:amount)).to_cents
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def subject_merchant_fee_currency
|
|
103
|
+
subject_merchant_fee[:currency] || "EUR"
|
|
104
|
+
end
|
|
105
|
+
|
|
60
106
|
def build_request
|
|
61
107
|
raise NotImplementedError
|
|
62
108
|
end
|
|
@@ -130,14 +176,21 @@ module Docdata
|
|
|
130
176
|
|
|
131
177
|
# The description that is used by payment providers on shopper statements.
|
|
132
178
|
builder.receiptText(receipt_text)
|
|
179
|
+
|
|
180
|
+
# The merchant_reference is used for recurring payments.
|
|
181
|
+
if initial
|
|
182
|
+
builder.paymentRequest do |payment_request|
|
|
183
|
+
payment_request.initialPaymentReference do |payment_reference|
|
|
184
|
+
payment_reference.merchantReference(merchant_reference)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
133
188
|
end
|
|
134
189
|
|
|
135
190
|
private
|
|
136
191
|
|
|
137
192
|
def amount
|
|
138
|
-
|
|
139
|
-
decimal *= 100 # to cents
|
|
140
|
-
decimal.to_i
|
|
193
|
+
Amount.new(options.fetch(:amount)).to_cents
|
|
141
194
|
end
|
|
142
195
|
|
|
143
196
|
def order_reference
|
|
@@ -211,6 +264,14 @@ module Docdata
|
|
|
211
264
|
def receipt_text
|
|
212
265
|
options.fetch(:description)[0, 49]
|
|
213
266
|
end
|
|
267
|
+
|
|
268
|
+
def initial
|
|
269
|
+
options[:initial]
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def merchant_reference
|
|
273
|
+
initial[:merchant_reference]
|
|
274
|
+
end
|
|
214
275
|
end
|
|
215
276
|
|
|
216
277
|
# Start a payment order (Webdirect).
|
|
@@ -219,22 +280,30 @@ module Docdata
|
|
|
219
280
|
# Payment order key belonging to the order for which a transaction needs to be started.
|
|
220
281
|
builder.paymentOrderKey(order_key)
|
|
221
282
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
when PaymentMethod::IDEAL
|
|
227
|
-
payment.iDealPaymentInput do |input|
|
|
228
|
-
input.issuerId(issuer_id)
|
|
283
|
+
if recurring
|
|
284
|
+
builder.recurringPaymentRequest do |payment_request|
|
|
285
|
+
payment_request.initialPaymentReference do |payment_reference|
|
|
286
|
+
payment_reference.merchantReference(merchant_reference)
|
|
229
287
|
end
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
288
|
+
end
|
|
289
|
+
else
|
|
290
|
+
builder.payment do |payment|
|
|
291
|
+
payment.paymentMethod(payment_method)
|
|
292
|
+
|
|
293
|
+
case payment_method
|
|
294
|
+
when PaymentMethod::IDEAL
|
|
295
|
+
payment.iDealPaymentInput do |input|
|
|
296
|
+
input.issuerId(issuer_id)
|
|
297
|
+
end
|
|
298
|
+
when PaymentMethod::SEPA_DIRECT_DEBIT
|
|
299
|
+
payment.directDebitPaymentInput do |input|
|
|
300
|
+
input.holderName(consumer_name)
|
|
301
|
+
input.iban(consumer_iban)
|
|
302
|
+
input.bic(consumer_bic) if consumer_bic
|
|
303
|
+
end
|
|
304
|
+
else
|
|
305
|
+
raise ArgumentError, "Payment method not supported: #{payment_method}"
|
|
235
306
|
end
|
|
236
|
-
else
|
|
237
|
-
raise ArgumentError, "Payment method not supported: #{payment_method}"
|
|
238
307
|
end
|
|
239
308
|
end
|
|
240
309
|
end
|
|
@@ -246,23 +315,31 @@ module Docdata
|
|
|
246
315
|
end
|
|
247
316
|
|
|
248
317
|
def payment_method
|
|
249
|
-
options.fetch(:payment_method)
|
|
318
|
+
options.fetch(:payment_method).to_s
|
|
250
319
|
end
|
|
251
320
|
|
|
252
321
|
def issuer_id
|
|
253
322
|
options.fetch(:issuer_id)
|
|
254
323
|
end
|
|
255
324
|
|
|
256
|
-
def
|
|
257
|
-
options.fetch(:
|
|
325
|
+
def consumer_name
|
|
326
|
+
options.fetch(:consumer_name)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def consumer_iban
|
|
330
|
+
options.fetch(:consumer_iban)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def consumer_bic
|
|
334
|
+
options[:consumer_bic]
|
|
258
335
|
end
|
|
259
336
|
|
|
260
|
-
def
|
|
261
|
-
options
|
|
337
|
+
def recurring
|
|
338
|
+
options[:recurring]
|
|
262
339
|
end
|
|
263
340
|
|
|
264
|
-
def
|
|
265
|
-
|
|
341
|
+
def merchant_reference
|
|
342
|
+
recurring[:merchant_reference]
|
|
266
343
|
end
|
|
267
344
|
end
|
|
268
345
|
|
|
@@ -278,5 +355,57 @@ module Docdata
|
|
|
278
355
|
options.fetch(:order_key)
|
|
279
356
|
end
|
|
280
357
|
end
|
|
358
|
+
|
|
359
|
+
# Create a refund request in the DocData system.
|
|
360
|
+
class RefundRequest < Request
|
|
361
|
+
def build_request(builder)
|
|
362
|
+
# The payment ID on which the refund request needs to be performed.
|
|
363
|
+
builder.paymentId(payment_id)
|
|
364
|
+
|
|
365
|
+
# Merchant's internal ID for identifying this refund.
|
|
366
|
+
builder.merchantRefundReference(refund_reference) if refund_reference
|
|
367
|
+
|
|
368
|
+
# Optional amount to refund.
|
|
369
|
+
builder.amount(amount, currency: currency) if amount
|
|
370
|
+
|
|
371
|
+
# Optional description for this refund.
|
|
372
|
+
builder.description(description) if description
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
private
|
|
376
|
+
|
|
377
|
+
def payment_id
|
|
378
|
+
options.fetch(:payment_id)
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def refund_reference
|
|
382
|
+
options[:refund_reference]
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def amount
|
|
386
|
+
Amount.new(options[:amount]).to_cents if options[:amount]
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def currency
|
|
390
|
+
options[:currency] || "EUR"
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def description
|
|
394
|
+
options[:description]
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
# Retrieve available payment methods for an Order.
|
|
399
|
+
class ListPaymentMethodsRequest < Request
|
|
400
|
+
def build_request(builder)
|
|
401
|
+
builder.paymentOrderKey(order_key)
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
private
|
|
405
|
+
|
|
406
|
+
def order_key
|
|
407
|
+
options.fetch(:order_key)
|
|
408
|
+
end
|
|
409
|
+
end
|
|
281
410
|
end
|
|
282
411
|
end
|
|
@@ -63,7 +63,7 @@ module Docdata
|
|
|
63
63
|
when PaymentMethod::IDEAL
|
|
64
64
|
params[:default_act] = true
|
|
65
65
|
params[:ideal_issuer_id] = issuer_id if issuer_id
|
|
66
|
-
when PaymentMethod::PAYPAL
|
|
66
|
+
when PaymentMethod::PAYPAL, PaymentMethod::SOFORT
|
|
67
67
|
params[:default_act] = true
|
|
68
68
|
end
|
|
69
69
|
end
|
|
@@ -93,7 +93,12 @@ module Docdata
|
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
def merchant_name
|
|
96
|
-
|
|
96
|
+
# Use subject merchant when present, otherwise fallback to merchant.
|
|
97
|
+
if options[:subject_merchant]
|
|
98
|
+
options.fetch(:subject_merchant).fetch(:name)
|
|
99
|
+
else
|
|
100
|
+
options.fetch(:merchant).fetch(:name)
|
|
101
|
+
end
|
|
97
102
|
end
|
|
98
103
|
|
|
99
104
|
def client_language
|
|
@@ -101,7 +106,7 @@ module Docdata
|
|
|
101
106
|
end
|
|
102
107
|
|
|
103
108
|
def payment_method
|
|
104
|
-
options[:payment_method]
|
|
109
|
+
options[:payment_method].to_s
|
|
105
110
|
end
|
|
106
111
|
|
|
107
112
|
def issuer_id
|
|
@@ -280,7 +285,7 @@ module Docdata
|
|
|
280
285
|
authorization_status == "CANCELED"
|
|
281
286
|
end
|
|
282
287
|
|
|
283
|
-
def
|
|
288
|
+
def consumer_iban
|
|
284
289
|
case payment_method
|
|
285
290
|
when PaymentMethod::IDEAL
|
|
286
291
|
payment_info = payment[:extended][:i_deal_payment_info]
|
|
@@ -291,7 +296,7 @@ module Docdata
|
|
|
291
296
|
end
|
|
292
297
|
end
|
|
293
298
|
|
|
294
|
-
def
|
|
299
|
+
def consumer_bic
|
|
295
300
|
case payment_method
|
|
296
301
|
when PaymentMethod::IDEAL
|
|
297
302
|
payment_info = payment[:extended][:i_deal_payment_info]
|
|
@@ -302,7 +307,7 @@ module Docdata
|
|
|
302
307
|
end
|
|
303
308
|
end
|
|
304
309
|
|
|
305
|
-
def
|
|
310
|
+
def consumer_name
|
|
306
311
|
if payment_method == PaymentMethod::IDEAL
|
|
307
312
|
payment_info = payment[:extended][:i_deal_payment_info]
|
|
308
313
|
payment_info[:holder_name] if payment_info
|
|
@@ -319,9 +324,53 @@ module Docdata
|
|
|
319
324
|
private
|
|
320
325
|
|
|
321
326
|
def to_decimal(cents)
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
327
|
+
Amount.from_cents(cents).to_d
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# Response to a refund operation.
|
|
332
|
+
class RefundResponse < Response
|
|
333
|
+
def data
|
|
334
|
+
body[:refund_response]
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def success?
|
|
338
|
+
data.key?(:refund_success)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def error?
|
|
342
|
+
data.key?(:refund_errors)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def errors
|
|
346
|
+
data[:refund_errors]
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Response to a list payment methods operation.
|
|
351
|
+
class ListPaymentMethodsResponse < Response
|
|
352
|
+
def data
|
|
353
|
+
body[:list_payment_methods_response]
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def success?
|
|
357
|
+
data.key?(:list_payment_methods_success)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def error?
|
|
361
|
+
data.key?(:list_payment_methods_errors)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def errors
|
|
365
|
+
data[:list_payment_methods_errors]
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def payment_methods
|
|
369
|
+
data[:list_payment_methods_success][:payment_method].map do |payment_method|
|
|
370
|
+
method = PaymentMethod.new(payment_method[:name])
|
|
371
|
+
method.issuers = payment_method[:issuers][:issuer].map { |issuer| [issuer.attributes["id"], issuer.to_s] }.to_h if payment_method.key?(:issuers)
|
|
372
|
+
method
|
|
373
|
+
end
|
|
325
374
|
end
|
|
326
375
|
end
|
|
327
376
|
end
|
data/lib/docdata/order/urls.rb
CHANGED
|
@@ -5,11 +5,11 @@ module Docdata
|
|
|
5
5
|
module Urls
|
|
6
6
|
# WSDL location, see Order API 1.3.
|
|
7
7
|
WSDL_LIVE_URL = "https://secure.docdatapayments.com/ps/services/paymentservice/1_3?wsdl"
|
|
8
|
-
WSDL_TEST_URL = "https://
|
|
8
|
+
WSDL_TEST_URL = "https://testsecure.docdatapayments.com/ps/services/paymentservice/1_3?wsdl"
|
|
9
9
|
|
|
10
10
|
# Payment Menu base URL, see Functional API.
|
|
11
11
|
MENU_LIVE_URL = "https://secure.docdatapayments.com/ps/menu"
|
|
12
|
-
MENU_TEST_URL = "https://
|
|
12
|
+
MENU_TEST_URL = "https://testsecure.docdatapayments.com/ps/menu"
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: docdata-order
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kentaa
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-05-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '2.0'
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '2.0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -103,7 +103,6 @@ files:
|
|
|
103
103
|
- ".rspec"
|
|
104
104
|
- ".rubocop.yml"
|
|
105
105
|
- ".travis.yml"
|
|
106
|
-
- CHANGELOG.md
|
|
107
106
|
- Gemfile
|
|
108
107
|
- Gemfile.lock
|
|
109
108
|
- LICENSE.txt
|
|
@@ -113,10 +112,10 @@ files:
|
|
|
113
112
|
- bin/setup
|
|
114
113
|
- docdata-order.gemspec
|
|
115
114
|
- lib/docdata/order.rb
|
|
115
|
+
- lib/docdata/order/amount.rb
|
|
116
116
|
- lib/docdata/order/client.rb
|
|
117
117
|
- lib/docdata/order/exception.rb
|
|
118
118
|
- lib/docdata/order/gender.rb
|
|
119
|
-
- lib/docdata/order/ideal.rb
|
|
120
119
|
- lib/docdata/order/payment_method.rb
|
|
121
120
|
- lib/docdata/order/request.rb
|
|
122
121
|
- lib/docdata/order/response.rb
|
|
@@ -134,7 +133,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
134
133
|
requirements:
|
|
135
134
|
- - ">="
|
|
136
135
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: 2.
|
|
136
|
+
version: 2.4.0
|
|
138
137
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
138
|
requirements:
|
|
140
139
|
- - ">="
|
data/CHANGELOG.md
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# Docdata::Order changelog
|
|
2
|
-
|
|
3
|
-
## 1.0.3 (2021-04-15)
|
|
4
|
-
|
|
5
|
-
- Added Revolut to the list of iDEAL issuers.
|
|
6
|
-
|
|
7
|
-
## 1.0.2 (2018-11-30)
|
|
8
|
-
|
|
9
|
-
- Added Handelsbanken to the list of iDEAL issuers.
|
|
10
|
-
|
|
11
|
-
## 1.0.1 (2018-10-05)
|
|
12
|
-
|
|
13
|
-
- Added Moneyou to the list of iDEAL issuers.
|
|
14
|
-
- Fixed result of ExtendedStatusResponse#total_reversed.
|
|
15
|
-
|
|
16
|
-
## 1.0.0 (2018-02-09)
|
|
17
|
-
|
|
18
|
-
- First public release.
|
data/lib/docdata/order/ideal.rb
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Docdata
|
|
4
|
-
module Order
|
|
5
|
-
module Ideal
|
|
6
|
-
ISSUERS = {
|
|
7
|
-
"ABNANL2A" => "ABN AMRO",
|
|
8
|
-
"ASNBNL21" => "ASN Bank",
|
|
9
|
-
"BUNQNL2A" => "bunq",
|
|
10
|
-
"HANDNL2A" => "Handelsbanken",
|
|
11
|
-
"INGBNL2A" => "ING",
|
|
12
|
-
"KNABNL2H" => "Knab bank",
|
|
13
|
-
"MOYONL21" => "Moneyou",
|
|
14
|
-
"RABONL2U" => "Rabobank",
|
|
15
|
-
"RBRBNL21" => "RegioBank",
|
|
16
|
-
"REVOLT21" => "Revolut",
|
|
17
|
-
"SNSBNL2A" => "SNS Bank",
|
|
18
|
-
"TRIONL2U" => "Triodos Bank",
|
|
19
|
-
"FVLBNL22" => "Van Lanschot"
|
|
20
|
-
}.freeze
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|