braintree 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|