buckaruby 1.3.1 → 1.7.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/.github/workflows/test.yml +23 -0
- data/.rubocop.yml +22 -5
- data/CHANGELOG.md +25 -7
- data/Gemfile +3 -3
- data/Gemfile.lock +30 -28
- data/README.md +21 -1
- data/buckaruby.gemspec +1 -1
- data/lib/buckaruby.rb +1 -2
- data/lib/buckaruby/field_mapper.rb +52 -0
- data/lib/buckaruby/gateway.rb +30 -4
- data/lib/buckaruby/iban.rb +4 -2
- data/lib/buckaruby/ideal.rb +4 -3
- data/lib/buckaruby/operation.rb +1 -0
- data/lib/buckaruby/payment_method.rb +2 -0
- data/lib/buckaruby/request.rb +24 -0
- data/lib/buckaruby/response.rb +20 -84
- data/lib/buckaruby/signature.rb +22 -4
- data/lib/buckaruby/transaction_status.rb +19 -0
- data/lib/buckaruby/transaction_type.rb +81 -0
- data/lib/buckaruby/version.rb +1 -1
- data/spec/buckaruby/field_mapper_spec.rb +69 -0
- data/spec/buckaruby/gateway_spec.rb +90 -2
- data/spec/buckaruby/signature_spec.rb +6 -0
- data/spec/fixtures/responses/callback_payment_giropay.txt +1 -0
- data/spec/fixtures/responses/callback_payment_sofort.txt +1 -0
- data/spec/fixtures/responses/specify_transaction_success.txt +1 -0
- metadata +18 -9
- data/.travis.yml +0 -11
data/lib/buckaruby/iban.rb
CHANGED
@@ -2,8 +2,10 @@
|
|
2
2
|
|
3
3
|
module Buckaruby
|
4
4
|
# Helper for calculating the IBAN for a given account number, bank code and country code.
|
5
|
-
|
6
|
-
|
5
|
+
module Iban
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def calculate_iban(account_number, bank_code, country_code = "NL")
|
7
9
|
if account_number.nil? || account_number.to_s.empty?
|
8
10
|
raise ArgumentError, "Invalid account number"
|
9
11
|
end
|
data/lib/buckaruby/ideal.rb
CHANGED
@@ -8,12 +8,13 @@ module Buckaruby
|
|
8
8
|
"BUNQNL2A" => "bunq",
|
9
9
|
"HANDNL2A" => "Handelsbanken",
|
10
10
|
"INGBNL2A" => "ING",
|
11
|
-
"KNABNL2H" => "Knab
|
11
|
+
"KNABNL2H" => "Knab",
|
12
12
|
"MOYONL21" => "Moneyou",
|
13
13
|
"RABONL2U" => "Rabobank",
|
14
|
-
"RBRBNL21" => "
|
14
|
+
"RBRBNL21" => "Regiobank",
|
15
|
+
"REVOLT21" => "Revolut",
|
15
16
|
"SNSBNL2A" => "SNS Bank",
|
16
|
-
"TRIONL2U" => "Triodos
|
17
|
+
"TRIONL2U" => "Triodos",
|
17
18
|
"FVLBNL22" => "Van Lanschot"
|
18
19
|
}.freeze
|
19
20
|
end
|
data/lib/buckaruby/operation.rb
CHANGED
@@ -4,6 +4,7 @@ module Buckaruby
|
|
4
4
|
module Operation
|
5
5
|
TRANSACTION_REQUEST = "TransactionRequest"
|
6
6
|
TRANSACTION_STATUS = "TransactionStatus"
|
7
|
+
TRANSACTION_REQUEST_SPECIFICATION = "TransactionRequestSpecification"
|
7
8
|
REFUND_INFO = "RefundInfo"
|
8
9
|
CANCEL_TRANSACTION = "CancelTransaction"
|
9
10
|
end
|
data/lib/buckaruby/request.rb
CHANGED
@@ -159,6 +159,30 @@ module Buckaruby
|
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
162
|
+
# Request for a creating a transaction specification.
|
163
|
+
class TransactionSpecificationRequest < Request
|
164
|
+
def execute(options)
|
165
|
+
super(options.merge(operation: Operation::TRANSACTION_REQUEST_SPECIFICATION))
|
166
|
+
end
|
167
|
+
|
168
|
+
def build_request_params(options)
|
169
|
+
params = {}
|
170
|
+
|
171
|
+
if options[:payment_method]
|
172
|
+
if options[:payment_method].respond_to?(:join)
|
173
|
+
params[:brq_services] = options[:payment_method].join(",")
|
174
|
+
else
|
175
|
+
params[:brq_services] = options[:payment_method]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
params[:brq_latestversiononly] = "true"
|
180
|
+
params[:brq_culture] = options[:culture] || Language::DUTCH
|
181
|
+
|
182
|
+
params
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
162
186
|
# Request for a creating a recurrent transaction.
|
163
187
|
class RecurrentTransactionRequest < TransactionRequest
|
164
188
|
def build_transaction_request_params(options)
|
data/lib/buckaruby/response.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'support/case_insensitive_hash'
|
4
|
+
|
3
5
|
require 'cgi'
|
4
6
|
require 'date'
|
5
7
|
|
@@ -20,19 +22,7 @@ module Buckaruby
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def status
|
23
|
-
|
24
|
-
case params[:brq_statuscode]
|
25
|
-
when '190'
|
26
|
-
TransactionStatus::SUCCESS
|
27
|
-
when '490', '491', '492'
|
28
|
-
TransactionStatus::FAILED
|
29
|
-
when '690'
|
30
|
-
TransactionStatus::REJECTED
|
31
|
-
when '790', '791', '792', '793'
|
32
|
-
TransactionStatus::PENDING
|
33
|
-
when '890', '891'
|
34
|
-
TransactionStatus::CANCELLED
|
35
|
-
end
|
25
|
+
TransactionStatus.parse(params[:brq_statuscode])
|
36
26
|
end
|
37
27
|
|
38
28
|
def timestamp
|
@@ -83,7 +73,7 @@ module Buckaruby
|
|
83
73
|
end
|
84
74
|
|
85
75
|
def verify_signature!(response, config)
|
86
|
-
if params[:brq_apiresult]
|
76
|
+
if params[:brq_apiresult].nil? || params[:brq_apiresult].casecmp("fail") != 0
|
87
77
|
sent_signature = params[:brq_signature]
|
88
78
|
generated_signature = Signature.generate_signature(response, config)
|
89
79
|
|
@@ -174,76 +164,7 @@ module Buckaruby
|
|
174
164
|
end
|
175
165
|
|
176
166
|
def transaction_type
|
177
|
-
|
178
|
-
# See http://support.buckaroo.nl/index.php/Transactietypes
|
179
|
-
case params[:brq_transaction_type]
|
180
|
-
when 'C021', 'V021', # iDEAL
|
181
|
-
'C002', 'C004', 'C005', # (SEPA) Direct Debit
|
182
|
-
'V010', 'V014', # PayPal
|
183
|
-
'C090', 'V090', # Bancontact
|
184
|
-
'C001', # Transfer
|
185
|
-
|
186
|
-
'C044', 'C192', 'C283', 'C293', 'C318', 'C345',
|
187
|
-
'C880', 'C963', 'V002', 'V032', 'V038', 'V044',
|
188
|
-
'V192', 'V283', 'V293', 'V313', 'V318', 'V345',
|
189
|
-
'V696', # Visa
|
190
|
-
|
191
|
-
'C043', 'C089', 'C273', 'C303', 'C328', 'C355',
|
192
|
-
'C876', 'C969', 'V001', 'V031', 'V037', 'V043',
|
193
|
-
'V089', 'V273', 'V303', 'V328', 'V355', 'V702', # MasterCard
|
194
|
-
|
195
|
-
'C046', 'C251', 'C288', 'C308', 'C333', 'C872',
|
196
|
-
'C972', 'V034', 'V040', 'V046', 'V094', 'V245',
|
197
|
-
'V288', 'V308', 'V333', 'V705', # Maestro
|
198
|
-
|
199
|
-
'V003', 'V030', 'V036', 'V042' # American Express
|
200
|
-
|
201
|
-
# Check the recurring flag to detect a normal or recurring transaction.
|
202
|
-
if params[:brq_recurring] && params[:brq_recurring].casecmp("true").zero?
|
203
|
-
TransactionType::PAYMENT_RECURRENT
|
204
|
-
else
|
205
|
-
TransactionType::PAYMENT
|
206
|
-
end
|
207
|
-
when 'C121', # iDEAL
|
208
|
-
'C102', 'C500', # (SEPA) Direct Debit
|
209
|
-
'V110', # PayPal
|
210
|
-
'C092', 'V092', # Bancontact
|
211
|
-
'C101', # Transfer
|
212
|
-
|
213
|
-
'C080', 'C194', 'C281', 'C290', 'C315', 'C342',
|
214
|
-
'C881', 'C961', 'V068', 'V074', 'V080', 'V102',
|
215
|
-
'V194', 'V281', 'V290', 'V315', 'V342', 'V694', # Visa
|
216
|
-
|
217
|
-
'C079', 'C197', 'C300', 'C325', 'C352', 'C371',
|
218
|
-
'C877', 'C967', 'V067', 'V073', 'V079', 'V101',
|
219
|
-
'V149', 'V197', 'V300', 'V325', 'V352', 'V371',
|
220
|
-
'V700', # MasterCard
|
221
|
-
|
222
|
-
'C082', 'C252', 'C286', 'C305', 'C330', 'C873',
|
223
|
-
'C970', 'V070', 'V076', 'V082', 'V246', 'V286',
|
224
|
-
'V305', 'V330', 'V703', # Maestro
|
225
|
-
|
226
|
-
'V066', 'V072', 'V078', 'V103' # American Express
|
227
|
-
TransactionType::REFUND
|
228
|
-
when 'C501', 'C502', 'C562', # (SEPA) Direct Debit
|
229
|
-
'V111', # PayPal
|
230
|
-
|
231
|
-
'C554', 'C593', 'C882', 'V132', 'V138', 'V144',
|
232
|
-
'V544', 'V592', # Visa
|
233
|
-
|
234
|
-
'C553', 'C589', 'C878', 'V131', 'V137', 'V143',
|
235
|
-
'V543', 'V589', # MasterCard
|
236
|
-
|
237
|
-
'C546', 'C551', 'C874', 'V134', 'V140', 'V146',
|
238
|
-
'V545', 'V546', # Maestro
|
239
|
-
|
240
|
-
'V130', 'V136', 'V142' # American Express
|
241
|
-
TransactionType::REVERSAL
|
242
|
-
end
|
243
|
-
else
|
244
|
-
# Fallback when transaction type is not known (cancelling credit card)
|
245
|
-
TransactionType::PAYMENT
|
246
|
-
end
|
167
|
+
TransactionType.parse(params[:brq_transaction_type], params[:brq_recurring])
|
247
168
|
end
|
248
169
|
|
249
170
|
def transaction_status
|
@@ -348,4 +269,19 @@ module Buckaruby
|
|
348
269
|
class CallbackResponse < Response
|
349
270
|
include TransactionResponse
|
350
271
|
end
|
272
|
+
|
273
|
+
# Response when retrieving the specification for a transaction.
|
274
|
+
class TransactionSpecificationResponse < ApiResponse
|
275
|
+
def services
|
276
|
+
@services ||= FieldMapper.map_fields(params, :brq_services)
|
277
|
+
end
|
278
|
+
|
279
|
+
def basic_fields
|
280
|
+
@basic_fields ||= FieldMapper.map_fields(params, :brq_basicfields)
|
281
|
+
end
|
282
|
+
|
283
|
+
def custom_parameters
|
284
|
+
@custom_parameters ||= FieldMapper.map_fields(params, :brq_customparameters)
|
285
|
+
end
|
286
|
+
end
|
351
287
|
end
|
data/lib/buckaruby/signature.rb
CHANGED
@@ -5,8 +5,10 @@ require 'digest'
|
|
5
5
|
module Buckaruby
|
6
6
|
# Calculate a signature based on the parameters of the payment request or response.
|
7
7
|
# -> see BPE 3.0 Gateway NVP, chapter 4 'Digital Signature'
|
8
|
-
|
9
|
-
|
8
|
+
module Signature
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def generate_signature(params, config)
|
10
12
|
case config.hash_method
|
11
13
|
when :sha1
|
12
14
|
Digest::SHA1.hexdigest(generate_signature_string(params, config.secret))
|
@@ -19,11 +21,27 @@ module Buckaruby
|
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
22
|
-
def
|
24
|
+
def generate_signature_string(params, secret)
|
23
25
|
sign_params = params.select { |key, _value| key.to_s.upcase.start_with?("BRQ_", "ADD_", "CUST_") && key.to_s.casecmp("BRQ_SIGNATURE").nonzero? }
|
24
|
-
|
26
|
+
sign_params = order_signature_params(sign_params)
|
27
|
+
|
28
|
+
string = sign_params.map { |param| "#{param[0]}=#{param[1]}" }.join
|
25
29
|
string << secret
|
26
30
|
string
|
27
31
|
end
|
32
|
+
|
33
|
+
# Excerpt from the Buckaroo documentation, chapter 4 'Digital Signature':
|
34
|
+
# In the payment engine, the used lexical sort algorithm uses the following order:
|
35
|
+
# symbols first, then numbers, then case insensitive letters. Also, a shorter string
|
36
|
+
# that is identical to the beginning of a longer string, comes before the longer string.
|
37
|
+
# Take for example the following, comma separated, list which has been sorted:
|
38
|
+
# a_a, a0, a0a, a1a, aaA, aab, aba, aCa
|
39
|
+
CHAR_ORDER = "_01234567890abcdefghijklmnopqrstuvwxyz"
|
40
|
+
|
41
|
+
def order_signature_params(params)
|
42
|
+
params.sort_by do |key, _value|
|
43
|
+
key.to_s.downcase.each_char.map { |c| CHAR_ORDER.index(c) }
|
44
|
+
end
|
45
|
+
end
|
28
46
|
end
|
29
47
|
end
|
@@ -1,11 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Buckaruby
|
4
|
+
# Parses the transaction status code from Buckaroo.
|
4
5
|
module TransactionStatus
|
5
6
|
SUCCESS = 1
|
6
7
|
FAILED = 2
|
7
8
|
REJECTED = 3
|
8
9
|
CANCELLED = 4
|
9
10
|
PENDING = 5
|
11
|
+
|
12
|
+
module_function
|
13
|
+
|
14
|
+
# See https://support.buckaroo.nl/categorie%C3%ABn/transacties/status
|
15
|
+
def parse(brq_statuscode)
|
16
|
+
case brq_statuscode
|
17
|
+
when '190'
|
18
|
+
TransactionStatus::SUCCESS
|
19
|
+
when '490', '491', '492'
|
20
|
+
TransactionStatus::FAILED
|
21
|
+
when '690'
|
22
|
+
TransactionStatus::REJECTED
|
23
|
+
when '790', '791', '792', '793'
|
24
|
+
TransactionStatus::PENDING
|
25
|
+
when '890', '891'
|
26
|
+
TransactionStatus::CANCELLED
|
27
|
+
end
|
28
|
+
end
|
10
29
|
end
|
11
30
|
end
|
@@ -1,10 +1,91 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Buckaruby
|
4
|
+
# Parses the transaction type from Buckaroo.
|
4
5
|
module TransactionType
|
5
6
|
PAYMENT = 1
|
6
7
|
PAYMENT_RECURRENT = 2
|
7
8
|
REFUND = 3
|
8
9
|
REVERSAL = 4
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
# See https://support.buckaroo.nl/categorie%C3%ABn/integratie/transactietypes-overzicht
|
14
|
+
def parse(brq_transaction_type, brq_recurring)
|
15
|
+
if brq_transaction_type && !brq_transaction_type.empty?
|
16
|
+
case brq_transaction_type
|
17
|
+
when 'C021', 'V021', # iDEAL
|
18
|
+
'C002', 'C004', 'C005', # (SEPA) Direct Debit
|
19
|
+
'V010', 'V014', # PayPal
|
20
|
+
'C090', 'V090', # Bancontact
|
21
|
+
'C075', 'N074', # Sofort
|
22
|
+
'C241', 'N031', # Giropay
|
23
|
+
'C001', # Transfer
|
24
|
+
|
25
|
+
'C044', 'C192', 'C283', 'C293', 'C318', 'C345',
|
26
|
+
'C880', 'C963', 'V002', 'V032', 'V038', 'V044',
|
27
|
+
'V192', 'V283', 'V293', 'V313', 'V318', 'V345',
|
28
|
+
'V696', # Visa
|
29
|
+
|
30
|
+
'C043', 'C089', 'C273', 'C303', 'C328', 'C355',
|
31
|
+
'C876', 'C969', 'V001', 'V031', 'V037', 'V043',
|
32
|
+
'V089', 'V273', 'V303', 'V328', 'V355', 'V702', # MasterCard
|
33
|
+
|
34
|
+
'C046', 'C251', 'C288', 'C308', 'C333', 'C872',
|
35
|
+
'C972', 'V034', 'V040', 'V046', 'V094', 'V245',
|
36
|
+
'V288', 'V308', 'V333', 'V705', # Maestro
|
37
|
+
|
38
|
+
'V003', 'V030', 'V036', 'V042' # American Express
|
39
|
+
|
40
|
+
# Check the recurring flag to detect a normal or recurring transaction.
|
41
|
+
if brq_recurring && brq_recurring.casecmp("true").zero?
|
42
|
+
TransactionType::PAYMENT_RECURRENT
|
43
|
+
else
|
44
|
+
TransactionType::PAYMENT
|
45
|
+
end
|
46
|
+
when 'C121', # iDEAL
|
47
|
+
'C102', 'C500', # (SEPA) Direct Debit
|
48
|
+
'V110', # PayPal
|
49
|
+
'C092', 'V092', # Bancontact
|
50
|
+
'C543', 'N540', # Sofort
|
51
|
+
'C242', 'N541', # Giropay
|
52
|
+
'C101', # Transfer
|
53
|
+
|
54
|
+
'C080', 'C194', 'C281', 'C290', 'C315', 'C342',
|
55
|
+
'C881', 'C961', 'V068', 'V074', 'V080', 'V102',
|
56
|
+
'V194', 'V281', 'V290', 'V315', 'V342', 'V694', # Visa
|
57
|
+
|
58
|
+
'C079', 'C197', 'C300', 'C325', 'C352', 'C371',
|
59
|
+
'C877', 'C967', 'V067', 'V073', 'V079', 'V101',
|
60
|
+
'V149', 'V197', 'V300', 'V325', 'V352', 'V371',
|
61
|
+
'V700', # MasterCard
|
62
|
+
|
63
|
+
'C082', 'C252', 'C286', 'C305', 'C330', 'C873',
|
64
|
+
'C970', 'V070', 'V076', 'V082', 'V246', 'V286',
|
65
|
+
'V305', 'V330', 'V703', # Maestro
|
66
|
+
|
67
|
+
'V066', 'V072', 'V078', 'V103' # American Express
|
68
|
+
TransactionType::REFUND
|
69
|
+
when 'C501', 'C502', 'C562', # (SEPA) Direct Debit
|
70
|
+
'V111', # PayPal
|
71
|
+
'C544', # Sofort
|
72
|
+
|
73
|
+
'C554', 'C593', 'C882', 'V132', 'V138', 'V144',
|
74
|
+
'V544', 'V592', # Visa
|
75
|
+
|
76
|
+
'C553', 'C589', 'C878', 'V131', 'V137', 'V143',
|
77
|
+
'V543', 'V589', # MasterCard
|
78
|
+
|
79
|
+
'C546', 'C551', 'C874', 'V134', 'V140', 'V146',
|
80
|
+
'V545', 'V546', # Maestro
|
81
|
+
|
82
|
+
'V130', 'V136', 'V142' # American Express
|
83
|
+
TransactionType::REVERSAL
|
84
|
+
end
|
85
|
+
else
|
86
|
+
# Fallback when transaction type is not known (e.g. cancelling credit card)
|
87
|
+
TransactionType::PAYMENT
|
88
|
+
end
|
89
|
+
end
|
9
90
|
end
|
10
91
|
end
|
data/lib/buckaruby/version.rb
CHANGED
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Buckaruby::FieldMapper do
|
6
|
+
describe '.map_fields' do
|
7
|
+
let(:fields) do
|
8
|
+
{
|
9
|
+
brq_services_1_description: "iDEAL",
|
10
|
+
brq_services_1_name: "ideal",
|
11
|
+
brq_services_1_version: "2",
|
12
|
+
brq_services_1_supportedcurrencies_1_code: "EUR",
|
13
|
+
brq_services_1_supportedcurrencies_1_isonumber: "978",
|
14
|
+
brq_services_1_supportedcurrencies_1_name: "Euro",
|
15
|
+
brq_services_2_description: "Visa",
|
16
|
+
brq_services_2_name: "visa",
|
17
|
+
brq_services_2_version: "1",
|
18
|
+
brq_services_2_supportedcurrencies_1_code: "GBP",
|
19
|
+
brq_services_2_supportedcurrencies_1_isonumber: "826",
|
20
|
+
brq_services_2_supportedcurrencies_1_name: "Pond",
|
21
|
+
brq_services_2_supportedcurrencies_2_code: "USD",
|
22
|
+
brq_services_2_supportedcurrencies_2_isonumber: "840",
|
23
|
+
brq_services_2_supportedcurrencies_2_name: "US Dollar"
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'maps NVP fields to arrays and hashes' do
|
28
|
+
services = Buckaruby::FieldMapper.map_fields(fields, :brq_services)
|
29
|
+
expect(services).to be_an_instance_of(Array)
|
30
|
+
expect(services.count).to eq(2)
|
31
|
+
|
32
|
+
ideal = services.first
|
33
|
+
expect(ideal).to be_an_instance_of(Buckaruby::Support::CaseInsensitiveHash)
|
34
|
+
expect(ideal[:description]).to eq("iDEAL")
|
35
|
+
expect(ideal[:name]).to eq("ideal")
|
36
|
+
expect(ideal[:version]).to eq("2")
|
37
|
+
|
38
|
+
visa = services.last
|
39
|
+
expect(visa).to be_an_instance_of(Buckaruby::Support::CaseInsensitiveHash)
|
40
|
+
expect(visa[:description]).to eq("Visa")
|
41
|
+
expect(visa[:name]).to eq("visa")
|
42
|
+
expect(visa[:version]).to eq("1")
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'maps NVP subfields to arrays and hashes' do
|
46
|
+
services = Buckaruby::FieldMapper.map_fields(fields, :brq_services)
|
47
|
+
|
48
|
+
currencies = services.first[:supportedcurrencies]
|
49
|
+
expect(currencies).to be_an_instance_of(Array)
|
50
|
+
expect(currencies.count).to eq(1)
|
51
|
+
|
52
|
+
currency = currencies.first
|
53
|
+
expect(currency).to be_an_instance_of(Buckaruby::Support::CaseInsensitiveHash)
|
54
|
+
expect(currency[:code]).to eq("EUR")
|
55
|
+
expect(currency[:isonumber]).to eq("978")
|
56
|
+
expect(currency[:name]).to eq("Euro")
|
57
|
+
|
58
|
+
currencies = services.last[:supportedcurrencies]
|
59
|
+
expect(currencies).to be_an_instance_of(Array)
|
60
|
+
expect(currencies.count).to eq(2)
|
61
|
+
|
62
|
+
currency = currencies.first
|
63
|
+
expect(currency).to be_an_instance_of(Buckaruby::Support::CaseInsensitiveHash)
|
64
|
+
expect(currency[:code]).to eq("GBP")
|
65
|
+
expect(currency[:isonumber]).to eq("826")
|
66
|
+
expect(currency[:name]).to eq("Pond")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|