braintree 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/lib/braintree/configuration.rb +1 -1
- data/lib/braintree/customer.rb +19 -13
- data/lib/braintree/error_codes.rb +2 -2
- data/lib/braintree/transaction.rb +21 -3
- data/lib/braintree/transaction/status_details.rb +13 -0
- data/lib/braintree/util.rb +20 -2
- data/lib/braintree/version.rb +2 -2
- data/spec/hacks/tcp_socket.rb +18 -0
- data/spec/integration/braintree/credit_card_spec.rb +2 -2
- data/spec/integration/braintree/customer_spec.rb +46 -2
- data/spec/integration/braintree/error_codes_spec.rb +16 -0
- data/spec/integration/braintree/transaction_spec.rb +305 -13
- data/spec/integration/spec_helper.rb +34 -28
- data/spec/spec_helper.rb +0 -3
- data/spec/unit/braintree/transaction_spec.rb +18 -0
- data/spec/unit/braintree/util_spec.rb +38 -1
- metadata +5 -2
data/LICENSE
CHANGED
data/lib/braintree/customer.rb
CHANGED
@@ -3,7 +3,7 @@ module Braintree
|
|
3
3
|
include BaseModule
|
4
4
|
|
5
5
|
attr_reader :addresses, :company, :created_at, :credit_cards, :email, :fax, :first_name, :id, :last_name,
|
6
|
-
:phone, :updated_at, :website
|
6
|
+
:phone, :updated_at, :website, :custom_fields
|
7
7
|
|
8
8
|
# Returns a PagedCollection of all customers stored in the vault. Due to race conditions, this method
|
9
9
|
# may not reliably return all customers stored in the vault.
|
@@ -92,6 +92,17 @@ module Braintree
|
|
92
92
|
def self.sale!(customer_id, transaction_attributes)
|
93
93
|
return_object_or_raise(:transaction){ sale(customer_id, transaction_attributes) }
|
94
94
|
end
|
95
|
+
|
96
|
+
# Returns a PagedCollection of transactions for the customer with the given +customer_id+.
|
97
|
+
def self.transactions(customer_id, options = {})
|
98
|
+
page_number = options[:page] || 1
|
99
|
+
response = Http.get "/customers/#{customer_id}/transactions?page=#{page_number}"
|
100
|
+
attributes = response[:credit_card_transactions]
|
101
|
+
attributes[:items] = Util.extract_attribute_as_array(attributes, :transaction).map do |transaction_attributes|
|
102
|
+
Transaction._new transaction_attributes
|
103
|
+
end
|
104
|
+
PagedCollection.new(attributes) { |page_number| Customer.transactions(customer_id, :page => page_number) }
|
105
|
+
end
|
95
106
|
|
96
107
|
def self.update(customer_id, attributes)
|
97
108
|
Util.verify_keys(_update_signature, attributes)
|
@@ -118,7 +129,7 @@ module Braintree
|
|
118
129
|
end
|
119
130
|
|
120
131
|
def credit(transaction_attributes)
|
121
|
-
Customer.credit(
|
132
|
+
Customer.credit(id, transaction_attributes)
|
122
133
|
end
|
123
134
|
|
124
135
|
def credit!(transaction_attributes)
|
@@ -140,22 +151,16 @@ module Braintree
|
|
140
151
|
end
|
141
152
|
|
142
153
|
def sale(transaction_attributes)
|
143
|
-
Customer.sale(
|
154
|
+
Customer.sale(id, transaction_attributes)
|
144
155
|
end
|
145
156
|
|
146
157
|
def sale!(transaction_attributes)
|
147
158
|
return_object_or_raise(:transaction) { sale(transaction_attributes) }
|
148
159
|
end
|
149
160
|
|
150
|
-
#
|
161
|
+
# Returns a PagedCollection of transactions for the customer.
|
151
162
|
def transactions(options = {})
|
152
|
-
|
153
|
-
response = Http.get "/customers/#{id}/transactions?page=#{page_number}"
|
154
|
-
attributes = response[:credit_card_transactions]
|
155
|
-
attributes[:items] = Util.extract_attribute_as_array(attributes, :transaction).map do |transaction_attributes|
|
156
|
-
Transaction._new transaction_attributes
|
157
|
-
end
|
158
|
-
PagedCollection.new(attributes) { |page_number| self.transactions(:page => page_number) }
|
163
|
+
Customer.transactions(id, options)
|
159
164
|
end
|
160
165
|
|
161
166
|
def update(attributes)
|
@@ -194,7 +199,8 @@ module Braintree
|
|
194
199
|
credit_card_signature = CreditCard._create_signature - [:customer_id]
|
195
200
|
[
|
196
201
|
:company, :email, :fax, :first_name, :id, :last_name, :phone, :website,
|
197
|
-
{:credit_card => credit_card_signature}
|
202
|
+
{:credit_card => credit_card_signature},
|
203
|
+
{:custom_fields => :_any_key_}
|
198
204
|
]
|
199
205
|
end
|
200
206
|
|
@@ -225,7 +231,7 @@ module Braintree
|
|
225
231
|
end
|
226
232
|
|
227
233
|
def self._update_signature # :nodoc:
|
228
|
-
[ :company, :email, :fax, :first_name, :id, :last_name, :phone, :website ]
|
234
|
+
[ :company, :email, :fax, :first_name, :id, :last_name, :phone, :website, {:custom_fields => :_any_key_} ]
|
229
235
|
end
|
230
236
|
end
|
231
237
|
end
|
@@ -21,6 +21,7 @@ module Braintree
|
|
21
21
|
module CreditCard
|
22
22
|
BillingAddressConflict = "91701"
|
23
23
|
BillingAddressIdIsInvalid = "91702"
|
24
|
+
CardholderNameIsTooLong = "81723"
|
24
25
|
CreditCardTypeIsNotAccepted = "81703"
|
25
26
|
CustomerIdIsRequired = "91704"
|
26
27
|
CustomerIdIsInvalid = "91705"
|
@@ -77,12 +78,11 @@ module Braintree
|
|
77
78
|
HasAlreadyBeenRefunded = "91512"
|
78
79
|
MerchantAccountNameIsInvalid = "91513"
|
79
80
|
MerchantAccountIsSuspended = "91514"
|
81
|
+
OrderIdIsTooLong = "91501"
|
80
82
|
PaymentMethodConflict = "91515"
|
81
83
|
PaymentMethodDoesNotBelongToCustomer = "91516"
|
82
84
|
PaymentMethodTokenCardTypeIsNotAccepted = "91517"
|
83
85
|
PaymentMethodTokenIsInvalid = "91518"
|
84
|
-
ProcessorAuthorizationCodeCannotBeSet = "91519"
|
85
|
-
ProcessorAuthorizationCodeIsInvalid = "81520"
|
86
86
|
RefundAmountIsTooLarge = "91521"
|
87
87
|
SettlementAmountIsTooLarge = "91522"
|
88
88
|
TypeIsInvalid = "91523"
|
@@ -55,6 +55,9 @@ module Braintree
|
|
55
55
|
# :region => "IL",
|
56
56
|
# :postal_code => "60103",
|
57
57
|
# :country_name => "United States of America"
|
58
|
+
# },
|
59
|
+
# :custom_fields => {
|
60
|
+
# :birthdate => "11/13/1954"
|
58
61
|
# }
|
59
62
|
# )
|
60
63
|
#
|
@@ -64,7 +67,7 @@ module Braintree
|
|
64
67
|
# a transaction can be stored in the vault by setting
|
65
68
|
# <tt>transaction[options][store_in_vault]</tt> to true.
|
66
69
|
#
|
67
|
-
# transaction = Braintree::Transaction.
|
70
|
+
# transaction = Braintree::Transaction.sale!(
|
68
71
|
# :customer => {
|
69
72
|
# :first_name => "Adam",
|
70
73
|
# :last_name => "Williams"
|
@@ -82,6 +85,17 @@ module Braintree
|
|
82
85
|
# transaction.credit_card_details.token
|
83
86
|
# # => "6b6m"
|
84
87
|
#
|
88
|
+
# To also store the billing address in the vault, pass the
|
89
|
+
# +add_billing_address_to_payment_method+ option.
|
90
|
+
#
|
91
|
+
# Braintree::Transaction.sale!(
|
92
|
+
# # ...
|
93
|
+
# :options => {
|
94
|
+
# :store_in_vault => true
|
95
|
+
# :add_billing_address_to_payment_method => true
|
96
|
+
# }
|
97
|
+
# )
|
98
|
+
#
|
85
99
|
# == Submitting for Settlement
|
86
100
|
#
|
87
101
|
# This can only be done when the transction's
|
@@ -112,8 +126,10 @@ module Braintree
|
|
112
126
|
|
113
127
|
attr_reader :avs_error_response_code, :avs_postal_code_response_code, :avs_street_address_response_code
|
114
128
|
attr_reader :amount, :created_at, :credit_card_details, :customer_details, :id, :status
|
129
|
+
attr_reader :custom_fields
|
115
130
|
attr_reader :order_id
|
116
131
|
attr_reader :billing_details, :shipping_details
|
132
|
+
attr_reader :status_history
|
117
133
|
# The response code from the processor.
|
118
134
|
attr_reader :processor_response_code
|
119
135
|
# Will either be "sale" or "credit"
|
@@ -345,7 +361,8 @@ module Braintree
|
|
345
361
|
{:customer => [:id, :company, :email, :fax, :first_name, :last_name, :phone, :website]},
|
346
362
|
{:billing => [:first_name, :last_name, :company, :country_name, :extended_address, :locality, :postal_code, :region, :street_address]},
|
347
363
|
{:shipping => [:first_name, :last_name, :company, :country_name, :extended_address, :locality, :postal_code, :region, :street_address]},
|
348
|
-
{:options => [:store_in_vault, :submit_for_settlement]}
|
364
|
+
{:options => [:store_in_vault, :submit_for_settlement, :add_billing_address_to_payment_method]},
|
365
|
+
{:custom_fields => :_any_key_}
|
349
366
|
]
|
350
367
|
end
|
351
368
|
|
@@ -355,6 +372,7 @@ module Braintree
|
|
355
372
|
@customer_details = CustomerDetails.new(@customer)
|
356
373
|
@billing_details = AddressDetails.new(@billing)
|
357
374
|
@shipping_details = AddressDetails.new(@shipping)
|
375
|
+
@status_history = attributes[:status_history] ? attributes[:status_history].map { |s| StatusDetails.new(s) } : []
|
358
376
|
end
|
359
|
-
end
|
377
|
+
end
|
360
378
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Braintree
|
2
|
+
class Transaction
|
3
|
+
class StatusDetails # :nodoc:
|
4
|
+
include BaseModule
|
5
|
+
|
6
|
+
attr_reader :amount, :status, :timestamp, :transaction_source, :user
|
7
|
+
|
8
|
+
def initialize(attributes)
|
9
|
+
set_instance_variables_from_hash attributes unless attributes.nil?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/braintree/util.rb
CHANGED
@@ -59,7 +59,9 @@ module Braintree
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def self.verify_keys(valid_keys, hash)
|
62
|
-
|
62
|
+
flattened_valid_keys = _flatten_valid_keys(valid_keys)
|
63
|
+
invalid_keys = _flatten_hash_keys(hash) - flattened_valid_keys
|
64
|
+
invalid_keys = _remove_wildcard_keys(flattened_valid_keys, invalid_keys)
|
63
65
|
if invalid_keys.any?
|
64
66
|
sorted = invalid_keys.sort_by { |k| k.to_s }.join(", ")
|
65
67
|
raise ArgumentError, "invalid keys: #{sorted}"
|
@@ -71,7 +73,12 @@ module Braintree
|
|
71
73
|
if key.is_a?(Hash)
|
72
74
|
full_key = key.keys[0]
|
73
75
|
full_key = (namespace ? "#{namespace}[#{full_key}]" : full_key)
|
74
|
-
|
76
|
+
nested_keys = key.values[0]
|
77
|
+
if nested_keys.is_a?(Array)
|
78
|
+
result += _flatten_valid_keys(nested_keys, full_key)
|
79
|
+
else
|
80
|
+
result << "#{full_key}[#{nested_keys}]"
|
81
|
+
end
|
75
82
|
else
|
76
83
|
result << (namespace ? "#{namespace}[#{key}]" : key.to_s)
|
77
84
|
end
|
@@ -90,5 +97,16 @@ module Braintree
|
|
90
97
|
result
|
91
98
|
end.sort
|
92
99
|
end
|
100
|
+
|
101
|
+
def self._remove_wildcard_keys(valid_keys, invalid_keys)
|
102
|
+
wildcard_keys = valid_keys.select { |k| k.include? "[_any_key_]" }
|
103
|
+
return invalid_keys if wildcard_keys.empty?
|
104
|
+
wildcard_keys.map! { |wk| wk.sub "[_any_key_]", "" }
|
105
|
+
invalid_keys.select do |invalid_key|
|
106
|
+
wildcard_keys.all? do |wildcard_key|
|
107
|
+
invalid_key.index(wildcard_key) != 0
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
93
111
|
end
|
94
112
|
end
|
data/lib/braintree/version.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
TCPSocket.class_eval do
|
5
|
+
def self.wait_for_service(options)
|
6
|
+
Timeout::timeout(options[:timeout] || 20) do
|
7
|
+
loop do
|
8
|
+
begin
|
9
|
+
socket = TCPSocket.new(options[:host], options[:port])
|
10
|
+
socket.close
|
11
|
+
return
|
12
|
+
rescue Errno::ECONNREFUSED
|
13
|
+
sleep 0.5
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -644,7 +644,7 @@ describe Braintree::CreditCard do
|
|
644
644
|
|
645
645
|
def create_credit_card_via_tr(regular_params, tr_params = {})
|
646
646
|
response = nil
|
647
|
-
Net::HTTP.start("localhost",
|
647
|
+
Net::HTTP.start("localhost", Braintree::Configuration.port) do |http|
|
648
648
|
request = Net::HTTP::Post.new("/" + Braintree::CreditCard.create_credit_card_url.split("/", 4)[3])
|
649
649
|
request.add_field "Content-Type", "application/x-www-form-urlencoded"
|
650
650
|
tr_data = Braintree::TransparentRedirect.create_credit_card_data({:redirect_url => "http://example.com"}.merge(tr_params))
|
@@ -660,7 +660,7 @@ describe Braintree::CreditCard do
|
|
660
660
|
|
661
661
|
def update_credit_card_via_tr(regular_params, tr_params = {})
|
662
662
|
response = nil
|
663
|
-
Net::HTTP.start("localhost",
|
663
|
+
Net::HTTP.start("localhost", Braintree::Configuration.port) do |http|
|
664
664
|
request = Net::HTTP::Post.new("/" + Braintree::CreditCard.update_credit_card_url.split("/", 4)[3])
|
665
665
|
request.add_field "Content-Type", "application/x-www-form-urlencoded"
|
666
666
|
tr_data = Braintree::TransparentRedirect.update_credit_card_data({:redirect_url => "http://example.com"}.merge(tr_params))
|
@@ -134,6 +134,18 @@ describe Braintree::Customer do
|
|
134
134
|
result.customer.addresses[0].country_name.should == "United States of America"
|
135
135
|
end
|
136
136
|
|
137
|
+
it "stores custom fields when valid" do
|
138
|
+
result = Braintree::Customer.create(
|
139
|
+
:first_name => "Bill",
|
140
|
+
:last_name => "Gates",
|
141
|
+
:custom_fields => {
|
142
|
+
:store_me => "custom value"
|
143
|
+
}
|
144
|
+
)
|
145
|
+
result.success?.should == true
|
146
|
+
result.customer.custom_fields[:store_me].should == "custom value"
|
147
|
+
end
|
148
|
+
|
137
149
|
it "returns nested errors if credit card and/or billing address are invalid" do
|
138
150
|
result = Braintree::Customer.create(
|
139
151
|
:email => "invalid",
|
@@ -149,6 +161,18 @@ describe Braintree::Customer do
|
|
149
161
|
result.errors.for(:customer).for(:credit_card).on(:number)[0].message.should == "Credit card number is invalid."
|
150
162
|
result.errors.for(:customer).for(:credit_card).for(:billing_address).on(:country_name)[0].message.should == "Country name is not an accepted country."
|
151
163
|
end
|
164
|
+
|
165
|
+
it "returns errors if custom_fields are not registered" do
|
166
|
+
result = Braintree::Customer.create(
|
167
|
+
:first_name => "Jack",
|
168
|
+
:last_name => "Kennedy",
|
169
|
+
:custom_fields => {
|
170
|
+
:spouse_name => "Jacqueline"
|
171
|
+
}
|
172
|
+
)
|
173
|
+
result.success?.should == false
|
174
|
+
result.errors.for(:customer).on(:custom_fields)[0].message.should == "Custom field is invalid: spouse_name."
|
175
|
+
end
|
152
176
|
end
|
153
177
|
|
154
178
|
describe "self.create!" do
|
@@ -252,6 +276,22 @@ describe Braintree::Customer do
|
|
252
276
|
end
|
253
277
|
end
|
254
278
|
|
279
|
+
describe "self.transactions" do
|
280
|
+
it "finds transactions for the given customer id" do
|
281
|
+
customer = Braintree::Customer.create!(
|
282
|
+
:credit_card => {
|
283
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
284
|
+
:expiration_date => "05/2010"
|
285
|
+
}
|
286
|
+
)
|
287
|
+
transaction = customer.sale!(:amount => "100.00")
|
288
|
+
collection = Braintree::Customer.transactions(customer.id)
|
289
|
+
collection.current_page_number.should == 1
|
290
|
+
collection.total_items.should == 1
|
291
|
+
collection[0].should == transaction
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
255
295
|
|
256
296
|
describe "sale" do
|
257
297
|
it "creates a sale transaction using the customer, returning a result object" do
|
@@ -453,14 +493,18 @@ describe Braintree::Customer do
|
|
453
493
|
result = Braintree::Customer.update(
|
454
494
|
customer.id,
|
455
495
|
:first_name => "Mr. Joe",
|
456
|
-
:last_name => "Super Cool"
|
496
|
+
:last_name => "Super Cool",
|
497
|
+
:custom_fields => {
|
498
|
+
:store_me => "a value"
|
499
|
+
}
|
457
500
|
)
|
458
501
|
result.success?.should == true
|
459
502
|
result.customer.id.should == customer.id
|
460
503
|
result.customer.first_name.should == "Mr. Joe"
|
461
504
|
result.customer.last_name.should == "Super Cool"
|
505
|
+
result.customer.custom_fields[:store_me].should == "a value"
|
462
506
|
end
|
463
|
-
|
507
|
+
|
464
508
|
it "returns an error response if invalid" do
|
465
509
|
customer = Braintree::Customer.create!(:email => "valid@email.com")
|
466
510
|
result = Braintree::Customer.update(
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../spec_helper"
|
2
|
+
|
3
|
+
describe Braintree::ErrorCodes do
|
4
|
+
describe Braintree::ErrorCodes::CreditCard do
|
5
|
+
it "returns CardholderNameIsTooLong when cardholder name is too long" do
|
6
|
+
result = Braintree::Customer.create(
|
7
|
+
:credit_card => {
|
8
|
+
:cardholder_name => "x" * 256
|
9
|
+
}
|
10
|
+
)
|
11
|
+
result.success?.should == false
|
12
|
+
result.errors.for(:customer).for(:credit_card).map { |e| e.code }.should \
|
13
|
+
include(Braintree::ErrorCodes::CreditCard::CardholderNameIsTooLong)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -20,7 +20,39 @@ describe Braintree::Transaction do
|
|
20
20
|
result.transaction.credit_card_details.expiration_date.should == "05/2009"
|
21
21
|
end
|
22
22
|
|
23
|
-
it "
|
23
|
+
it "can create custom fields" do
|
24
|
+
result = Braintree::Transaction.create(
|
25
|
+
:type => "sale",
|
26
|
+
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
27
|
+
:credit_card => {
|
28
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
29
|
+
:expiration_date => "05/2009"
|
30
|
+
},
|
31
|
+
:custom_fields => {
|
32
|
+
:store_me => "custom value"
|
33
|
+
}
|
34
|
+
)
|
35
|
+
result.success?.should == true
|
36
|
+
result.transaction.custom_fields.should == {:store_me => "custom value"}
|
37
|
+
end
|
38
|
+
|
39
|
+
it "returns an error if custom_field is not registered" do
|
40
|
+
result = Braintree::Transaction.create(
|
41
|
+
:type => "sale",
|
42
|
+
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
43
|
+
:credit_card => {
|
44
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
45
|
+
:expiration_date => "05/2009"
|
46
|
+
},
|
47
|
+
:custom_fields => {
|
48
|
+
:invalid_key => "custom value"
|
49
|
+
}
|
50
|
+
)
|
51
|
+
result.success?.should == false
|
52
|
+
result.errors.for(:transaction).on(:custom_fields)[0].message.should == "Custom field is invalid: invalid_key."
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns the given params if validations fail" do
|
24
56
|
params = {
|
25
57
|
:transaction => {
|
26
58
|
:type => "sale",
|
@@ -34,7 +66,94 @@ describe Braintree::Transaction do
|
|
34
66
|
result = Braintree::Transaction.create(params[:transaction])
|
35
67
|
result.success?.should == false
|
36
68
|
result.params.should == {:transaction => {:type => 'sale', :amount => nil, :credit_card => {:expiration_date => "05/2009"}}}
|
37
|
-
|
69
|
+
end
|
70
|
+
|
71
|
+
it "returns errors if validations fail (tests many errors at once for spec speed)" do
|
72
|
+
params = {
|
73
|
+
:transaction => {
|
74
|
+
:type => "pants",
|
75
|
+
:amount => nil,
|
76
|
+
:credit_card => {
|
77
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
78
|
+
:expiration_date => "05/2009"
|
79
|
+
},
|
80
|
+
:customer_id => "invalid",
|
81
|
+
:order_id => "too long" * 250,
|
82
|
+
:payment_method_token => "too long and doesn't belong to customer" * 250
|
83
|
+
}
|
84
|
+
}
|
85
|
+
result = Braintree::Transaction.create(params[:transaction])
|
86
|
+
result.success?.should == false
|
87
|
+
result.errors.for(:transaction).on(:base).map{|error| error.code}.should include(Braintree::ErrorCodes::Transaction::PaymentMethodConflict)
|
88
|
+
result.errors.for(:transaction).on(:base).map{|error| error.code}.should include(Braintree::ErrorCodes::Transaction::PaymentMethodDoesNotBelongToCustomer)
|
89
|
+
result.errors.for(:transaction).on(:amount)[0].code.should == Braintree::ErrorCodes::Transaction::AmountIsRequired
|
90
|
+
result.errors.for(:transaction).on(:customer_id)[0].code.should == Braintree::ErrorCodes::Transaction::CustomerIdIsInvalid
|
91
|
+
result.errors.for(:transaction).on(:order_id)[0].code.should == Braintree::ErrorCodes::Transaction::OrderIdIsTooLong
|
92
|
+
result.errors.for(:transaction).on(:payment_method_token)[0].code.should == Braintree::ErrorCodes::Transaction::PaymentMethodTokenIsInvalid
|
93
|
+
result.errors.for(:transaction).on(:type)[0].code.should == Braintree::ErrorCodes::Transaction::TypeIsInvalid
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
it "returns an error if amount is negative" do
|
98
|
+
params = {
|
99
|
+
:transaction => {
|
100
|
+
:type => "credit",
|
101
|
+
:amount => "-1"
|
102
|
+
}
|
103
|
+
}
|
104
|
+
result = Braintree::Transaction.create(params[:transaction])
|
105
|
+
result.success?.should == false
|
106
|
+
result.errors.for(:transaction).on(:amount)[0].code.should == Braintree::ErrorCodes::Transaction::AmountCannotBeNegative
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns an error if amount is invalid format" do
|
110
|
+
params = {
|
111
|
+
:transaction => {
|
112
|
+
:type => "sale",
|
113
|
+
:amount => "shorts"
|
114
|
+
}
|
115
|
+
}
|
116
|
+
result = Braintree::Transaction.create(params[:transaction])
|
117
|
+
result.success?.should == false
|
118
|
+
result.errors.for(:transaction).on(:amount)[0].code.should == Braintree::ErrorCodes::Transaction::AmountIsInvalid
|
119
|
+
end
|
120
|
+
|
121
|
+
it "returns an error if type is not given" do
|
122
|
+
params = {
|
123
|
+
:transaction => {
|
124
|
+
:type => nil
|
125
|
+
}
|
126
|
+
}
|
127
|
+
result = Braintree::Transaction.create(params[:transaction])
|
128
|
+
result.success?.should == false
|
129
|
+
result.errors.for(:transaction).on(:type)[0].code.should == Braintree::ErrorCodes::Transaction::TypeIsRequired
|
130
|
+
end
|
131
|
+
|
132
|
+
it "returns an error if no credit card is given" do
|
133
|
+
params = {
|
134
|
+
:transaction => {
|
135
|
+
}
|
136
|
+
}
|
137
|
+
result = Braintree::Transaction.create(params[:transaction])
|
138
|
+
result.success?.should == false
|
139
|
+
result.errors.for(:transaction).on(:base)[0].code.should == Braintree::ErrorCodes::Transaction::CreditCardIsRequired
|
140
|
+
end
|
141
|
+
|
142
|
+
it "returns an error if the given payment method token doesn't belong to the customer" do
|
143
|
+
customer = Braintree::Customer.create!(
|
144
|
+
:credit_card => {
|
145
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
146
|
+
:expiration_date => "05/2010"
|
147
|
+
}
|
148
|
+
)
|
149
|
+
result = Braintree::Transaction.create(
|
150
|
+
:type => "sale",
|
151
|
+
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
152
|
+
:customer_id => customer.id,
|
153
|
+
:payment_method_token => customer.credit_cards[0].token + "x"
|
154
|
+
)
|
155
|
+
result.success?.should == false
|
156
|
+
result.errors.for(:transaction).on(:base)[0].code.should == Braintree::ErrorCodes::Transaction::PaymentMethodDoesNotBelongToCustomer
|
38
157
|
end
|
39
158
|
end
|
40
159
|
|
@@ -196,6 +315,49 @@ describe Braintree::Transaction do
|
|
196
315
|
transaction.vault_credit_card.token.should == transaction.credit_card_details.token
|
197
316
|
end
|
198
317
|
|
318
|
+
it "associates a billing address with a credit card in the vault" do
|
319
|
+
result = Braintree::Transaction.sale(
|
320
|
+
:amount => "100",
|
321
|
+
:customer => {
|
322
|
+
:first_name => "Adam",
|
323
|
+
:last_name => "Williams"
|
324
|
+
},
|
325
|
+
:credit_card => {
|
326
|
+
:number => "5105105105105100",
|
327
|
+
:expiration_date => "05/2012"
|
328
|
+
},
|
329
|
+
:billing => {
|
330
|
+
:first_name => "Carl",
|
331
|
+
:last_name => "Jones",
|
332
|
+
:company => "Braintree",
|
333
|
+
:street_address => "123 E Main St",
|
334
|
+
:extended_address => "Suite 403",
|
335
|
+
:locality => "Chicago",
|
336
|
+
:region => "IL",
|
337
|
+
:postal_code => "60622",
|
338
|
+
:country_name => "United States of America"
|
339
|
+
},
|
340
|
+
:options => {
|
341
|
+
:store_in_vault => true,
|
342
|
+
:add_billing_address_to_payment_method => true,
|
343
|
+
}
|
344
|
+
)
|
345
|
+
result.success?.should == true
|
346
|
+
transaction = result.transaction
|
347
|
+
transaction.customer_details.id.should =~ /\A\d{6,7}\z/
|
348
|
+
transaction.vault_customer.id.should == transaction.customer_details.id
|
349
|
+
credit_card = Braintree::CreditCard.find(transaction.vault_credit_card.token)
|
350
|
+
credit_card.billing_address.first_name.should == "Carl"
|
351
|
+
credit_card.billing_address.last_name.should == "Jones"
|
352
|
+
credit_card.billing_address.company.should == "Braintree"
|
353
|
+
credit_card.billing_address.street_address.should == "123 E Main St"
|
354
|
+
credit_card.billing_address.extended_address.should == "Suite 403"
|
355
|
+
credit_card.billing_address.locality.should == "Chicago"
|
356
|
+
credit_card.billing_address.region.should == "IL"
|
357
|
+
credit_card.billing_address.postal_code.should == "60622"
|
358
|
+
credit_card.billing_address.country_name.should == "United States of America"
|
359
|
+
end
|
360
|
+
|
199
361
|
it "submits for settlement if given transaction[options][submit_for_settlement]" do
|
200
362
|
result = Braintree::Transaction.sale(
|
201
363
|
:amount => "100",
|
@@ -251,7 +413,7 @@ describe Braintree::Transaction do
|
|
251
413
|
result = Braintree::Transaction.sale(params[:transaction])
|
252
414
|
result.success?.should == false
|
253
415
|
result.params.should == {:transaction => {:type => 'sale', :amount => nil, :credit_card => {:expiration_date => "05/2009"}}}
|
254
|
-
result.errors.for(:transaction).on(:amount)[0].
|
416
|
+
result.errors.for(:transaction).on(:amount)[0].code.should == Braintree::ErrorCodes::Transaction::AmountIsRequired
|
255
417
|
end
|
256
418
|
end
|
257
419
|
|
@@ -314,7 +476,7 @@ describe Braintree::Transaction do
|
|
314
476
|
result.transaction.updated_at.between?(Time.now - 5, Time.now).should == true
|
315
477
|
end
|
316
478
|
|
317
|
-
it "returns an error result if
|
479
|
+
it "returns an error result if settlement is too large" do
|
318
480
|
transaction = Braintree::Transaction.sale!(
|
319
481
|
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
320
482
|
:credit_card => {
|
@@ -325,9 +487,22 @@ describe Braintree::Transaction do
|
|
325
487
|
transaction.amount.should == "1000.00"
|
326
488
|
result = Braintree::Transaction.submit_for_settlement(transaction.id, "1000.01")
|
327
489
|
result.success?.should == false
|
328
|
-
result.errors.for(:transaction).on(:amount)[0].
|
490
|
+
result.errors.for(:transaction).on(:amount)[0].code.should == Braintree::ErrorCodes::Transaction::SettlementAmountIsTooLarge
|
329
491
|
result.params[:transaction][:amount].should == "1000.01"
|
330
492
|
end
|
493
|
+
|
494
|
+
it "returns an error result if status is not authorized" do
|
495
|
+
transaction = Braintree::Transaction.sale!(
|
496
|
+
:amount => Braintree::Test::TransactionAmounts::Decline,
|
497
|
+
:credit_card => {
|
498
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
499
|
+
:expiration_date => "06/2009"
|
500
|
+
}
|
501
|
+
)
|
502
|
+
result = Braintree::Transaction.submit_for_settlement(transaction.id)
|
503
|
+
result.success?.should == false
|
504
|
+
result.errors.for(:transaction).on(:base)[0].code.should == Braintree::ErrorCodes::Transaction::CannotSubmitForSettlement
|
505
|
+
end
|
331
506
|
end
|
332
507
|
|
333
508
|
describe "self.submit_for_settlement!" do
|
@@ -390,7 +565,7 @@ describe Braintree::Transaction do
|
|
390
565
|
result = Braintree::Transaction.credit(params[:transaction])
|
391
566
|
result.success?.should == false
|
392
567
|
result.params.should == {:transaction => {:type => 'credit', :amount => nil, :credit_card => {:expiration_date => "05/2009"}}}
|
393
|
-
result.errors.for(:transaction).on(:amount)[0].
|
568
|
+
result.errors.for(:transaction).on(:amount)[0].code.should == Braintree::ErrorCodes::Transaction::AmountIsRequired
|
394
569
|
end
|
395
570
|
end
|
396
571
|
|
@@ -450,7 +625,99 @@ describe Braintree::Transaction do
|
|
450
625
|
transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
|
451
626
|
transaction.credit_card_details.expiration_date.should == "05/2009"
|
452
627
|
end
|
453
|
-
|
628
|
+
|
629
|
+
it "can put any param in tr_data" do
|
630
|
+
params = {
|
631
|
+
|
632
|
+
}
|
633
|
+
tr_data_params = {
|
634
|
+
:transaction => {
|
635
|
+
:amount => "100.00",
|
636
|
+
:order_id => "123",
|
637
|
+
:type => "sale",
|
638
|
+
:credit_card => {
|
639
|
+
:number => "5105105105105100",
|
640
|
+
:expiration_date => "05/2011",
|
641
|
+
:cvv => "123"
|
642
|
+
},
|
643
|
+
:customer => {
|
644
|
+
:first_name => "Dan",
|
645
|
+
:last_name => "Smith",
|
646
|
+
:company => "Braintree Payment Solutions",
|
647
|
+
:email => "dan@example.com",
|
648
|
+
:phone => "419-555-1234",
|
649
|
+
:fax => "419-555-1235",
|
650
|
+
:website => "http://braintreepaymentsolutions.com"
|
651
|
+
},
|
652
|
+
:billing => {
|
653
|
+
:first_name => "Carl",
|
654
|
+
:last_name => "Jones",
|
655
|
+
:company => "Braintree",
|
656
|
+
:street_address => "123 E Main St",
|
657
|
+
:extended_address => "Suite 403",
|
658
|
+
:locality => "Chicago",
|
659
|
+
:region => "IL",
|
660
|
+
:postal_code => "60622",
|
661
|
+
:country_name => "United States of America"
|
662
|
+
},
|
663
|
+
:shipping => {
|
664
|
+
:first_name => "Andrew",
|
665
|
+
:last_name => "Mason",
|
666
|
+
:company => "Braintree",
|
667
|
+
:street_address => "456 W Main St",
|
668
|
+
:extended_address => "Apt 2F",
|
669
|
+
:locality => "Bartlett",
|
670
|
+
:region => "IL",
|
671
|
+
:postal_code => "60103",
|
672
|
+
:country_name => "United States of America"
|
673
|
+
}
|
674
|
+
}
|
675
|
+
}
|
676
|
+
query_string_response = create_transaction_via_tr(params, tr_data_params)
|
677
|
+
result = Braintree::Transaction.create_from_transparent_redirect(query_string_response)
|
678
|
+
transaction = result.transaction
|
679
|
+
transaction.id.should =~ /\A\w{6}\z/
|
680
|
+
transaction.type.should == "sale"
|
681
|
+
transaction.status.should == "authorized"
|
682
|
+
transaction.amount.should == "100.00"
|
683
|
+
transaction.order_id.should == "123"
|
684
|
+
transaction.processor_response_code.should == "1000"
|
685
|
+
transaction.created_at.between?(Time.now - 5, Time.now).should == true
|
686
|
+
transaction.updated_at.between?(Time.now - 5, Time.now).should == true
|
687
|
+
transaction.credit_card_details.bin.should == "510510"
|
688
|
+
transaction.credit_card_details.last_4.should == "5100"
|
689
|
+
transaction.credit_card_details.masked_number.should == "510510******5100"
|
690
|
+
transaction.credit_card_details.card_type.should == "MasterCard"
|
691
|
+
transaction.avs_error_response_code.should == nil
|
692
|
+
transaction.avs_postal_code_response_code.should == "M"
|
693
|
+
transaction.avs_street_address_response_code.should == "M"
|
694
|
+
transaction.customer_details.first_name.should == "Dan"
|
695
|
+
transaction.customer_details.last_name.should == "Smith"
|
696
|
+
transaction.customer_details.company.should == "Braintree Payment Solutions"
|
697
|
+
transaction.customer_details.email.should == "dan@example.com"
|
698
|
+
transaction.customer_details.phone.should == "419-555-1234"
|
699
|
+
transaction.customer_details.fax.should == "419-555-1235"
|
700
|
+
transaction.customer_details.website.should == "http://braintreepaymentsolutions.com"
|
701
|
+
transaction.billing_details.first_name.should == "Carl"
|
702
|
+
transaction.billing_details.last_name.should == "Jones"
|
703
|
+
transaction.billing_details.company.should == "Braintree"
|
704
|
+
transaction.billing_details.street_address.should == "123 E Main St"
|
705
|
+
transaction.billing_details.extended_address.should == "Suite 403"
|
706
|
+
transaction.billing_details.locality.should == "Chicago"
|
707
|
+
transaction.billing_details.region.should == "IL"
|
708
|
+
transaction.billing_details.postal_code.should == "60622"
|
709
|
+
transaction.billing_details.country_name.should == "United States of America"
|
710
|
+
transaction.shipping_details.first_name.should == "Andrew"
|
711
|
+
transaction.shipping_details.last_name.should == "Mason"
|
712
|
+
transaction.shipping_details.company.should == "Braintree"
|
713
|
+
transaction.shipping_details.street_address.should == "456 W Main St"
|
714
|
+
transaction.shipping_details.extended_address.should == "Apt 2F"
|
715
|
+
transaction.shipping_details.locality.should == "Bartlett"
|
716
|
+
transaction.shipping_details.region.should == "IL"
|
717
|
+
transaction.shipping_details.postal_code.should == "60103"
|
718
|
+
transaction.shipping_details.country_name.should == "United States of America"
|
719
|
+
end
|
720
|
+
|
454
721
|
it "returns an error result if validations fail" do
|
455
722
|
params = {
|
456
723
|
:transaction => {
|
@@ -470,7 +737,7 @@ describe Braintree::Transaction do
|
|
470
737
|
result = Braintree::Transaction.create_from_transparent_redirect(query_string_response)
|
471
738
|
result.success?.should == false
|
472
739
|
result.params[:transaction].should == {:amount => "", :type => "sale", :credit_card => {:expiration_date => "05/2009"}}
|
473
|
-
result.errors.for(:transaction).on(:amount)[0].
|
740
|
+
result.errors.for(:transaction).on(:amount)[0].code.should == Braintree::ErrorCodes::Transaction::AmountIsRequired
|
474
741
|
end
|
475
742
|
end
|
476
743
|
|
@@ -522,7 +789,7 @@ describe Braintree::Transaction do
|
|
522
789
|
)
|
523
790
|
result = Braintree::Transaction.void(transaction.id)
|
524
791
|
result.success?.should == false
|
525
|
-
result.errors.for(:transaction).on(:base)[0].
|
792
|
+
result.errors.for(:transaction).on(:base)[0].code.should == Braintree::ErrorCodes::Transaction::CannotBeVoided
|
526
793
|
end
|
527
794
|
end
|
528
795
|
|
@@ -562,7 +829,16 @@ describe Braintree::Transaction do
|
|
562
829
|
result.new_transaction.type.should == "credit"
|
563
830
|
end
|
564
831
|
|
565
|
-
it "returns an error
|
832
|
+
it "returns an error if already refunded" do
|
833
|
+
transaction = find_transaction_to_refund
|
834
|
+
result = transaction.refund
|
835
|
+
result.success?.should == true
|
836
|
+
result = transaction.refund
|
837
|
+
result.success?.should == false
|
838
|
+
result.errors.for(:transaction).on(:base)[0].code.should == Braintree::ErrorCodes::Transaction::HasAlreadyBeenRefunded
|
839
|
+
end
|
840
|
+
|
841
|
+
it "returns an error result if unsettled" do
|
566
842
|
transaction = Braintree::Transaction.create!(
|
567
843
|
:type => "sale",
|
568
844
|
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
@@ -573,7 +849,7 @@ describe Braintree::Transaction do
|
|
573
849
|
)
|
574
850
|
result = transaction.refund
|
575
851
|
result.success?.should == false
|
576
|
-
result.errors.for(:transaction).on(:base)[0].
|
852
|
+
result.errors.for(:transaction).on(:base)[0].code.should == Braintree::ErrorCodes::Transaction::CannotRefundUnlessSettled
|
577
853
|
end
|
578
854
|
end
|
579
855
|
|
@@ -631,7 +907,7 @@ describe Braintree::Transaction do
|
|
631
907
|
transaction.amount.should == "1000.00"
|
632
908
|
result = transaction.submit_for_settlement("1000.01")
|
633
909
|
result.success?.should == false
|
634
|
-
result.errors.for(:transaction).on(:amount)[0].
|
910
|
+
result.errors.for(:transaction).on(:amount)[0].code.should == Braintree::ErrorCodes::Transaction::SettlementAmountIsTooLarge
|
635
911
|
result.params[:transaction][:amount].should == "1000.01"
|
636
912
|
end
|
637
913
|
end
|
@@ -762,6 +1038,22 @@ describe Braintree::Transaction do
|
|
762
1038
|
end
|
763
1039
|
end
|
764
1040
|
end
|
1041
|
+
|
1042
|
+
describe "status_history" do
|
1043
|
+
it "returns an array of StatusDetail" do
|
1044
|
+
transaction = Braintree::Transaction.sale!(
|
1045
|
+
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
1046
|
+
:credit_card => {
|
1047
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
1048
|
+
:expiration_date => "05/2009"
|
1049
|
+
}
|
1050
|
+
)
|
1051
|
+
transaction.submit_for_settlement!
|
1052
|
+
transaction.status_history.size.should == 2
|
1053
|
+
transaction.status_history[0].status.should == "authorized"
|
1054
|
+
transaction.status_history[1].status.should == "submitted_for_settlement"
|
1055
|
+
end
|
1056
|
+
end
|
765
1057
|
|
766
1058
|
describe "vault_credit_card" do
|
767
1059
|
it "returns the Braintree::CreditCard if the transaction credit card is stored in the vault" do
|
@@ -843,7 +1135,7 @@ describe Braintree::Transaction do
|
|
843
1135
|
transaction.status.should == "processor_declined"
|
844
1136
|
result = transaction.void
|
845
1137
|
result.success?.should == false
|
846
|
-
result.errors.for(:transaction).on(:base)[0].
|
1138
|
+
result.errors.for(:transaction).on(:base)[0].code.should == Braintree::ErrorCodes::Transaction::CannotBeVoided
|
847
1139
|
end
|
848
1140
|
end
|
849
1141
|
|
@@ -1,38 +1,44 @@
|
|
1
|
-
|
1
|
+
unless defined?(INTEGRATION_SPEC_HELPER_LOADED)
|
2
|
+
INTEGRATION_SPEC_HELPER_LOADED = true
|
2
3
|
|
3
|
-
require
|
4
|
-
require
|
4
|
+
require File.dirname(__FILE__) + "/../spec_helper"
|
5
|
+
require File.dirname(__FILE__) + "/../hacks/tcp_socket"
|
5
6
|
|
7
|
+
Spec::Runner.configure do |config|
|
8
|
+
CLIENT_LIB_ROOT = File.expand_path(File.dirname(__FILE__) + "/../..")
|
9
|
+
GATEWAY_ROOT = File.expand_path("#{CLIENT_LIB_ROOT}/../gateway")
|
10
|
+
GATEWAY_SERVER_PORT = 3000
|
11
|
+
GATEWAY_PID_FILE = "/tmp/gateway_server_#{Braintree::Configuration.port}.pid"
|
12
|
+
SPHINX_PID_FILE = "#{GATEWAY_ROOT}/log/searchd.integration.pid"
|
13
|
+
|
14
|
+
gateway_already_started = File.exist?(GATEWAY_PID_FILE)
|
15
|
+
sphinx_already_started = File.exist?(SPHINX_PID_FILE)
|
16
|
+
config.before(:suite) do
|
17
|
+
Dir.chdir(CLIENT_LIB_ROOT) do
|
18
|
+
system "rake start_gateway" or raise "rake start_gateway failed" unless gateway_already_started
|
19
|
+
system "rake start_sphinx" or raise "rake start_sphinx failed" unless sphinx_already_started
|
20
|
+
end
|
21
|
+
end
|
6
22
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def self.wait_for_service(options)
|
12
|
-
Timeout::timeout(options[:timeout] || 20) do
|
13
|
-
loop do
|
14
|
-
begin
|
15
|
-
socket = TCPSocket.new(options[:host], options[:port])
|
16
|
-
socket.close
|
17
|
-
return
|
18
|
-
rescue Errno::ECONNREFUSED
|
19
|
-
sleep 0.5
|
20
|
-
end
|
21
|
-
end
|
23
|
+
config.after(:suite) do
|
24
|
+
Dir.chdir(CLIENT_LIB_ROOT) do
|
25
|
+
system "rake stop_gateway" or raise "rake stop_gateway failed" unless gateway_already_started
|
26
|
+
system "rake stop_sphinx" or raise "rake stop_sphinx failed" unless sphinx_already_started
|
22
27
|
end
|
23
28
|
end
|
24
29
|
end
|
25
30
|
|
26
|
-
|
27
|
-
|
28
|
-
#puts command
|
29
|
-
`#{command} #{web_server_pid_file}`
|
30
|
-
#puts "== waiting for web server - port: #{8433}"
|
31
|
-
TCPSocket.wait_for_service :host => "127.0.0.1", :port => 8443
|
31
|
+
def start_ssl_server
|
32
|
+
web_server_pid_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "httpsd.pid"))
|
32
33
|
|
33
|
-
|
34
|
+
FileUtils.rm(web_server_pid_file) if File.exist?(web_server_pid_file)
|
35
|
+
command = File.expand_path(File.join(File.dirname(__FILE__), "..", "script", "httpsd.rb"))
|
36
|
+
`#{command} #{web_server_pid_file}`
|
37
|
+
TCPSocket.wait_for_service :host => "127.0.0.1", :port => 8443
|
34
38
|
|
35
|
-
|
36
|
-
|
37
|
-
|
39
|
+
yield
|
40
|
+
|
41
|
+
10.times { unless File.exists?(web_server_pid_file); sleep 1; end }
|
42
|
+
Process.kill "INT", File.read(web_server_pid_file).to_i
|
43
|
+
end
|
38
44
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -16,9 +16,6 @@ unless defined?(SPEC_HELPER_LOADED)
|
|
16
16
|
Braintree::Configuration.logger = Logger.new("/dev/null")
|
17
17
|
Braintree::Configuration.logger.level = Logger::INFO
|
18
18
|
|
19
|
-
Spec::Runner.configure do |config|
|
20
|
-
end
|
21
|
-
|
22
19
|
module SpecHelper
|
23
20
|
def self.stub_time_dot_now(desired_time)
|
24
21
|
Time.class_eval do
|
@@ -76,6 +76,24 @@ describe Braintree::Transaction do
|
|
76
76
|
transaction.credit_card_details.issuer_location.should == "US"
|
77
77
|
end
|
78
78
|
|
79
|
+
it "sets up history attributes in status_history" do
|
80
|
+
time = Time.utc(2010,1,14)
|
81
|
+
transaction = Braintree::Transaction._new(
|
82
|
+
:status_history => [
|
83
|
+
{ :timestamp => time, :amount => "12.00", :transaction_source => "API",
|
84
|
+
:user => "larry", :status => "authorized" },
|
85
|
+
{ :timestamp => Time.utc(2010,1,15), :amount => "12.00", :transaction_source => "API",
|
86
|
+
:user => "curly", :status => "scheduled_for_settlement"}
|
87
|
+
])
|
88
|
+
transaction.status_history.size.should == 2
|
89
|
+
transaction.status_history[0].user.should == "larry"
|
90
|
+
transaction.status_history[0].amount.should == "12.00"
|
91
|
+
transaction.status_history[0].status.should == "authorized"
|
92
|
+
transaction.status_history[0].transaction_source.should == "API"
|
93
|
+
transaction.status_history[0].timestamp.should == time
|
94
|
+
transaction.status_history[1].user.should == "curly"
|
95
|
+
end
|
96
|
+
|
79
97
|
it "handles receiving custom as an empty string" do
|
80
98
|
transaction = Braintree::Transaction._new(
|
81
99
|
:custom => "\n "
|
@@ -28,7 +28,33 @@ describe Braintree::Util do
|
|
28
28
|
)
|
29
29
|
end.to raise_error(ArgumentError, "invalid keys: nested[nested_invalid], top_level_invalid")
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
|
+
it "does not raise an exception for wildcards" do
|
33
|
+
expect do
|
34
|
+
Braintree::Util.verify_keys(
|
35
|
+
[:allowed, {:custom_fields => :_any_key_}],
|
36
|
+
:allowed => "ok",
|
37
|
+
:custom_fields => {
|
38
|
+
:custom_allowed => "ok",
|
39
|
+
:custom_allowed2 => "also ok",
|
40
|
+
}
|
41
|
+
)
|
42
|
+
end.to_not raise_error
|
43
|
+
end
|
44
|
+
|
45
|
+
it "raise an exception for wildcards at different nesting" do
|
46
|
+
expect do
|
47
|
+
Braintree::Util.verify_keys(
|
48
|
+
[:allowed, {:custom_fields => :_any_key_}],
|
49
|
+
:allowed => {
|
50
|
+
:custom_fields => {
|
51
|
+
:bad_nesting => "very bad"
|
52
|
+
}
|
53
|
+
}
|
54
|
+
)
|
55
|
+
end.to raise_error(ArgumentError, "invalid keys: allowed[custom_fields][bad_nesting]")
|
56
|
+
end
|
57
|
+
|
32
58
|
it "raises an exception if a deeply nested hash contains an invalid key" do
|
33
59
|
expect do
|
34
60
|
Braintree::Util.verify_keys(
|
@@ -65,6 +91,12 @@ describe Braintree::Util do
|
|
65
91
|
[:top_level, {:nested => [:nested_allowed, :nested_allowed2]}]
|
66
92
|
).should == ["nested[nested_allowed2]", "nested[nested_allowed]", "top_level"]
|
67
93
|
end
|
94
|
+
|
95
|
+
it "allows wildcards with the :_any_key_ symbol" do
|
96
|
+
Braintree::Util._flatten_valid_keys(
|
97
|
+
[:top_level, {:nested => :_any_key_}]
|
98
|
+
).should == ["nested[_any_key_]", "top_level"]
|
99
|
+
end
|
68
100
|
end
|
69
101
|
|
70
102
|
describe "self.extract_attribute_as_array" do
|
@@ -92,6 +124,11 @@ describe Braintree::Util do
|
|
92
124
|
hash = {:foo => {:key_one => "value_one", :key_two => "value_two"}}
|
93
125
|
Braintree::Util.hash_to_query_string(hash).should == "foo%5Bkey_one%5D=value_one&foo%5Bkey_two%5D=value_two"
|
94
126
|
end
|
127
|
+
|
128
|
+
it "works for nesting 2 levels deep" do
|
129
|
+
hash = {:foo => {:nested => {:key_one => "value_one", :key_two => "value_two"}}}
|
130
|
+
Braintree::Util.hash_to_query_string(hash).should == "foo%5Bnested%5D%5Bkey_one%5D=value_one&foo%5Bnested%5D%5Bkey_two%5D=value_two"
|
131
|
+
end
|
95
132
|
end
|
96
133
|
|
97
134
|
describe "self.parse_query_string" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: braintree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Braintree Payment Solutions
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-01-20 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- lib/braintree/transaction/address_details.rb
|
44
44
|
- lib/braintree/transaction/credit_card_details.rb
|
45
45
|
- lib/braintree/transaction/customer_details.rb
|
46
|
+
- lib/braintree/transaction/status_details.rb
|
46
47
|
- lib/braintree/transaction.rb
|
47
48
|
- lib/braintree/transparent_redirect.rb
|
48
49
|
- lib/braintree/util.rb
|
@@ -54,9 +55,11 @@ files:
|
|
54
55
|
- lib/braintree/xml/parser.rb
|
55
56
|
- lib/braintree/xml.rb
|
56
57
|
- lib/braintree.rb
|
58
|
+
- spec/hacks/tcp_socket.rb
|
57
59
|
- spec/integration/braintree/address_spec.rb
|
58
60
|
- spec/integration/braintree/credit_card_spec.rb
|
59
61
|
- spec/integration/braintree/customer_spec.rb
|
62
|
+
- spec/integration/braintree/error_codes_spec.rb
|
60
63
|
- spec/integration/braintree/http_spec.rb
|
61
64
|
- spec/integration/braintree/test/transaction_amounts_spec.rb
|
62
65
|
- spec/integration/braintree/transaction_spec.rb
|