braintree 2.25.0 → 2.26.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/lib/braintree/configuration.rb +6 -9
- data/lib/braintree/credit_card_gateway.rb +1 -1
- data/lib/braintree/gateway.rb +2 -1
- data/lib/braintree/test/credit_card.rb +2 -0
- data/lib/braintree/transaction.rb +27 -20
- data/lib/braintree/transaction_gateway.rb +7 -2
- data/lib/braintree/version.rb +1 -1
- data/lib/braintree/webhook_notification.rb +7 -3
- data/lib/braintree/webhook_testing_gateway.rb +29 -6
- data/lib/ssl/api_braintreegateway_com.ca.crt +351 -0
- data/spec/httpsd.pid +1 -1
- data/spec/integration/braintree/credit_card_spec.rb +2 -1
- data/spec/integration/braintree/customer_spec.rb +3 -2
- data/spec/integration/braintree/http_spec.rb +14 -0
- data/spec/integration/braintree/merchant_account_spec.rb +4 -2
- data/spec/integration/braintree/transaction_search_spec.rb +10 -0
- data/spec/integration/braintree/transaction_spec.rb +17 -2
- data/spec/spec_helper.rb +158 -155
- data/spec/unit/braintree/configuration_spec.rb +35 -9
- data/spec/unit/braintree/credit_card_spec.rb +2 -0
- data/spec/unit/braintree/customer_spec.rb +2 -0
- data/spec/unit/braintree/webhook_notification_spec.rb +34 -7
- metadata +109 -112
data/spec/httpsd.pid
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
4588
|
@@ -34,7 +34,8 @@ describe Braintree::CreditCard do
|
|
34
34
|
:number => Braintree::Test::CreditCardNumbers::Visa,
|
35
35
|
:expiration_date => "05/2009",
|
36
36
|
:cvv => "100",
|
37
|
-
:device_session_id => "abc123"
|
37
|
+
:device_session_id => "abc123",
|
38
|
+
:fraud_merchant_id => "7"
|
38
39
|
)
|
39
40
|
result.success?.should == true
|
40
41
|
end
|
@@ -53,13 +53,14 @@ describe Braintree::Customer do
|
|
53
53
|
result.customer.updated_at.between?(Time.now - 10, Time.now).should == true
|
54
54
|
end
|
55
55
|
|
56
|
-
it "supports creation with a device session ID" do
|
56
|
+
it "supports creation with a device session ID and (optional) fraud_merchant_id" do
|
57
57
|
result = Braintree::Customer.create(
|
58
58
|
:credit_card => {
|
59
59
|
:number => Braintree::Test::CreditCardNumbers::MasterCard,
|
60
60
|
:expiration_date => "05/2010",
|
61
61
|
:cvv => "100",
|
62
|
-
:device_session_id => "abc123"
|
62
|
+
:device_session_id => "abc123",
|
63
|
+
:fraud_merchant_id => "7"
|
63
64
|
}
|
64
65
|
)
|
65
66
|
|
@@ -113,6 +113,20 @@ describe Braintree::Http do
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
+
it "accepts the certificate on the qa server" do
|
117
|
+
begin
|
118
|
+
original_env = Braintree::Configuration.environment
|
119
|
+
Braintree::Configuration.environment = :qa
|
120
|
+
Braintree::Configuration.stub(:base_merchant_path).and_return("/")
|
121
|
+
|
122
|
+
expect do
|
123
|
+
Braintree::Configuration.instantiate.http._http_do(Net::HTTP::Get, "/login")
|
124
|
+
end.to_not raise_error
|
125
|
+
ensure
|
126
|
+
Braintree::Configuration.environment = original_env
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
116
130
|
it "accepts the certificate on the sandbox server" do
|
117
131
|
begin
|
118
132
|
original_env = Braintree::Configuration.environment
|
@@ -14,7 +14,7 @@ VALID_APPLICATION_PARAMS = {
|
|
14
14
|
},
|
15
15
|
:date_of_birth => "10/9/1980",
|
16
16
|
:ssn => "123-00-1234",
|
17
|
-
:routing_number => "
|
17
|
+
:routing_number => "121000248",
|
18
18
|
:account_number => "43759348798"
|
19
19
|
},
|
20
20
|
:tos_accepted => true,
|
@@ -54,7 +54,9 @@ describe Braintree::MerchantAccount do
|
|
54
54
|
|
55
55
|
it "requires all fields" do
|
56
56
|
result = Braintree::MerchantAccount.create(
|
57
|
-
:master_merchant_account_id => "sandbox_master_merchant_account"
|
57
|
+
:master_merchant_account_id => "sandbox_master_merchant_account",
|
58
|
+
:tos_accepted => true,
|
59
|
+
:applicant_details => {}
|
58
60
|
)
|
59
61
|
result.should_not be_success
|
60
62
|
result.errors.for(:merchant_account).for(:applicant_details).on(:first_name).first.code.should == Braintree::ErrorCodes::MerchantAccount::ApplicantDetails::FirstNameIsRequired
|
@@ -1090,5 +1090,15 @@ describe Braintree::Transaction, "search" do
|
|
1090
1090
|
collection.maximum_size.should == 0
|
1091
1091
|
end
|
1092
1092
|
end
|
1093
|
+
|
1094
|
+
context "when the search times out" do
|
1095
|
+
it "raises a Down for Maintenance Error" do
|
1096
|
+
expect {
|
1097
|
+
collection = Braintree::Transaction.search do |search|
|
1098
|
+
search.amount.is -10
|
1099
|
+
end
|
1100
|
+
}.to raise_error(Braintree::DownForMaintenanceError)
|
1101
|
+
end
|
1102
|
+
end
|
1093
1103
|
end
|
1094
1104
|
end
|
@@ -149,13 +149,14 @@ describe Braintree::Transaction do
|
|
149
149
|
result.transaction.type.should == "sale"
|
150
150
|
result.transaction.amount.should == BigDecimal.new(Braintree::Test::TransactionAmounts::Authorize)
|
151
151
|
result.transaction.processor_authorization_code.should_not be_nil
|
152
|
+
result.transaction.voice_referral_number.should be_nil
|
152
153
|
result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
|
153
154
|
result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
|
154
155
|
result.transaction.credit_card_details.expiration_date.should == "05/2009"
|
155
156
|
result.transaction.credit_card_details.customer_location.should == "US"
|
156
157
|
end
|
157
158
|
|
158
|
-
it "accepts additional security parameters
|
159
|
+
it "accepts additional security parameters: device_session_id and fraud_merchant_id" do
|
159
160
|
result = Braintree::Transaction.create(
|
160
161
|
:type => "sale",
|
161
162
|
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
@@ -163,7 +164,8 @@ describe Braintree::Transaction do
|
|
163
164
|
:number => Braintree::Test::CreditCardNumbers::Visa,
|
164
165
|
:expiration_date => "05/2009"
|
165
166
|
},
|
166
|
-
:device_session_id => "abc123"
|
167
|
+
:device_session_id => "abc123",
|
168
|
+
:fraud_merchant_id => "7"
|
167
169
|
)
|
168
170
|
|
169
171
|
result.success?.should == true
|
@@ -385,6 +387,19 @@ describe Braintree::Transaction do
|
|
385
387
|
Braintree::Configuration.private_key = old_private_key
|
386
388
|
end
|
387
389
|
end
|
390
|
+
|
391
|
+
it "exposes the fraud gateway rejection reason" do
|
392
|
+
result = Braintree::Transaction.sale(
|
393
|
+
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
394
|
+
:credit_card => {
|
395
|
+
:number => Braintree::Test::CreditCardNumbers::Fraud,
|
396
|
+
:expiration_date => "05/2017",
|
397
|
+
:cvv => "333"
|
398
|
+
}
|
399
|
+
)
|
400
|
+
result.success?.should == false
|
401
|
+
result.transaction.gateway_rejection_reason.should == Braintree::Transaction::GatewayRejectionReason::Fraud
|
402
|
+
end
|
388
403
|
end
|
389
404
|
|
390
405
|
it "accepts credit card expiration month and expiration year" do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,182 +1,185 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
Braintree::Configuration.
|
12
|
-
Braintree::Configuration.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
1
|
+
unless defined?(SPEC_HELPER_LOADED)
|
2
|
+
SPEC_HELPER_LOADED = true
|
3
|
+
project_root = File.expand_path(File.dirname(__FILE__) + "/..")
|
4
|
+
require "rubygems"
|
5
|
+
require "libxml"
|
6
|
+
|
7
|
+
braintree_lib = "#{project_root}/lib"
|
8
|
+
$LOAD_PATH << braintree_lib
|
9
|
+
require "braintree"
|
10
|
+
|
11
|
+
Braintree::Configuration.environment = :development
|
12
|
+
Braintree::Configuration.merchant_id = "integration_merchant_id"
|
13
|
+
Braintree::Configuration.public_key = "integration_public_key"
|
14
|
+
Braintree::Configuration.private_key = "integration_private_key"
|
15
|
+
logger = Logger.new("/dev/null")
|
16
|
+
logger.level = Logger::INFO
|
17
|
+
Braintree::Configuration.logger = logger
|
18
|
+
|
19
|
+
module Kernel
|
20
|
+
alias_method :original_warn, :warn
|
21
|
+
def warn(message)
|
22
|
+
return if message =~ /^\[DEPRECATED\]/
|
23
|
+
original_warn(message)
|
24
|
+
end
|
22
25
|
end
|
23
|
-
end
|
24
26
|
|
25
|
-
def now_in_eastern
|
26
|
-
|
27
|
-
end
|
27
|
+
def now_in_eastern
|
28
|
+
(Time.now.utc - 5*60*60).strftime("%Y-%m-%d")
|
29
|
+
end
|
28
30
|
|
29
|
-
module SpecHelper
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
31
|
+
module SpecHelper
|
32
|
+
|
33
|
+
DefaultMerchantAccountId = "sandbox_credit_card"
|
34
|
+
NonDefaultMerchantAccountId = "sandbox_credit_card_non_default"
|
35
|
+
NonDefaultSubMerchantAccountId = "sandbox_sub_merchant_account"
|
36
|
+
|
37
|
+
TrialPlan = {
|
38
|
+
:description => "Plan for integration tests -- with trial",
|
39
|
+
:id => "integration_trial_plan",
|
40
|
+
:price => BigDecimal.new("43.21"),
|
41
|
+
:trial_period => true,
|
42
|
+
:trial_duration => 2,
|
43
|
+
:trial_duration_unit => Braintree::Subscription::TrialDurationUnit::Day
|
44
|
+
}
|
45
|
+
|
46
|
+
TriallessPlan = {
|
47
|
+
:description => "Plan for integration tests -- without a trial",
|
48
|
+
:id => "integration_trialless_plan",
|
49
|
+
:price => BigDecimal.new("12.34"),
|
50
|
+
:trial_period => false
|
51
|
+
}
|
52
|
+
|
53
|
+
AddOnDiscountPlan = {
|
54
|
+
:description => "Plan for integration tests -- with add-ons and discounts",
|
55
|
+
:id => "integration_plan_with_add_ons_and_discounts",
|
56
|
+
:price => BigDecimal.new("9.99"),
|
57
|
+
:trial_period => true,
|
58
|
+
:trial_duration => 2,
|
59
|
+
:trial_duration_unit => Braintree::Subscription::TrialDurationUnit::Day
|
60
|
+
}
|
61
|
+
|
62
|
+
BillingDayOfMonthPlan = {
|
63
|
+
:description => "Plan for integration tests -- with billing day of month",
|
64
|
+
:id => "integration_plan_with_billing_day_of_month",
|
65
|
+
:price => BigDecimal.new("8.88"),
|
66
|
+
:billing_day_of_month => 5
|
67
|
+
}
|
68
|
+
|
69
|
+
AddOnIncrease10 = "increase_10"
|
70
|
+
AddOnIncrease20 = "increase_20"
|
71
|
+
AddOnIncrease30 = "increase_30"
|
72
|
+
|
73
|
+
Discount7 = "discount_7"
|
74
|
+
Discount11 = "discount_11"
|
75
|
+
Discount15 = "discount_15"
|
76
|
+
|
77
|
+
TestMerchantConfig = Braintree::Configuration.new(
|
78
|
+
:logger => Logger.new("/dev/null"),
|
79
|
+
:environment => :development,
|
80
|
+
:merchant_id => "test_merchant_id",
|
81
|
+
:public_key => "test_public_key",
|
82
|
+
:private_key => "test_private_key"
|
83
|
+
)
|
84
|
+
|
85
|
+
def self.make_past_due(subscription, number_of_days_past_due = 1)
|
86
|
+
Braintree::Configuration.instantiate.http.put(
|
87
|
+
"/subscriptions/#{subscription.id}/make_past_due?days_past_due=#{number_of_days_past_due}"
|
81
88
|
)
|
89
|
+
end
|
82
90
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
)
|
87
|
-
end
|
88
|
-
|
89
|
-
def self.settle_transaction(transaction_id)
|
90
|
-
Braintree::Configuration.instantiate.http.put("/transactions/#{transaction_id}/settle")
|
91
|
-
end
|
91
|
+
def self.settle_transaction(transaction_id)
|
92
|
+
Braintree::Configuration.instantiate.http.put("/transactions/#{transaction_id}/settle")
|
93
|
+
end
|
92
94
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
95
|
+
def self.stub_time_dot_now(desired_time)
|
96
|
+
Time.class_eval do
|
97
|
+
class << self
|
98
|
+
alias original_now now
|
99
|
+
end
|
97
100
|
end
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
101
|
+
(class << Time; self; end).class_eval do
|
102
|
+
define_method(:now) { desired_time }
|
103
|
+
end
|
104
|
+
yield
|
105
|
+
ensure
|
106
|
+
Time.class_eval do
|
107
|
+
class << self
|
108
|
+
alias now original_now
|
109
|
+
end
|
107
110
|
end
|
108
111
|
end
|
109
|
-
end
|
110
112
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
113
|
+
def self.simulate_form_post_for_tr(tr_data_string, form_data_hash, url = Braintree::TransparentRedirect.url)
|
114
|
+
response = nil
|
115
|
+
Net::HTTP.start("localhost", Braintree::Configuration.instantiate.port) do |http|
|
116
|
+
request = Net::HTTP::Post.new("/" + url.split("/", 4)[3])
|
117
|
+
request.add_field "Content-Type", "application/x-www-form-urlencoded"
|
118
|
+
request.body = Braintree::Util.hash_to_query_string({:tr_data => tr_data_string}.merge(form_data_hash))
|
119
|
+
response = http.request(request)
|
120
|
+
end
|
121
|
+
if response.code.to_i == 303
|
122
|
+
response["Location"].split("?", 2).last
|
123
|
+
else
|
124
|
+
raise "did not receive a valid tr response: #{response.body[0,1000].inspect}"
|
125
|
+
end
|
123
126
|
end
|
124
|
-
end
|
125
127
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
128
|
+
def self.using_configuration(config = {}, &block)
|
129
|
+
original_values = {}
|
130
|
+
[:merchant_id, :public_key, :private_key].each do |key|
|
131
|
+
if config[key]
|
132
|
+
original_values[key] = Braintree::Configuration.send(key)
|
133
|
+
Braintree::Configuration.send("#{key}=", config[key])
|
134
|
+
end
|
132
135
|
end
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
136
|
+
begin
|
137
|
+
yield
|
138
|
+
ensure
|
139
|
+
original_values.each do |key, value|
|
140
|
+
Braintree::Configuration.send("#{key}=", value)
|
141
|
+
end
|
139
142
|
end
|
140
143
|
end
|
141
144
|
end
|
142
|
-
end
|
143
145
|
|
144
|
-
module CustomMatchers
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
146
|
+
module CustomMatchers
|
147
|
+
class ParseTo
|
148
|
+
def initialize(hash)
|
149
|
+
@expected_hash = hash
|
150
|
+
end
|
149
151
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
152
|
+
def matches?(xml_string)
|
153
|
+
@libxml_parse = Braintree::Xml::Parser.hash_from_xml(xml_string, Braintree::Xml::Libxml)
|
154
|
+
@rexml_parse = Braintree::Xml::Parser.hash_from_xml(xml_string, Braintree::Xml::Rexml)
|
155
|
+
if @libxml_parse != @expected_hash
|
156
|
+
@results = @libxml_parse
|
157
|
+
@failed_parser = "libxml"
|
158
|
+
false
|
159
|
+
elsif @rexml_parse != @expected_hash
|
160
|
+
@results = @rexml_parse
|
161
|
+
@failed_parser = "rexml"
|
162
|
+
false
|
163
|
+
else
|
164
|
+
true
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def failure_message
|
169
|
+
"xml parsing failed for #{@failed_parser}, expected #{@expected_hash.inspect} but was #{@results.inspect}"
|
163
170
|
end
|
164
|
-
end
|
165
171
|
|
166
|
-
|
167
|
-
|
172
|
+
def negative_failure_message
|
173
|
+
raise NotImplementedError
|
174
|
+
end
|
168
175
|
end
|
169
176
|
|
170
|
-
def
|
171
|
-
|
177
|
+
def parse_to(hash)
|
178
|
+
ParseTo.new(hash)
|
172
179
|
end
|
173
180
|
end
|
174
181
|
|
175
|
-
|
176
|
-
|
182
|
+
Spec::Runner.configure do |config|
|
183
|
+
config.include CustomMatchers
|
177
184
|
end
|
178
185
|
end
|
179
|
-
|
180
|
-
Spec::Runner.configure do |config|
|
181
|
-
config.include CustomMatchers
|
182
|
-
end
|