braintree 2.3.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,7 +6,8 @@ module Braintree
6
6
  include BaseModule # :nodoc:
7
7
 
8
8
  attr_reader :company, :country_name, :created_at, :customer_id, :extended_address, :first_name, :id,
9
- :last_name, :locality, :postal_code, :region, :street_address, :updated_at
9
+ :last_name, :locality, :postal_code, :region, :street_address, :updated_at,
10
+ :country_code_alpha2, :country_code_alpha3, :country_code_numeric
10
11
 
11
12
  def self.create(attributes)
12
13
  Util.verify_keys(_create_signature, attributes)
@@ -99,8 +100,7 @@ module Braintree
99
100
  end
100
101
 
101
102
  def self._create_signature # :nodoc:
102
- [:company, :country_name, :customer_id, :extended_address, :first_name,
103
- :last_name, :locality, :postal_code, :region, :street_address]
103
+ _shared_signature + [:customer_id]
104
104
  end
105
105
 
106
106
  def self._determine_customer_id(customer_or_customer_id) # :nodoc:
@@ -111,6 +111,12 @@ module Braintree
111
111
  customer_id
112
112
  end
113
113
 
114
+ def self._shared_signature # :nodoc:
115
+ [:company, :country_code_alpha2, :country_code_alpha3, :country_code_numeric,
116
+ :country_name, :extended_address, :first_name,
117
+ :last_name, :locality, :postal_code, :region, :street_address]
118
+ end
119
+
114
120
  def self._new(*args) # :nodoc:
115
121
  self.new *args
116
122
  end
@@ -66,6 +66,10 @@ module Braintree
66
66
  return_object_or_raise(:transaction) { credit(token, transaction_attributes) }
67
67
  end
68
68
 
69
+ def self.delete(token)
70
+ Http.delete("/payment_methods/#{token}")
71
+ end
72
+
69
73
  # Returns a ResourceCollection of expired credit cards.
70
74
  def self.expired(options = {})
71
75
  response = Http.post("/payment_methods/all/expired_ids")
@@ -152,7 +156,7 @@ module Braintree
152
156
  end
153
157
 
154
158
  def delete
155
- Http.delete("/payment_methods/#{token}")
159
+ CreditCard.delete(token)
156
160
  end
157
161
 
158
162
  # Returns true if this credit card is the customer's default.
@@ -261,7 +265,7 @@ module Braintree
261
265
  end
262
266
 
263
267
  def self._signature(type) # :nodoc:
264
- billing_address_params = [:company, :country_name, :extended_address, :first_name, :last_name, :locality, :postal_code, :region, :street_address]
268
+ billing_address_params = Address._shared_signature
265
269
  signature = [
266
270
  :cardholder_name, :cvv, :expiration_date, :expiration_month, :expiration_year, :number, :token,
267
271
  {:options => [:make_default, :verification_merchant_account_id, :verify_card]},
@@ -3,7 +3,8 @@ module Braintree
3
3
  include BaseModule
4
4
 
5
5
  attr_reader :avs_error_response_code, :avs_postal_code_response_code, :avs_street_address_response_code,
6
- :cvv_response_code, :merchant_account_id, :processor_response_code, :processor_response_text, :status
6
+ :cvv_response_code, :merchant_account_id, :processor_response_code, :processor_response_text, :status,
7
+ :gateway_rejection_reason
7
8
 
8
9
  def initialize(attributes) # :nodoc:
9
10
  set_instance_variables_from_hash(attributes)
@@ -14,7 +15,7 @@ module Braintree
14
15
  :status, :processor_response_code, :processor_response_text,
15
16
  :cvv_response_code, :avs_error_response_code,
16
17
  :avs_postal_code_response_code, :avs_street_address_response_code,
17
- :merchant_account_id
18
+ :merchant_account_id, :gateway_rejection_reason
18
19
  ]
19
20
  formatted_attrs = attr_order.map do |attr|
20
21
  "#{attr}: #{send(attr).inspect}"
@@ -7,8 +7,12 @@ module Braintree
7
7
  CannotBeBlank = "81801"
8
8
  CompanyIsTooLong = "81802"
9
9
  CountryNameIsNotAccepted = "91803"
10
+ CountryCodeAlpha2IsNotAccepted = "91814"
11
+ CountryCodeAlpha3IsNotAccepted = "91816"
12
+ CountryCodeNumericIsNotAccepted = "91817"
10
13
  ExtendedAddressIsTooLong = "81804"
11
14
  FirstNameIsTooLong = "81805"
15
+ InconsistentCountry = "91815"
12
16
  LastNameIsTooLong = "81806"
13
17
  LocalityIsTooLong = "81807"
14
18
  PostalCodeInvalidCharacters = "81813"
@@ -55,18 +59,19 @@ module Braintree
55
59
  CustomFieldIsInvalid = "91602"
56
60
  CustomFieldIsTooLong = "81603"
57
61
  EmailIsInvalid = "81604"
58
- EmailIsTooLong = "81605"
59
62
  EmailIsRequired = "81606"
63
+ EmailIsTooLong = "81605"
60
64
  FaxIsTooLong = "81607"
61
65
  FirstNameIsTooLong = "81608"
62
66
  IdIsInUse = "91609"
63
67
  IdIsInvaild = "91610"
64
68
  IdIsNotAllowed = "91611"
69
+ IdIsRequired = "91613"
65
70
  IdIsTooLong = "91612"
66
71
  LastNameIsTooLong = "81613"
67
72
  PhoneIsTooLong = "81614"
68
- WebsiteIsTooLong = "81615"
69
73
  WebsiteIsInvalid = "81616"
74
+ WebsiteIsTooLong = "81615"
70
75
  end
71
76
 
72
77
  module Subscription
@@ -17,11 +17,12 @@ module Braintree
17
17
  # end
18
18
  class ErrorResult
19
19
 
20
- attr_reader :credit_card_verification, :transaction, :errors, :params
20
+ attr_reader :credit_card_verification, :transaction, :errors, :params, :message
21
21
 
22
22
  def initialize(data) # :nodoc:
23
23
  @params = data[:params]
24
24
  @credit_card_verification = CreditCardVerification._new(data[:verification]) if data[:verification]
25
+ @message = data[:message]
25
26
  @transaction = Transaction._new(data[:transaction]) if data[:transaction]
26
27
  @errors = Errors.new(data[:errors])
27
28
  end
@@ -128,6 +128,13 @@ module Braintree
128
128
  Token = 'token'
129
129
  end
130
130
 
131
+ module GatewayRejectionReason
132
+ AVS = "avs"
133
+ AVS_AND_CVV = "avs_and_cvv"
134
+ CVV = "cvv"
135
+ DUPLICATE = "duplicate"
136
+ end
137
+
131
138
  module Status
132
139
  Authorizing = 'authorizing'
133
140
  Authorized = 'authorized'
@@ -137,7 +144,6 @@ module Braintree
137
144
  Settled = 'settled'
138
145
  SettlementFailed = 'settlement_failed'
139
146
  SubmittedForSettlement = 'submitted_for_settlement'
140
- Unknown = 'unknown'
141
147
  Voided = 'voided'
142
148
 
143
149
  All = constants.map { |c| const_get(c) }
@@ -159,6 +165,7 @@ module Braintree
159
165
  attr_reader :currency_iso_code
160
166
  attr_reader :custom_fields
161
167
  attr_reader :cvv_response_code
168
+ attr_reader :gateway_rejection_reason
162
169
  attr_reader :merchant_account_id
163
170
  attr_reader :order_id
164
171
  attr_reader :billing_details, :shipping_details
@@ -408,8 +415,12 @@ module Braintree
408
415
  :amount, :customer_id, :merchant_account_id, :order_id, :payment_method_token, :type,
409
416
  {:credit_card => [:token, :cardholder_name, :cvv, :expiration_date, :expiration_month, :expiration_year, :number]},
410
417
  {:customer => [:id, :company, :email, :fax, :first_name, :last_name, :phone, :website]},
411
- {:billing => [:first_name, :last_name, :company, :country_name, :extended_address, :locality, :postal_code, :region, :street_address]},
412
- {:shipping => [:first_name, :last_name, :company, :country_name, :extended_address, :locality, :postal_code, :region, :street_address]},
418
+ {
419
+ :billing => Address._shared_signature
420
+ },
421
+ {
422
+ :shipping => Address._shared_signature
423
+ },
413
424
  {:options => [:store_in_vault, :submit_for_settlement, :add_billing_address_to_payment_method, :store_shipping_address_in_vault]},
414
425
  {:custom_fields => :_any_key_}
415
426
  ]
@@ -5,7 +5,8 @@ module Braintree
5
5
 
6
6
  attr_reader :id, :first_name, :last_name, :company,
7
7
  :street_address, :extended_address, :locality, :region,
8
- :postal_code, :country_name
8
+ :postal_code, :country_code_alpha2, :country_code_alpha3,
9
+ :country_code_numeric, :country_name
9
10
 
10
11
  def initialize(attributes)
11
12
  set_instance_variables_from_hash attributes unless attributes.nil?
@@ -1,8 +1,8 @@
1
1
  module Braintree
2
2
  module Version
3
3
  Major = 2
4
- Minor = 3
5
- Tiny = 1
4
+ Minor = 4
5
+ Tiny = 0
6
6
 
7
7
  String = "#{Major}.#{Minor}.#{Tiny}"
8
8
  end
@@ -8,6 +8,7 @@ module Braintree
8
8
  "Bignum" => "integer",
9
9
  "TrueClass" => "boolean",
10
10
  "FalseClass" => "boolean",
11
+ "Date" => "datetime",
11
12
  "DateTime" => "datetime",
12
13
  "Time" => "datetime",
13
14
  }
@@ -19,7 +20,9 @@ module Braintree
19
20
 
20
21
  XML_FORMATTING = {
21
22
  "symbol" => Proc.new { |symbol| symbol.to_s },
22
- "datetime" => Proc.new { |time| time.xmlschema },
23
+ "datetime" => Proc.new do |date_or_time|
24
+ date_or_time.respond_to?(:xmlschema) ? date_or_time.xmlschema : date_or_time.to_s
25
+ end,
23
26
  "bigdecimal" => Proc.new do |bigdecimal|
24
27
  str = bigdecimal.to_s('F')
25
28
  if str =~ /\.\d$/
@@ -27,6 +27,65 @@ describe Braintree::Address do
27
27
  result.address.region.should == "Illinois"
28
28
  result.address.postal_code.should == "60622"
29
29
  result.address.country_name.should == "United States of America"
30
+ result.address.country_code_alpha2.should == "US"
31
+ result.address.country_code_alpha3.should == "USA"
32
+ result.address.country_code_numeric.should == "840"
33
+ end
34
+
35
+ it "accepts country_codes" do
36
+ customer = Braintree::Customer.create!
37
+ result = Braintree::Address.create(
38
+ :customer_id => customer.id,
39
+ :country_code_alpha2 => "AS",
40
+ :country_code_alpha3 => "ASM",
41
+ :country_code_numeric => "16"
42
+ )
43
+ result.success?.should == true
44
+ result.address.country_name.should == "American Samoa"
45
+ result.address.country_code_alpha2.should == "AS"
46
+ result.address.country_code_alpha3.should == "ASM"
47
+ result.address.country_code_numeric.should == "016"
48
+ end
49
+
50
+ it "returns an error response given inconsistent country codes" do
51
+ customer = Braintree::Customer.create!
52
+ result = Braintree::Address.create(
53
+ :customer_id => customer.id,
54
+ :country_code_alpha2 => "AS",
55
+ :country_code_alpha3 => "USA"
56
+ )
57
+ result.success?.should == false
58
+ result.errors.for(:address).on(:base).map {|e| e.code}.should include(Braintree::ErrorCodes::Address::InconsistentCountry)
59
+ end
60
+
61
+ it "returns an error response given an invalid country_code_alpha2" do
62
+ customer = Braintree::Customer.create!
63
+ result = Braintree::Address.create(
64
+ :customer_id => customer.id,
65
+ :country_code_alpha2 => "zz"
66
+ )
67
+ result.success?.should == false
68
+ result.errors.for(:address).on(:country_code_alpha2).map {|e| e.code}.should include(Braintree::ErrorCodes::Address::CountryCodeAlpha2IsNotAccepted)
69
+ end
70
+
71
+ it "returns an error response given an invalid country_code_alpha3" do
72
+ customer = Braintree::Customer.create!
73
+ result = Braintree::Address.create(
74
+ :customer_id => customer.id,
75
+ :country_code_alpha3 => "zzz"
76
+ )
77
+ result.success?.should == false
78
+ result.errors.for(:address).on(:country_code_alpha3).map {|e| e.code}.should include(Braintree::ErrorCodes::Address::CountryCodeAlpha3IsNotAccepted)
79
+ end
80
+
81
+ it "returns an error response given an invalid country_code_numeric" do
82
+ customer = Braintree::Customer.create!
83
+ result = Braintree::Address.create(
84
+ :customer_id => customer.id,
85
+ :country_code_numeric => "zz"
86
+ )
87
+ result.success?.should == false
88
+ result.errors.for(:address).on(:country_code_numeric).map {|e| e.code}.should include(Braintree::ErrorCodes::Address::CountryCodeNumericIsNotAccepted)
30
89
  end
31
90
 
32
91
  it "returns an error response if invalid" do
@@ -175,6 +234,28 @@ describe Braintree::Address do
175
234
  result.address.region.should == "Illinois"
176
235
  result.address.postal_code.should == "60621"
177
236
  result.address.country_name.should == "United States of America"
237
+ result.address.country_code_alpha2.should == "US"
238
+ result.address.country_code_alpha3.should == "USA"
239
+ result.address.country_code_numeric.should == "840"
240
+ end
241
+
242
+ it "accepts country_codes" do
243
+ customer = Braintree::Customer.create!(:last_name => "Miller")
244
+ address = Braintree::Address.create!(
245
+ :customer_id => customer.id,
246
+ :country_name => "Angola"
247
+ )
248
+ result = Braintree::Address.update(
249
+ customer.id,
250
+ address.id,
251
+ :country_name => "Azerbaijan"
252
+ )
253
+
254
+ result.success?.should == true
255
+ result.address.country_name.should == "Azerbaijan"
256
+ result.address.country_code_alpha2.should == "AZ"
257
+ result.address.country_code_alpha3.should == "AZE"
258
+ result.address.country_code_numeric.should == "031"
178
259
  end
179
260
 
180
261
  it "returns an error response if invalid" do
@@ -1,7 +1,6 @@
1
1
  require File.dirname(__FILE__) + "/../spec_helper"
2
2
 
3
3
  describe Braintree::CreditCard do
4
-
5
4
  describe "self.create" do
6
5
  it "throws and ArgumentError if given exipiration_date and any combination of expiration_month and expiration_year" do
7
6
  expect do
@@ -76,6 +75,33 @@ describe Braintree::CreditCard do
76
75
  result.credit_card_verification.avs_street_address_response_code.should == "I"
77
76
  end
78
77
 
78
+ it "exposes the gateway rejection reason on verification" do
79
+ old_merchant = Braintree::Configuration.merchant_id
80
+ old_public_key = Braintree::Configuration.public_key
81
+ old_private_key = Braintree::Configuration.private_key
82
+
83
+ begin
84
+ Braintree::Configuration.merchant_id = "processing_rules_merchant_id"
85
+ Braintree::Configuration.public_key = "processing_rules_public_key"
86
+ Braintree::Configuration.private_key = "processing_rules_private_key"
87
+
88
+ customer = Braintree::Customer.create!
89
+ result = Braintree::CreditCard.create(
90
+ :customer_id => customer.id,
91
+ :number => Braintree::Test::CreditCardNumbers::Visa,
92
+ :expiration_date => "05/2009",
93
+ :cvv => "200",
94
+ :options => {:verify_card => true}
95
+ )
96
+ result.success?.should == false
97
+ result.credit_card_verification.gateway_rejection_reason.should == Braintree::Transaction::GatewayRejectionReason::CVV
98
+ ensure
99
+ Braintree::Configuration.merchant_id = old_merchant
100
+ Braintree::Configuration.public_key = old_public_key
101
+ Braintree::Configuration.private_key = old_private_key
102
+ end
103
+ end
104
+
79
105
  it "allows user to specify merchant account for verification" do
80
106
  customer = Braintree::Customer.create!
81
107
  result = Braintree::CreditCard.create(
@@ -121,6 +147,42 @@ describe Braintree::CreditCard do
121
147
  credit_card.billing_address.street_address.should == "123 Abc Way"
122
148
  end
123
149
 
150
+ it "adds credit card with billing using country_code" do
151
+ customer = Braintree::Customer.create!
152
+ result = Braintree::CreditCard.create(
153
+ :customer_id => customer.id,
154
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
155
+ :expiration_date => "12/2009",
156
+ :billing_address => {
157
+ :country_name => "United States of America",
158
+ :country_code_alpha2 => "US",
159
+ :country_code_alpha3 => "USA",
160
+ :country_code_numeric => "840"
161
+ }
162
+ )
163
+ result.success?.should == true
164
+ credit_card = result.credit_card
165
+ credit_card.billing_address.country_name.should == "United States of America"
166
+ credit_card.billing_address.country_code_alpha2.should == "US"
167
+ credit_card.billing_address.country_code_alpha3.should == "USA"
168
+ credit_card.billing_address.country_code_numeric.should == "840"
169
+ end
170
+
171
+ it "returns an error when given inconsistent country information" do
172
+ customer = Braintree::Customer.create!
173
+ result = Braintree::CreditCard.create(
174
+ :customer_id => customer.id,
175
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
176
+ :expiration_date => "12/2009",
177
+ :billing_address => {
178
+ :country_name => "Mexico",
179
+ :country_code_alpha2 => "US"
180
+ }
181
+ )
182
+ result.success?.should == false
183
+ result.errors.for(:credit_card).for(:billing_address).on(:base).map { |e| e.code }.should include(Braintree::ErrorCodes::Address::InconsistentCountry)
184
+ end
185
+
124
186
  it "returns an error response if unsuccessful" do
125
187
  customer = Braintree::Customer.create!
126
188
  result = Braintree::CreditCard.create(
@@ -386,6 +448,33 @@ describe Braintree::CreditCard do
386
448
  updated_credit_card.billing_address.street_address.should == "123 Nigeria Ave"
387
449
  updated_credit_card.billing_address.id.should == credit_card.billing_address.id
388
450
  end
451
+
452
+ it "updates the country via codes" do
453
+ customer = Braintree::Customer.create!
454
+ credit_card = Braintree::CreditCard.create!(
455
+ :customer_id => customer.id,
456
+ :number => Braintree::Test::CreditCardNumbers::Visa,
457
+ :expiration_date => "05/2012",
458
+ :billing_address => {
459
+ :street_address => "123 Nigeria Ave"
460
+ }
461
+ )
462
+ update_result = Braintree::CreditCard.update(credit_card.token,
463
+ :billing_address => {
464
+ :country_name => "American Samoa",
465
+ :country_code_alpha2 => "AS",
466
+ :country_code_alpha3 => "ASM",
467
+ :country_code_numeric => "016",
468
+ :options => {:update_existing => true}
469
+ }
470
+ )
471
+ update_result.success?.should == true
472
+ updated_credit_card = update_result.credit_card
473
+ updated_credit_card.billing_address.country_name.should == "American Samoa"
474
+ updated_credit_card.billing_address.country_code_alpha2.should == "AS"
475
+ updated_credit_card.billing_address.country_code_alpha3.should == "ASM"
476
+ updated_credit_card.billing_address.country_code_numeric.should == "016"
477
+ end
389
478
  end
390
479
 
391
480
  it "can pass expiration_month and expiration_year" do
@@ -425,6 +514,7 @@ describe Braintree::CreditCard do
425
514
  )
426
515
  update_result.success?.should == false
427
516
  update_result.credit_card_verification.status.should == Braintree::Transaction::Status::ProcessorDeclined
517
+ update_result.credit_card_verification.gateway_rejection_reason.should be_nil
428
518
  end
429
519
 
430
520
  it "can update the billing address" do
@@ -680,6 +770,24 @@ describe Braintree::CreditCard do
680
770
  end
681
771
  end
682
772
 
773
+ describe "self.delete" do
774
+ it "deletes the credit card" do
775
+ customer = Braintree::Customer.create.customer
776
+ result = Braintree::CreditCard.create(
777
+ :customer_id => customer.id,
778
+ :number => Braintree::Test::CreditCardNumbers::Visa,
779
+ :expiration_date => "05/2012"
780
+ )
781
+
782
+ result.success?.should == true
783
+ credit_card = result.credit_card
784
+ Braintree::CreditCard.delete(credit_card.token).should == true
785
+ expect do
786
+ Braintree::CreditCard.find(credit_card.token)
787
+ end.to raise_error(Braintree::NotFoundError)
788
+ end
789
+ end
790
+
683
791
  describe "delete" do
684
792
  it "deletes the credit card" do
685
793
  customer = Braintree::Customer.create.customer
@@ -159,6 +159,28 @@ describe Braintree::Customer do
159
159
  result.customer.addresses[0].country_name.should == "United States of America"
160
160
  end
161
161
 
162
+ it "can use any country code" do
163
+ result = Braintree::Customer.create(
164
+ :first_name => "James",
165
+ :last_name => "Conroy",
166
+ :credit_card => {
167
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
168
+ :expiration_date => "05/2010",
169
+ :billing_address => {
170
+ :country_name => "Comoros",
171
+ :country_code_alpha2 => "KM",
172
+ :country_code_alpha3 => "COM",
173
+ :country_code_numeric => "174"
174
+ }
175
+ }
176
+ )
177
+ result.success?.should == true
178
+ result.customer.addresses[0].country_name.should == "Comoros"
179
+ result.customer.addresses[0].country_code_alpha2.should == "KM"
180
+ result.customer.addresses[0].country_code_alpha3.should == "COM"
181
+ result.customer.addresses[0].country_code_numeric.should == "174"
182
+ end
183
+
162
184
  it "stores custom fields when valid" do
163
185
  result = Braintree::Customer.create(
164
186
  :first_name => "Bill",
@@ -187,6 +209,72 @@ describe Braintree::Customer do
187
209
  result.errors.for(:customer).for(:credit_card).for(:billing_address).on(:country_name)[0].message.should == "Country name is not an accepted country."
188
210
  end
189
211
 
212
+ it "returns errors if country codes are inconsistent" do
213
+ result = Braintree::Customer.create(
214
+ :first_name => "Olivia",
215
+ :last_name => "Dupree",
216
+ :credit_card => {
217
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
218
+ :expiration_date => "05/2010",
219
+ :billing_address => {
220
+ :country_name => "Comoros",
221
+ :country_code_alpha2 => "US",
222
+ :country_code_alpha3 => "COM",
223
+ }
224
+ }
225
+ )
226
+ result.success?.should == false
227
+ result.errors.for(:customer).for(:credit_card).for(:billing_address).on(:base).map {|e| e.code}.should include(Braintree::ErrorCodes::Address::InconsistentCountry)
228
+ end
229
+
230
+ it "returns an error if country code alpha2 is invalid" do
231
+ result = Braintree::Customer.create(
232
+ :first_name => "Melissa",
233
+ :last_name => "Henderson",
234
+ :credit_card => {
235
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
236
+ :expiration_date => "05/2010",
237
+ :billing_address => {
238
+ :country_code_alpha2 => "zz",
239
+ }
240
+ }
241
+ )
242
+ result.success?.should == false
243
+ result.errors.for(:customer).for(:credit_card).for(:billing_address).on(:country_code_alpha2).map {|e| e.code}.should include(Braintree::ErrorCodes::Address::CountryCodeAlpha2IsNotAccepted)
244
+ end
245
+
246
+ it "returns an error if country code alpha3 is invalid" do
247
+ result = Braintree::Customer.create(
248
+ :first_name => "Andrew",
249
+ :last_name => "Patterson",
250
+ :credit_card => {
251
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
252
+ :expiration_date => "05/3010",
253
+ :billing_address => {
254
+ :country_code_alpha3 => "zzz",
255
+ }
256
+ }
257
+ )
258
+ result.success?.should == false
259
+ result.errors.for(:customer).for(:credit_card).for(:billing_address).on(:country_code_alpha3).map {|e| e.code}.should include(Braintree::ErrorCodes::Address::CountryCodeAlpha3IsNotAccepted)
260
+ end
261
+
262
+ it "returns an error if country code numeric is invalid" do
263
+ result = Braintree::Customer.create(
264
+ :first_name => "Steve",
265
+ :last_name => "Hamlin",
266
+ :credit_card => {
267
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
268
+ :expiration_date => "05/3010",
269
+ :billing_address => {
270
+ :country_code_numeric => "zzz",
271
+ }
272
+ }
273
+ )
274
+ result.success?.should == false
275
+ result.errors.for(:customer).for(:credit_card).for(:billing_address).on(:country_code_numeric).map {|e| e.code}.should include(Braintree::ErrorCodes::Address::CountryCodeNumericIsNotAccepted)
276
+ end
277
+
190
278
  it "returns errors if custom_fields are not registered" do
191
279
  result = Braintree::Customer.create(
192
280
  :first_name => "Jack",
@@ -571,6 +659,33 @@ describe Braintree::Customer do
571
659
  result.customer.custom_fields[:store_me].should == "a value"
572
660
  end
573
661
 
662
+ it "can use any country code" do
663
+ customer = Braintree::Customer.create!(
664
+ :first_name => "Alex",
665
+ :last_name => "Matterson"
666
+ )
667
+ result = Braintree::Customer.update(
668
+ customer.id,
669
+ :first_name => "Sammy",
670
+ :last_name => "Banderton",
671
+ :credit_card => {
672
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
673
+ :expiration_date => "05/2010",
674
+ :billing_address => {
675
+ :country_name => "Fiji",
676
+ :country_code_alpha2 => "FJ",
677
+ :country_code_alpha3 => "FJI",
678
+ :country_code_numeric => "242"
679
+ }
680
+ }
681
+ )
682
+ result.success?.should == true
683
+ result.customer.addresses[0].country_name.should == "Fiji"
684
+ result.customer.addresses[0].country_code_alpha2.should == "FJ"
685
+ result.customer.addresses[0].country_code_alpha3.should == "FJI"
686
+ result.customer.addresses[0].country_code_numeric.should == "242"
687
+ end
688
+
574
689
  it "can update the customer, credit card, and billing address in one request" do
575
690
  customer = Braintree::Customer.create!(
576
691
  :first_name => "Joe",
@@ -131,6 +131,17 @@ describe Braintree::Subscription do
131
131
  result.subscription.trial_period.should == false
132
132
  end
133
133
 
134
+ it "doesn't create a transaction if there's a trial period" do
135
+ result = Braintree::Subscription.create(
136
+ :payment_method_token => @credit_card.token,
137
+ :plan_id => TrialPlan[:id]
138
+ )
139
+
140
+ result.subscription.transactions.size.should == 0
141
+ end
142
+ end
143
+
144
+ context "no trial period" do
134
145
  it "creates a transaction if no trial period" do
135
146
  result = Braintree::Subscription.create(
136
147
  :payment_method_token => @credit_card.token,
@@ -144,13 +155,16 @@ describe Braintree::Subscription do
144
155
  result.subscription.transactions.first.subscription_id.should == result.subscription.id
145
156
  end
146
157
 
147
- it "doesn't create a transaction if there's a trial period" do
158
+ it "does not create the subscription and returns the transaction if the transaction is not successful" do
148
159
  result = Braintree::Subscription.create(
149
160
  :payment_method_token => @credit_card.token,
150
- :plan_id => TrialPlan[:id]
161
+ :plan_id => TriallessPlan[:id],
162
+ :price => Braintree::Test::TransactionAmounts::Decline
151
163
  )
152
164
 
153
- result.subscription.transactions.size.should == 0
165
+ result.success?.should be_false
166
+ result.transaction.status.should == Braintree::Transaction::Status::ProcessorDeclined
167
+ result.message.should == "Do Not Honor"
154
168
  end
155
169
  end
156
170
 
@@ -227,7 +241,6 @@ describe Braintree::Subscription do
227
241
  result.success?.should == false
228
242
  result.errors.for(:subscription).on(:trial_duration_unit)[0].message.should == "Trial Duration Unit is invalid."
229
243
  end
230
-
231
244
  end
232
245
  end
233
246
 
@@ -508,103 +508,126 @@ describe Braintree::Transaction, "search" do
508
508
  end
509
509
  end
510
510
 
511
- it "searches on created_at in UTC" do
512
- transaction = Braintree::Transaction.sale!(
513
- :amount => Braintree::Test::TransactionAmounts::Authorize,
514
- :credit_card => {
515
- :number => Braintree::Test::CreditCardNumbers::Visa,
516
- :expiration_date => "05/12"
517
- }
518
- )
511
+ context "created_at" do
512
+ it "searches on created_at in UTC" do
513
+ transaction = Braintree::Transaction.sale!(
514
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
515
+ :credit_card => {
516
+ :number => Braintree::Test::CreditCardNumbers::Visa,
517
+ :expiration_date => "05/12"
518
+ }
519
+ )
519
520
 
520
- created_at = transaction.created_at
521
- created_at.should be_utc
521
+ created_at = transaction.created_at
522
+ created_at.should be_utc
522
523
 
523
- collection = Braintree::Transaction.search do |search|
524
- search.id.is transaction.id
525
- search.created_at.between(
526
- created_at - 60,
527
- created_at + 60
528
- )
529
- end
524
+ collection = Braintree::Transaction.search do |search|
525
+ search.id.is transaction.id
526
+ search.created_at.between(
527
+ created_at - 60,
528
+ created_at + 60
529
+ )
530
+ end
530
531
 
531
- collection.maximum_size.should == 1
532
- collection.first.id.should == transaction.id
532
+ collection.maximum_size.should == 1
533
+ collection.first.id.should == transaction.id
533
534
 
534
- collection = Braintree::Transaction.search do |search|
535
- search.id.is transaction.id
536
- search.created_at >= created_at - 1
537
- end
535
+ collection = Braintree::Transaction.search do |search|
536
+ search.id.is transaction.id
537
+ search.created_at >= created_at - 1
538
+ end
538
539
 
539
- collection.maximum_size.should == 1
540
- collection.first.id.should == transaction.id
540
+ collection.maximum_size.should == 1
541
+ collection.first.id.should == transaction.id
541
542
 
542
- collection = Braintree::Transaction.search do |search|
543
- search.id.is transaction.id
544
- search.created_at <= created_at + 1
545
- end
543
+ collection = Braintree::Transaction.search do |search|
544
+ search.id.is transaction.id
545
+ search.created_at <= created_at + 1
546
+ end
546
547
 
547
- collection.maximum_size.should == 1
548
- collection.first.id.should == transaction.id
548
+ collection.maximum_size.should == 1
549
+ collection.first.id.should == transaction.id
549
550
 
550
- collection = Braintree::Transaction.search do |search|
551
- search.id.is transaction.id
552
- search.created_at.between(
553
- created_at - 300,
554
- created_at - 100
555
- )
551
+ collection = Braintree::Transaction.search do |search|
552
+ search.id.is transaction.id
553
+ search.created_at.between(
554
+ created_at - 300,
555
+ created_at - 100
556
+ )
557
+ end
558
+
559
+ collection.maximum_size.should == 0
556
560
  end
557
561
 
558
- collection.maximum_size.should == 0
559
- end
562
+ it "searches on created_at in local time" do
563
+ transaction = Braintree::Transaction.sale!(
564
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
565
+ :credit_card => {
566
+ :number => Braintree::Test::CreditCardNumbers::Visa,
567
+ :expiration_date => "05/12"
568
+ }
569
+ )
560
570
 
561
- it "searches on created_at in local time" do
562
- transaction = Braintree::Transaction.sale!(
563
- :amount => Braintree::Test::TransactionAmounts::Authorize,
564
- :credit_card => {
565
- :number => Braintree::Test::CreditCardNumbers::Visa,
566
- :expiration_date => "05/12"
567
- }
568
- )
571
+ now = Time.now
569
572
 
570
- now = Time.now
573
+ collection = Braintree::Transaction.search do |search|
574
+ search.id.is transaction.id
575
+ search.created_at.between(
576
+ now - 60,
577
+ now + 60
578
+ )
579
+ end
571
580
 
572
- collection = Braintree::Transaction.search do |search|
573
- search.id.is transaction.id
574
- search.created_at.between(
575
- now - 60,
576
- now + 60
577
- )
578
- end
581
+ collection.maximum_size.should == 1
582
+ collection.first.id.should == transaction.id
579
583
 
580
- collection.maximum_size.should == 1
581
- collection.first.id.should == transaction.id
584
+ collection = Braintree::Transaction.search do |search|
585
+ search.id.is transaction.id
586
+ search.created_at >= now - 60
587
+ end
582
588
 
583
- collection = Braintree::Transaction.search do |search|
584
- search.id.is transaction.id
585
- search.created_at >= now - 60
586
- end
589
+ collection.maximum_size.should == 1
590
+ collection.first.id.should == transaction.id
587
591
 
588
- collection.maximum_size.should == 1
589
- collection.first.id.should == transaction.id
592
+ collection = Braintree::Transaction.search do |search|
593
+ search.id.is transaction.id
594
+ search.created_at <= now + 60
595
+ end
590
596
 
591
- collection = Braintree::Transaction.search do |search|
592
- search.id.is transaction.id
593
- search.created_at <= now + 60
594
- end
597
+ collection.maximum_size.should == 1
598
+ collection.first.id.should == transaction.id
595
599
 
596
- collection.maximum_size.should == 1
597
- collection.first.id.should == transaction.id
600
+ collection = Braintree::Transaction.search do |search|
601
+ search.id.is transaction.id
602
+ search.created_at.between(
603
+ now - 300,
604
+ now - 100
605
+ )
606
+ end
598
607
 
599
- collection = Braintree::Transaction.search do |search|
600
- search.id.is transaction.id
601
- search.created_at.between(
602
- now - 300,
603
- now - 100
604
- )
608
+ collection.maximum_size.should == 0
605
609
  end
606
610
 
607
- collection.maximum_size.should == 0
611
+ it "searches on created_at with dates" do
612
+ transaction = Braintree::Transaction.sale!(
613
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
614
+ :credit_card => {
615
+ :number => Braintree::Test::CreditCardNumbers::Visa,
616
+ :expiration_date => "05/12"
617
+ }
618
+ )
619
+
620
+ collection = Braintree::Transaction.search do |search|
621
+ search.id.is transaction.id
622
+ search.created_at.between(
623
+ Date.today - 1,
624
+ Date.today + 1
625
+ )
626
+ end
627
+
628
+ collection.maximum_size.should == 1
629
+ collection.first.id.should == transaction.id
630
+ end
608
631
  end
609
632
  end
610
633
 
@@ -39,6 +39,207 @@ describe Braintree::Transaction do
39
39
  result.transaction.processor_response_text.should == "Do Not Honor"
40
40
  end
41
41
 
42
+ it "accepts all four country codes" do
43
+ result = Braintree::Transaction.sale(
44
+ :amount => "100",
45
+ :customer => {
46
+ :last_name => "Adama",
47
+ },
48
+ :credit_card => {
49
+ :number => "5105105105105100",
50
+ :expiration_date => "05/2012"
51
+ },
52
+ :billing => {
53
+ :country_name => "Botswana",
54
+ :country_code_alpha2 => "BW",
55
+ :country_code_alpha3 => "BWA",
56
+ :country_code_numeric => "072"
57
+ },
58
+ :shipping => {
59
+ :country_name => "Bhutan",
60
+ :country_code_alpha2 => "BT",
61
+ :country_code_alpha3 => "BTN",
62
+ :country_code_numeric => "064"
63
+ },
64
+ :options => {
65
+ :add_billing_address_to_payment_method => true,
66
+ :store_in_vault => true
67
+ }
68
+ )
69
+ result.success?.should == true
70
+ transaction = result.transaction
71
+ transaction.billing_details.country_name.should == "Botswana"
72
+ transaction.billing_details.country_code_alpha2.should == "BW"
73
+ transaction.billing_details.country_code_alpha3.should == "BWA"
74
+ transaction.billing_details.country_code_numeric.should == "072"
75
+
76
+ transaction.shipping_details.country_name.should == "Bhutan"
77
+ transaction.shipping_details.country_code_alpha2.should == "BT"
78
+ transaction.shipping_details.country_code_alpha3.should == "BTN"
79
+ transaction.shipping_details.country_code_numeric.should == "064"
80
+
81
+ transaction.vault_credit_card.billing_address.country_name.should == "Botswana"
82
+ transaction.vault_credit_card.billing_address.country_code_alpha2.should == "BW"
83
+ transaction.vault_credit_card.billing_address.country_code_alpha3.should == "BWA"
84
+ transaction.vault_credit_card.billing_address.country_code_numeric.should == "072"
85
+ end
86
+
87
+ it "returns an error if provided inconsistent country information" do
88
+ result = Braintree::Transaction.sale(
89
+ :amount => "100",
90
+ :credit_card => {
91
+ :number => "5105105105105100",
92
+ :expiration_date => "05/2012"
93
+ },
94
+ :billing => {
95
+ :country_name => "Botswana",
96
+ :country_code_alpha2 => "US",
97
+ }
98
+ )
99
+
100
+ result.success?.should == false
101
+ result.errors.for(:transaction).for(:billing).on(:base).map { |e| e.code }.should include(Braintree::ErrorCodes::Address::InconsistentCountry)
102
+ end
103
+
104
+ it "returns an error if given an incorrect alpha2 code" do
105
+ result = Braintree::Transaction.sale(
106
+ :amount => "100",
107
+ :credit_card => {
108
+ :number => "5105105105105100",
109
+ :expiration_date => "05/2012"
110
+ },
111
+ :billing => {
112
+ :country_code_alpha2 => "ZZ"
113
+ }
114
+ )
115
+
116
+ result.success?.should == false
117
+ codes = result.errors.for(:transaction).for(:billing).on(:country_code_alpha2).map { |e| e.code }
118
+ codes.should include(Braintree::ErrorCodes::Address::CountryCodeAlpha2IsNotAccepted)
119
+ end
120
+
121
+ it "returns an error if given an incorrect alpha3 code" do
122
+ result = Braintree::Transaction.sale(
123
+ :amount => "100",
124
+ :credit_card => {
125
+ :number => "5105105105105100",
126
+ :expiration_date => "05/2012"
127
+ },
128
+ :billing => {
129
+ :country_code_alpha3 => "ZZZ"
130
+ }
131
+ )
132
+
133
+ result.success?.should == false
134
+ codes = result.errors.for(:transaction).for(:billing).on(:country_code_alpha3).map { |e| e.code }
135
+ codes.should include(Braintree::ErrorCodes::Address::CountryCodeAlpha3IsNotAccepted)
136
+ end
137
+
138
+ it "returns an error if given an incorrect numeric code" do
139
+ result = Braintree::Transaction.sale(
140
+ :amount => "100",
141
+ :credit_card => {
142
+ :number => "5105105105105100",
143
+ :expiration_date => "05/2012"
144
+ },
145
+ :billing => {
146
+ :country_code_numeric => "FOO"
147
+ }
148
+ )
149
+
150
+ result.success?.should == false
151
+ codes = result.errors.for(:transaction).for(:billing).on(:country_code_numeric).map { |e| e.code }
152
+ codes.should include(Braintree::ErrorCodes::Address::CountryCodeNumericIsNotAccepted)
153
+ end
154
+
155
+ context "gateway rejection reason" do
156
+ it "exposes the cvv gateway rejection reason" do
157
+ old_merchant = Braintree::Configuration.merchant_id
158
+ old_public_key = Braintree::Configuration.public_key
159
+ old_private_key = Braintree::Configuration.private_key
160
+
161
+ begin
162
+ Braintree::Configuration.merchant_id = "processing_rules_merchant_id"
163
+ Braintree::Configuration.public_key = "processing_rules_public_key"
164
+ Braintree::Configuration.private_key = "processing_rules_private_key"
165
+
166
+ result = Braintree::Transaction.sale(
167
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
168
+ :credit_card => {
169
+ :number => Braintree::Test::CreditCardNumbers::Visa,
170
+ :expiration_date => "05/2009",
171
+ :cvv => "200"
172
+ }
173
+ )
174
+ result.success?.should == false
175
+ result.transaction.gateway_rejection_reason.should == Braintree::Transaction::GatewayRejectionReason::CVV
176
+ ensure
177
+ Braintree::Configuration.merchant_id = old_merchant
178
+ Braintree::Configuration.public_key = old_public_key
179
+ Braintree::Configuration.private_key = old_private_key
180
+ end
181
+ end
182
+
183
+ it "exposes the avs gateway rejection reason" do
184
+ old_merchant = Braintree::Configuration.merchant_id
185
+ old_public_key = Braintree::Configuration.public_key
186
+ old_private_key = Braintree::Configuration.private_key
187
+
188
+ begin
189
+ Braintree::Configuration.merchant_id = "processing_rules_merchant_id"
190
+ Braintree::Configuration.public_key = "processing_rules_public_key"
191
+ Braintree::Configuration.private_key = "processing_rules_private_key"
192
+
193
+ result = Braintree::Transaction.sale(
194
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
195
+ :billing => {
196
+ :street_address => "200 Fake Street"
197
+ },
198
+ :credit_card => {
199
+ :number => Braintree::Test::CreditCardNumbers::Visa,
200
+ :expiration_date => "05/2009"
201
+ }
202
+ )
203
+ result.success?.should == false
204
+ result.transaction.gateway_rejection_reason.should == Braintree::Transaction::GatewayRejectionReason::AVS
205
+ ensure
206
+ Braintree::Configuration.merchant_id = old_merchant
207
+ Braintree::Configuration.public_key = old_public_key
208
+ Braintree::Configuration.private_key = old_private_key
209
+ end
210
+ end
211
+
212
+ it "exposes the avs_and_cvv gateway rejection reason" do
213
+ old_merchant = Braintree::Configuration.merchant_id
214
+ old_public_key = Braintree::Configuration.public_key
215
+ old_private_key = Braintree::Configuration.private_key
216
+
217
+ begin
218
+ Braintree::Configuration.merchant_id = "processing_rules_merchant_id"
219
+ Braintree::Configuration.public_key = "processing_rules_public_key"
220
+ Braintree::Configuration.private_key = "processing_rules_private_key"
221
+
222
+ result = Braintree::Transaction.sale(
223
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
224
+ :billing => {
225
+ :postal_code => "20000"
226
+ },
227
+ :credit_card => {
228
+ :number => Braintree::Test::CreditCardNumbers::Visa,
229
+ :expiration_date => "05/2009",
230
+ :cvv => "200"
231
+ }
232
+ )
233
+ result.success?.should == false
234
+ result.transaction.gateway_rejection_reason.should == Braintree::Transaction::GatewayRejectionReason::AVS_AND_CVV
235
+ ensure
236
+ Braintree::Configuration.merchant_id = old_merchant
237
+ Braintree::Configuration.public_key = old_public_key
238
+ Braintree::Configuration.private_key = old_private_key
239
+ end
240
+ end
241
+ end
242
+
42
243
  it "accepts credit card expiration month and expiration year" do
43
244
  result = Braintree::Transaction.create(
44
245
  :type => "sale",
@@ -63,6 +264,7 @@ describe Braintree::Transaction do
63
264
  )
64
265
  result.success?.should == false
65
266
  result.errors.for(:transaction).on(:customer_id)[0].code.should == "91510"
267
+ result.message.should == "Customer ID is invalid."
66
268
  end
67
269
 
68
270
  it "can create custom fields" do
@@ -374,6 +576,9 @@ describe Braintree::Transaction do
374
576
  transaction.billing_details.region.should == "IL"
375
577
  transaction.billing_details.postal_code.should == "60622"
376
578
  transaction.billing_details.country_name.should == "United States of America"
579
+ transaction.billing_details.country_code_alpha2.should == "US"
580
+ transaction.billing_details.country_code_alpha3.should == "USA"
581
+ transaction.billing_details.country_code_numeric.should == "840"
377
582
  transaction.shipping_details.first_name.should == "Andrew"
378
583
  transaction.shipping_details.last_name.should == "Mason"
379
584
  transaction.shipping_details.company.should == "Braintree"
@@ -383,6 +588,9 @@ describe Braintree::Transaction do
383
588
  transaction.shipping_details.region.should == "IL"
384
589
  transaction.shipping_details.postal_code.should == "60103"
385
590
  transaction.shipping_details.country_name.should == "United States of America"
591
+ transaction.shipping_details.country_code_alpha2.should == "US"
592
+ transaction.shipping_details.country_code_alpha3.should == "USA"
593
+ transaction.shipping_details.country_code_numeric.should == "840"
386
594
  end
387
595
 
388
596
  it "allows merchant account to be specified" do
@@ -22,6 +22,9 @@ describe Braintree::CreditCard do
22
22
  {:options => [:make_default, :verification_merchant_account_id, :verify_card]},
23
23
  {:billing_address => [
24
24
  :company,
25
+ :country_code_alpha2,
26
+ :country_code_alpha3,
27
+ :country_code_numeric,
25
28
  :country_name,
26
29
  :extended_address,
27
30
  :first_name,
@@ -49,6 +52,9 @@ describe Braintree::CreditCard do
49
52
  {:options => [:make_default, :verification_merchant_account_id, :verify_card]},
50
53
  {:billing_address => [
51
54
  :company,
55
+ :country_code_alpha2,
56
+ :country_code_alpha3,
57
+ :country_code_numeric,
52
58
  :country_name,
53
59
  :extended_address,
54
60
  :first_name,
@@ -13,7 +13,7 @@ describe Braintree::CreditCardVerification do
13
13
  :processor_response_text => "Do Not Honor",
14
14
  :merchant_account_id => "some_id"
15
15
  )
16
- verification.inspect.should == %(#<Braintree::CreditCardVerification status: "verified", processor_response_code: "2000", processor_response_text: "Do Not Honor", cvv_response_code: "I", avs_error_response_code: "I", avs_postal_code_response_code: "I", avs_street_address_response_code: "I", merchant_account_id: "some_id">)
16
+ verification.inspect.should == %(#<Braintree::CreditCardVerification status: "verified", processor_response_code: "2000", processor_response_text: "Do Not Honor", cvv_response_code: "I", avs_error_response_code: "I", avs_postal_code_response_code: "I", avs_street_address_response_code: "I", merchant_account_id: "some_id", gateway_rejection_reason: nil>)
17
17
  end
18
18
  end
19
19
  end
@@ -70,6 +70,9 @@ describe Braintree::Customer do
70
70
  {:options => [:make_default, :verification_merchant_account_id, :verify_card]},
71
71
  {:billing_address => [
72
72
  :company,
73
+ :country_code_alpha2,
74
+ :country_code_alpha3,
75
+ :country_code_numeric,
73
76
  :country_name,
74
77
  :extended_address,
75
78
  :first_name,
@@ -112,6 +115,9 @@ describe Braintree::Customer do
112
115
  ]},
113
116
  {:billing_address => [
114
117
  :company,
118
+ :country_code_alpha2,
119
+ :country_code_alpha3,
120
+ :country_code_numeric,
115
121
  :country_name,
116
122
  :extended_address,
117
123
  :first_name,
@@ -2,25 +2,10 @@ require File.dirname(__FILE__) + "/../spec_helper"
2
2
 
3
3
  describe Braintree::ErrorResult do
4
4
  describe "initialize" do
5
- it "initializes params and errors" do
6
- errors = {
7
- :scope => {
8
- :errors => [{:code => "123", :message => "something is invalid", :attribute => "something"}]
9
- }
10
- }
11
- result = Braintree::ErrorResult.new(:params => "params", :errors => errors)
12
- result.success?.should == false
13
- result.params.should == "params"
14
- result.errors.size.should == 1
15
- result.errors.for(:scope)[0].message.should == "something is invalid"
16
- result.errors.for(:scope)[0].attribute.should == "something"
17
- result.errors.for(:scope)[0].code.should == "123"
18
- end
19
-
20
- it "ignores data other than params and errors" do
5
+ it "ignores data other than params, errors, and message" do
21
6
  # so that we can add more data into the response in the future without breaking the client lib
22
7
  expect do
23
- result = Braintree::ErrorResult.new(:params => "params", :errors => {:errors => []}, :extra => "is ignored")
8
+ result = Braintree::ErrorResult.new(:params => "params", :errors => {:errors => []}, :extra => "is ignored", :message => "foo bar")
24
9
  end.to_not raise_error
25
10
  end
26
11
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: braintree
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 2
8
- - 3
9
- - 1
10
- version: 2.3.1
8
+ - 4
9
+ - 0
10
+ version: 2.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Braintree Payment Solutions
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-24 00:00:00 -05:00
18
+ date: 2010-07-09 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency