vaulted_billing 1.1.0 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -13,6 +13,7 @@ Since you only store identifiers on your end, you are only responsible for: 1) t
13
13
  VaultedBilling supports the following payment providers:
14
14
 
15
15
  * [Authorize.net Customer Information Manager][authorize-net-cim]
16
+ * [IP Commerce Tokenization][ipcommerce-tokenization]
16
17
  * [Network Merchant Inc. Customer Vault][nmi-vault]
17
18
 
18
19
  VaultedBilling also supports the following fictitious payment provider for testing purposes:
@@ -67,10 +68,6 @@ bogus.add_customer(customer).tap do |customer_response|
67
68
  end
68
69
  ```
69
70
 
70
- ### Real world example
71
-
72
- TODO: Real world example coming soon.
73
-
74
71
  ## Testing
75
72
 
76
73
  When you're manually testing your application - meaning Development mode - it is often best to actually have a "sandbox" or "test" account with your payment processor. In this mode, you should use those credentials with VaultedBilling and indicate to VaultedBilling that the processor is in test mode, either by setting it in the VaultedBilling::Configuration (see Configuration) or when you instantiate your Gateway. You should note that all gateways, except for the Bogus gateway, attempt to open network connections when in use. So, if you are testing with them (which is suggested), you should look into an HTTP mocking library like [VCR][vcr] with [WebMock][webmock].
@@ -80,6 +77,7 @@ Strictly for testing interaction with the VaultedBilling library, there is a "Bo
80
77
  [ci]: http://travis-ci.org/envylabs/vaulted_billing
81
78
  [ci-image]: https://secure.travis-ci.org/envylabs/vaulted_billing.png
82
79
  [authorize-net-cim]: http://www.authorize.net/solutions/merchantsolutions/merchantservices/cim/
80
+ [ipcommerce-tokenization]: http://developer.ipcommerce.com/developer/integration/value_added_capabilities.aspx
83
81
  [nmi-vault]: https://www.nmi.com/newsmedia/index.php?ann_id=14
84
82
  [bundler]: http://gembundler.com/
85
83
  [vcr]: https://github.com/myronmarston/vcr
@@ -1,3 +1,5 @@
1
+ require 'iso3166'
2
+
1
3
  module VaultedBilling
2
4
  ##
3
5
  # Intermediary class used to translate your local credit card information
@@ -15,8 +17,24 @@ module VaultedBilling
15
17
  # the card is already stored on the gateway and is not new information.
16
18
  #
17
19
  class CreditCard
20
+ class Country < String
21
+ def to_iso_3166
22
+ country.number.to_i if country.data
23
+ end
24
+
25
+ def to_ipcommerce_id
26
+ VaultedBilling::Gateways::Ipcommerce::Countries.index(self) || 0
27
+ end
28
+
29
+ private
30
+
31
+ def country
32
+ ISO3166::Country.new(self)
33
+ end
34
+ end
35
+
18
36
  attr_accessor :card_number # The customer's credit card number
19
- attr_accessor :country # The country of the credit card address.
37
+ attr_reader :country # The country of the credit card address.
20
38
  attr_accessor :currency # The currency used by the credit card.
21
39
  attr_accessor :cvv_number # The verification number (CVV2) on the card.
22
40
  attr_accessor :expires_on # The date on which the credit card expires.
@@ -41,9 +59,7 @@ module VaultedBilling
41
59
  send("#{key}=", value) if respond_to?("#{key}=")
42
60
  end
43
61
  end
44
-
45
- def to_vaulted_billing; self; end
46
-
62
+
47
63
  def ==(o)
48
64
  self.attributes == o.attributes
49
65
  end
@@ -65,5 +81,15 @@ module VaultedBilling
65
81
  :phone => phone
66
82
  }
67
83
  end
84
+
85
+ def country=(input)
86
+ @country = Country.new(input) if input
87
+ end
88
+
89
+ def name_on_card
90
+ [first_name, last_name].compact.join(" ")
91
+ end
92
+
93
+ def to_vaulted_billing; self; end
68
94
  end
69
95
  end
@@ -1,9 +1,11 @@
1
1
  module VaultedBilling
2
2
  module Gateway
3
3
  module Response
4
+ attr_accessor :response
4
5
  attr_accessor :raw_response
5
6
  attr_accessor :response_message
6
7
  attr_accessor :error_code
8
+ attr_accessor :transactions
7
9
  attr_writer :connection_error
8
10
  attr_writer :success
9
11
  def success?; @success; end
@@ -22,11 +24,11 @@ module VaultedBilling
22
24
  raise NotImplementedError
23
25
  end
24
26
 
25
- def add_customer_credit_card(customer, credit_card)
27
+ def add_customer_credit_card(customer, credit_card, options = {})
26
28
  raise NotImplementedError
27
29
  end
28
30
 
29
- def update_customer_credit_card(customer, credit_card)
31
+ def update_customer_credit_card(customer, credit_card, options = {})
30
32
  raise NotImplementedError
31
33
  end
32
34
 
@@ -65,6 +67,7 @@ module VaultedBilling
65
67
  o.raw_response = options[:raw_response] || ''
66
68
  o.response_message = options[:response_message]
67
69
  o.error_code = options[:error_code]
70
+ o.transactions = options[:transactions] || nil
68
71
  yield(o) if block_given?
69
72
  end
70
73
  end
@@ -58,7 +58,7 @@ module VaultedBilling
58
58
  respond_with(customer, result, :success => result.success?)
59
59
  end
60
60
 
61
- def add_customer_credit_card(customer, credit_card)
61
+ def add_customer_credit_card(customer, credit_card, options = {})
62
62
  customer = customer.to_vaulted_billing
63
63
  credit_card = credit_card.to_vaulted_billing
64
64
  data = build_request('createCustomerPaymentProfileRequest') { |xml|
@@ -75,7 +75,7 @@ module VaultedBilling
75
75
  end
76
76
  end
77
77
 
78
- def update_customer_credit_card(customer, credit_card)
78
+ def update_customer_credit_card(customer, credit_card, options = {})
79
79
  customer = customer.to_vaulted_billing
80
80
  credit_card = credit_card.to_vaulted_billing
81
81
  data = build_request('updateCustomerPaymentProfileRequest') { |xml|
@@ -30,11 +30,11 @@ module VaultedBilling
30
30
  respond_with customer.to_vaulted_billing
31
31
  end
32
32
 
33
- def add_customer_credit_card(customer, credit_card)
33
+ def add_customer_credit_card(customer, credit_card, options = {})
34
34
  respond_with(credit_card.to_vaulted_billing) { |c| c.vault_id = new_identifier }
35
35
  end
36
36
 
37
- def update_customer_credit_card(customer, credit_card)
37
+ def update_customer_credit_card(customer, credit_card, options = {})
38
38
  respond_with credit_card.to_vaulted_billing
39
39
  end
40
40
 
@@ -42,19 +42,19 @@ module VaultedBilling
42
42
  respond_with credit_card.to_vaulted_billing
43
43
  end
44
44
 
45
- def authorize(customer, credit_card, amount)
45
+ def authorize(customer, credit_card, amount, options = {})
46
46
  transaction_response
47
47
  end
48
48
 
49
- def purchase(customer, credit_card, amount)
49
+ def purchase(customer, credit_card, amount, options = {})
50
50
  transaction_response
51
51
  end
52
52
 
53
- def void(transaction_id)
53
+ def void(transaction_id, options = {})
54
54
  transaction_response
55
55
  end
56
56
 
57
- def capture(transaction_id, amount)
57
+ def capture(transaction_id, amount, options = {})
58
58
  transaction_response
59
59
  end
60
60
 
@@ -18,6 +18,34 @@ module VaultedBilling
18
18
  class Ipcommerce
19
19
  include VaultedBilling::Gateway
20
20
 
21
+ Countries = %w(
22
+ !! AF AX AL DZ AS AD AO AI AQ
23
+ AG AR AM AW AU AT AZ BS BH BD
24
+ BB BY BE BZ BJ BM BT BO BA BW
25
+ BV BR IO BN BG BF BI KH CM CA
26
+ CV KY CF TD CL CN CX CC CO KM
27
+ CG CD CK CR CI HR CU CY CZ DK
28
+ DJ DM DO EC EG SV GQ ER EE ET
29
+ FK FO FJ FI FR FX GF PF TF GA
30
+ GM GE DE GH GI GR GL GD GP GU
31
+ GT GG GN GW GY HT HM VA HN HK
32
+ HU IS IN ID IR IQ IE IM IL IT
33
+ JM JP JE JO KZ KE KI KP KR KW
34
+ KG LA LV LB LS LR LY LI LT LU
35
+ MO MK MG MW MY MV ML MT MH MQ
36
+ MR MU YT MX FM MD MC MN ME MS
37
+ MA MZ MM NA NR NP NL AN NC NZ
38
+ NI NE NG NU NF MP NO OM PK PW
39
+ PS PA PG PY PE PH PN PL PT PR
40
+ QA RE RO RU RW SH KN LC PM VC
41
+ WS SM ST SA SN RS CS SC SL SG
42
+ SK SI SB SO ZA GS ES LK SD SR
43
+ SJ SZ SE CH SY TW TJ TZ TH TL
44
+ TG TK TP TO TT TN TR TM TC TV
45
+ UG UA AE GB US UM UY UZ VU VE
46
+ VN VG VI WF EH YE YU ZM ZW
47
+ )
48
+
21
49
  Companies = {
22
50
  2 => /^4\d{12}(\d{3})?$/, # Visa
23
51
  3 => /^(5[1-5]\d{4}|677189)\d{10}$/, # MasterCard
@@ -29,7 +57,7 @@ module VaultedBilling
29
57
 
30
58
  class ServiceKeyStore
31
59
  UnavailableKeyError = Class.new(VaultedBilling::CredentialError)
32
-
60
+
33
61
  attr_reader :identity_token
34
62
 
35
63
  def initialize(identity_token)
@@ -59,10 +87,12 @@ module VaultedBilling
59
87
  end
60
88
 
61
89
  def renew!
90
+ response = http.get
91
+ raise(UnavailableKeyError, 'Unable to renew service keys.') unless response.success?
62
92
  @expires_at = Time.now + 30.minutes
63
- @key = http.get.body.try(:[], 1...-1)
93
+ @key = response.body.try(:[], 1...-1)
64
94
  end
65
-
95
+
66
96
  private
67
97
  def http
68
98
  @request ||= begin
@@ -101,15 +131,22 @@ module VaultedBilling
101
131
  # A stub, since the IP Commerce only generates tokens during
102
132
  # successful authorization transactions.
103
133
  #
104
- #--
105
- # TODO: If necessary, this may be implemented by Authorizing the given card for $1.00, then voiding immediately.
106
- #++
107
- #
108
- def add_customer_credit_card(customer, credit_card)
109
- respond_with credit_card.to_vaulted_billing
134
+ def add_customer_credit_card(customer, credit_card, options = {})
135
+ credit_card = credit_card.to_vaulted_billing
136
+
137
+ authorization = authorize(customer, credit_card, 1.00, options)
138
+ void = void(authorization.id, options) if authorization.success?
139
+
140
+ respond_with(credit_card, authorization.response, {
141
+ :success => authorization.success?,
142
+ :transactions => { :void => void, :authorization => authorization }
143
+ }) do |cc|
144
+ cc.vault_id = authorization.response.body['PaymentAccountDataToken'].presence
145
+ end
110
146
  end
111
147
 
112
148
  def authorize(customer, credit_card, amount, options = {})
149
+ credit_card = credit_card.to_vaulted_billing
113
150
  data = {
114
151
  "__type" => "AuthorizeTransaction:http://schemas.ipcommerce.com/CWS/v2.0/Transactions/Rest",
115
152
  :ApplicationProfileId => @application_id,
@@ -118,31 +155,25 @@ module VaultedBilling
118
155
  :"__type" => "BankcardTransaction:http://schemas.ipcommerce.com/CWS/v2.0/Transactions/Bankcard",
119
156
  :TransactionData => {
120
157
  :Amount => "%.2f" % amount,
158
+ :ApprovalCode => options[:approval_code],
121
159
  :CurrencyCode => 4,
122
160
  :TransactionDateTime => Time.now.xmlschema,
123
161
  :CustomerPresent => 0,
124
- :EntryMode => 1,
162
+ :EntryMode => options[:entry_mode] || 1, # 1 => keyed
125
163
  :GoodsType => 0,
126
164
  :IndustryType => 2,
127
165
  :SignatureCaptured => false,
128
166
  :OrderNumber => options[:order_id] || generate_order_number
129
167
  },
130
- :TenderData => {
131
- :CardData => {
132
- :CardholderName => nil,
133
- :CardType => self.class.credit_card_type_id(credit_card.card_number),
134
- :Expire => credit_card.expires_on.try(:strftime, "%m%y"),
135
- :PAN => credit_card.card_number
136
- }
137
- }
168
+ :TenderData => card_data(credit_card)
138
169
  }
139
170
  }
140
-
171
+
141
172
  response = http(options[:workflow_id] || @service_id).post(data)
142
- transaction = new_transaction_from_response(response)
173
+ transaction = new_transaction_from_response(response)
143
174
  respond_with(transaction,
144
175
  response,
145
- :success => (transaction.code == 1))
176
+ :success => valid_code?(transaction.code))
146
177
  end
147
178
 
148
179
  def capture(transaction_id, amount, options = {})
@@ -156,15 +187,16 @@ module VaultedBilling
156
187
  :Amount => "%.2f" % amount
157
188
  }
158
189
  }
159
-
190
+
160
191
  response = http(options[:workflow_id] || @service_id, transaction_id).put(data)
161
192
  transaction = new_transaction_from_response(response)
162
193
  respond_with(transaction,
163
194
  response,
164
- :success => (transaction.code == 1))
195
+ :success => valid_code?(transaction.code))
165
196
  end
166
197
 
167
198
  def purchase(customer, credit_card, amount, options = {})
199
+ credit_card = credit_card.try(:to_vaulted_billing)
168
200
  data = {
169
201
  "__type" => "AuthorizeAndCaptureTransaction:http://schemas.ipcommerce.com/CWS/v2.0/Transactions/Rest",
170
202
  :ApplicationProfileId => @application_id,
@@ -173,31 +205,25 @@ module VaultedBilling
173
205
  :"__type" => "BankcardTransaction:http://schemas.ipcommerce.com/CWS/v2.0/Transactions/Bankcard",
174
206
  :TransactionData => {
175
207
  :Amount => "%.2f" % amount,
208
+ :ApprovalCode => options[:approval_code],
176
209
  :CurrencyCode => 4,
177
210
  :TransactionDateTime => Time.now.xmlschema,
178
211
  :CustomerPresent => 0,
179
212
  :EmployeeId => options[:employee_id],
180
- :EntryMode => 1,
213
+ :EntryMode => options[:entry_mode] || 1, # 1 => keyed
181
214
  :GoodsType => 0,
182
215
  :IndustryType => 2,
183
216
  :OrderNumber => options[:order_id] || generate_order_number,
184
217
  :SignatureCaptured => false
185
218
  },
186
- :TenderData => {
187
- :CardData => {
188
- :CardholderName => nil,
189
- :CardType => self.class.credit_card_type_id(credit_card.card_number),
190
- :Expire => credit_card.expires_on.try(:strftime, "%m%y"),
191
- :PAN => credit_card.card_number
192
- }
193
- }
219
+ :TenderData => card_data(credit_card)
194
220
  }
195
221
  }
196
222
  response = http(options[:workflow_id] || @service_id).post(data)
197
223
  transaction = new_transaction_from_response(response)
198
224
  respond_with(transaction,
199
225
  response,
200
- :success => (transaction.code == 1))
226
+ :success => valid_code?(transaction.code))
201
227
  end
202
228
 
203
229
  def refund(transaction_id, amount, options = {})
@@ -212,14 +238,14 @@ module VaultedBilling
212
238
  :Amount => "%.2f" % amount
213
239
  }
214
240
  }
215
-
241
+
216
242
  response = http(options[:workflow_id] || @service_id).post(data)
217
243
  transaction = new_transaction_from_response(response)
218
244
  respond_with(transaction,
219
245
  response,
220
- :success => (transaction.code == 1))
246
+ :success => valid_code?(transaction.code))
221
247
  end
222
-
248
+
223
249
  ##
224
250
  # A stub, since the IP Commerce only generates tokens during
225
251
  # successful authorization transactions.
@@ -248,10 +274,10 @@ module VaultedBilling
248
274
  # A stub, since the IP Commerce only generates tokens during
249
275
  # successful authorization transactions.
250
276
  #
251
- def update_customer_credit_card(customer, credit_card)
252
- respond_with credit_card.to_vaulted_billing
277
+ def update_customer_credit_card(customer, credit_card, options = {})
278
+ add_customer_credit_card(customer, credit_card, options)
253
279
  end
254
-
280
+
255
281
  def void(transaction_id, options = {})
256
282
  data = {
257
283
  :"__type" => "Undo:http://schemas.ipcommerce.com/CWS/v2.0/Transactions/Rest",
@@ -267,9 +293,45 @@ module VaultedBilling
267
293
  transaction = new_transaction_from_response(response)
268
294
  respond_with(transaction,
269
295
  response,
270
- :success => (transaction.code == 1))
296
+ :success => valid_code?(transaction.code))
297
+ end
298
+
299
+
300
+ protected
301
+
302
+ def valid_code?(code)
303
+ [0,1].include?(code)
271
304
  end
272
305
 
306
+ def card_data(credit_card)
307
+ return nil if credit_card.nil?
308
+
309
+ if credit_card.vault_id.present?
310
+ { :PaymentAccountDataToken => credit_card.vault_id }
311
+ else
312
+ {
313
+ :CardData => {
314
+ :CardholderName => credit_card.name_on_card,
315
+ :CardType => self.class.credit_card_type_id(credit_card.card_number),
316
+ :Expire => credit_card.expires_on.try(:strftime, "%m%y"),
317
+ :PAN => credit_card.card_number
318
+ },
319
+ :CardSecurityData => {
320
+ :AVSData => {
321
+ :CardholderName => credit_card.name_on_card,
322
+ :Street => credit_card.street_address.try(:[], (0...20)),
323
+ :City => credit_card.locality,
324
+ :StateProvince => credit_card.region,
325
+ :PostalCode => credit_card.postal_code.try(:[], (0...5)),
326
+ :Country => credit_card.country.try(:to_ipcommerce_id),
327
+ :Phone => credit_card.phone
328
+ }.select { |k, v| !v.nil? },
329
+ :CVDataProvided => credit_card.cvv_number.nil? ? nil : 2,
330
+ :CVData => credit_card.cvv_number
331
+ }.select { |k, v| !v.nil? }
332
+ }
333
+ end
334
+ end
273
335
 
274
336
  private
275
337
 
@@ -286,8 +348,7 @@ module VaultedBilling
286
348
  end
287
349
  return 1
288
350
  end
289
-
290
-
351
+
291
352
  def generate_order_number
292
353
  (Time.now.to_f * 100000).to_i.to_s(36) + rand(60000000).to_s(36)
293
354
  end
@@ -304,23 +365,22 @@ module VaultedBilling
304
365
  :on_success => :on_success
305
366
  })
306
367
  end
307
-
368
+
308
369
  def before_request(request)
309
370
  request.body = MultiJson.encode(request.body)
310
- # request.delete "accept"
311
371
  end
312
-
372
+
313
373
  def on_success(response)
314
374
  response.body = decode_body(response.body) || {}
315
375
  response.success = [1, 2].include?(response.body['Status'])
316
376
  end
317
-
377
+
318
378
  def decode_body(string)
319
379
  MultiJson.decode(string)
320
380
  rescue MultiJson::DecodeError
321
381
  parse_error(string)
322
382
  end
323
-
383
+
324
384
  def new_transaction_from_response(response)
325
385
  if response.success?
326
386
  Transaction.new({
@@ -346,27 +406,28 @@ module VaultedBilling
346
406
  end
347
407
  end
348
408
  end
349
-
409
+
350
410
  def parse_validation_errors(response)
351
411
  errors = ChainableHash.new.merge(response.body || {})
352
412
  if errors['ErrorResponse']['ValidationErrors'].present?
353
413
  [errors['ErrorResponse']['ValidationErrors']['ValidationError']].flatten.collect { |e| e['RuleMessage'] }
354
414
  end
355
415
  end
356
-
416
+
357
417
  def parse_error(response_body)
358
418
  MultiXml.parse(response_body)
359
419
  rescue MultiXml::ParseError
360
420
  end
361
-
421
+
362
422
  def respond_with(object, response = nil, options = {}, &block)
363
423
  super(object, options, &block).tap do |o|
364
424
  if response
425
+ o.response = response
365
426
  o.raw_response = response.raw_response.try(:body)
366
427
  o.connection_error = response.connection_error
367
428
  end
368
429
  end
369
430
  end
370
- end
431
+ end
371
432
  end
372
- end
433
+ end
@@ -52,7 +52,7 @@ module VaultedBilling
52
52
  respond_with customer.to_vaulted_billing
53
53
  end
54
54
 
55
- def add_customer_credit_card(customer, credit_card)
55
+ def add_customer_credit_card(customer, credit_card, options = {})
56
56
  data = storage_data('add_customer', customer.to_vaulted_billing, credit_card.to_vaulted_billing)
57
57
  response = http.post(data)
58
58
  respond_with(credit_card, response, :success => response.success?) do |c|
@@ -60,7 +60,7 @@ module VaultedBilling
60
60
  end
61
61
  end
62
62
 
63
- def update_customer_credit_card(customer, credit_card)
63
+ def update_customer_credit_card(customer, credit_card, options = {})
64
64
  data = storage_data('update_customer', customer.to_vaulted_billing, credit_card.to_vaulted_billing)
65
65
  response = http.post(data)
66
66
  respond_with(credit_card, response, :success => response.success?)
@@ -1,4 +1,5 @@
1
1
  require 'uri'
2
+ require 'net/http'
2
3
 
3
4
  module VaultedBilling
4
5
  class HTTP
@@ -1,3 +1,3 @@
1
1
  module VaultedBilling
2
- Version = '1.1.0'
2
+ Version = '1.1.2'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vaulted_billing
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-17 00:00:00.000000000Z
12
+ date: 2011-08-30 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &2168747560 !ruby/object:Gem::Requirement
16
+ requirement: &2153465380 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '2.3'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2168747560
24
+ version_requirements: *2153465380
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: builder
27
- requirement: &2168747100 !ruby/object:Gem::Requirement
27
+ requirement: &2153464920 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 2.1.2
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2168747100
35
+ version_requirements: *2153464920
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: multi_json
38
- requirement: &2168746640 !ruby/object:Gem::Requirement
38
+ requirement: &2153464460 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '1.0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *2168746640
46
+ version_requirements: *2153464460
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: multi_xml
49
- requirement: &2168746180 !ruby/object:Gem::Requirement
49
+ requirement: &2153464000 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,21 @@ dependencies:
54
54
  version: 0.3.0
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *2168746180
57
+ version_requirements: *2153464000
58
+ - !ruby/object:Gem::Dependency
59
+ name: countries
60
+ requirement: &2153463620 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *2153463620
58
69
  - !ruby/object:Gem::Dependency
59
70
  name: rspec
60
- requirement: &2168745720 !ruby/object:Gem::Requirement
71
+ requirement: &2153463080 !ruby/object:Gem::Requirement
61
72
  none: false
62
73
  requirements:
63
74
  - - ~>
@@ -65,10 +76,10 @@ dependencies:
65
76
  version: '2.4'
66
77
  type: :development
67
78
  prerelease: false
68
- version_requirements: *2168745720
79
+ version_requirements: *2153463080
69
80
  - !ruby/object:Gem::Dependency
70
81
  name: vcr
71
- requirement: &2168745260 !ruby/object:Gem::Requirement
82
+ requirement: &2153462580 !ruby/object:Gem::Requirement
72
83
  none: false
73
84
  requirements:
74
85
  - - ~>
@@ -76,10 +87,10 @@ dependencies:
76
87
  version: '1.7'
77
88
  type: :development
78
89
  prerelease: false
79
- version_requirements: *2168745260
90
+ version_requirements: *2153462580
80
91
  - !ruby/object:Gem::Dependency
81
92
  name: webmock
82
- requirement: &2168744800 !ruby/object:Gem::Requirement
93
+ requirement: &2153462120 !ruby/object:Gem::Requirement
83
94
  none: false
84
95
  requirements:
85
96
  - - ~>
@@ -87,10 +98,10 @@ dependencies:
87
98
  version: '1.6'
88
99
  type: :development
89
100
  prerelease: false
90
- version_requirements: *2168744800
101
+ version_requirements: *2153462120
91
102
  - !ruby/object:Gem::Dependency
92
103
  name: factory_girl
93
- requirement: &2168744340 !ruby/object:Gem::Requirement
104
+ requirement: &2153461660 !ruby/object:Gem::Requirement
94
105
  none: false
95
106
  requirements:
96
107
  - - ~>
@@ -98,10 +109,10 @@ dependencies:
98
109
  version: '1.3'
99
110
  type: :development
100
111
  prerelease: false
101
- version_requirements: *2168744340
112
+ version_requirements: *2153461660
102
113
  - !ruby/object:Gem::Dependency
103
114
  name: faker
104
- requirement: &2168743880 !ruby/object:Gem::Requirement
115
+ requirement: &2153461200 !ruby/object:Gem::Requirement
105
116
  none: false
106
117
  requirements:
107
118
  - - ~>
@@ -109,10 +120,10 @@ dependencies:
109
120
  version: '0.9'
110
121
  type: :development
111
122
  prerelease: false
112
- version_requirements: *2168743880
123
+ version_requirements: *2153461200
113
124
  - !ruby/object:Gem::Dependency
114
125
  name: rake
115
- requirement: &2168763880 !ruby/object:Gem::Requirement
126
+ requirement: &2153460740 !ruby/object:Gem::Requirement
116
127
  none: false
117
128
  requirements:
118
129
  - - ~>
@@ -120,10 +131,10 @@ dependencies:
120
131
  version: '0.9'
121
132
  type: :development
122
133
  prerelease: false
123
- version_requirements: *2168763880
134
+ version_requirements: *2153460740
124
135
  - !ruby/object:Gem::Dependency
125
136
  name: watchr
126
- requirement: &2168763500 !ruby/object:Gem::Requirement
137
+ requirement: &2153460360 !ruby/object:Gem::Requirement
127
138
  none: false
128
139
  requirements:
129
140
  - - ! '>='
@@ -131,10 +142,10 @@ dependencies:
131
142
  version: '0'
132
143
  type: :development
133
144
  prerelease: false
134
- version_requirements: *2168763500
145
+ version_requirements: *2153460360
135
146
  - !ruby/object:Gem::Dependency
136
147
  name: open4
137
- requirement: &2168763040 !ruby/object:Gem::Requirement
148
+ requirement: &2153476260 !ruby/object:Gem::Requirement
138
149
  none: false
139
150
  requirements:
140
151
  - - ! '>='
@@ -142,10 +153,10 @@ dependencies:
142
153
  version: '0'
143
154
  type: :development
144
155
  prerelease: false
145
- version_requirements: *2168763040
156
+ version_requirements: *2153476260
146
157
  - !ruby/object:Gem::Dependency
147
158
  name: appraisal
148
- requirement: &2168762620 !ruby/object:Gem::Requirement
159
+ requirement: &2153475840 !ruby/object:Gem::Requirement
149
160
  none: false
150
161
  requirements:
151
162
  - - ! '>='
@@ -153,7 +164,7 @@ dependencies:
153
164
  version: '0'
154
165
  type: :development
155
166
  prerelease: false
156
- version_requirements: *2168762620
167
+ version_requirements: *2153475840
157
168
  description: Several card processors and gateways support offloading the storage of
158
169
  credit card information onto their service. This offloads PCI compliance to the
159
170
  gateway rather than keeping it with each retailer. This library abstracts the interface