braintree 4.23.0 → 4.34.0
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.
- checksums.yaml +4 -4
- data/lib/braintree/address_gateway.rb +5 -0
- data/lib/braintree/apple_pay_card.rb +6 -0
- data/lib/braintree/bank_account_instant_verification_gateway.rb +38 -0
- data/lib/braintree/bank_account_instant_verification_jwt.rb +23 -0
- data/lib/braintree/bank_account_instant_verification_jwt_request.rb +21 -0
- data/lib/braintree/bin_data.rb +8 -2
- data/lib/braintree/configuration.rb +1 -1
- data/lib/braintree/credit_card.rb +12 -5
- data/lib/braintree/credit_card_gateway.rb +1 -0
- data/lib/braintree/credit_card_verification_gateway.rb +5 -2
- data/lib/braintree/customer_session_gateway.rb +195 -0
- data/lib/braintree/dispute.rb +1 -0
- data/lib/braintree/error_codes.rb +58 -104
- data/lib/braintree/error_result.rb +1 -1
- data/lib/braintree/errors.rb +2 -1
- data/lib/braintree/gateway.rb +12 -0
- data/lib/braintree/google_pay_card.rb +5 -0
- data/lib/braintree/graphql/enums/recommendations.rb +9 -0
- data/lib/braintree/graphql/enums/recommended_payment_option.rb +10 -0
- data/lib/braintree/graphql/inputs/create_customer_session_input.rb +44 -0
- data/lib/braintree/graphql/inputs/customer_recommendations_input.rb +40 -0
- data/lib/braintree/graphql/inputs/customer_session_input.rb +45 -0
- data/lib/braintree/graphql/inputs/monetary_amount_input.rb +28 -0
- data/lib/braintree/graphql/inputs/paypal_payee_input.rb +28 -0
- data/lib/braintree/graphql/inputs/paypal_purchase_unit_input.rb +31 -0
- data/lib/braintree/graphql/inputs/phone_input.rb +34 -0
- data/lib/braintree/graphql/inputs/update_customer_session_input.rb +42 -0
- data/lib/braintree/graphql/types/customer_recommendations_payload.rb +129 -0
- data/lib/braintree/graphql/types/payment_options.rb +35 -0
- data/lib/braintree/graphql/types/payment_recommendations.rb +35 -0
- data/lib/braintree/graphql/unions/customer_recommendations.rb +47 -0
- data/lib/braintree/graphql_client.rb +16 -0
- data/lib/braintree/merchant_account.rb +1 -25
- data/lib/braintree/merchant_account_gateway.rb +0 -81
- data/lib/braintree/meta_checkout_card.rb +11 -6
- data/lib/braintree/meta_checkout_token.rb +11 -6
- data/lib/braintree/payment_method_gateway.rb +9 -0
- data/lib/braintree/paypal_payment_resource.rb +22 -0
- data/lib/braintree/paypal_payment_resource_gateway.rb +36 -0
- data/lib/braintree/successful_result.rb +3 -0
- data/lib/braintree/test/credit_card.rb +5 -0
- data/lib/braintree/transaction/apple_pay_details.rb +7 -0
- data/lib/braintree/transaction/credit_card_details.rb +22 -10
- data/lib/braintree/transaction/google_pay_details.rb +16 -10
- data/lib/braintree/transaction/meta_checkout_card_details.rb +11 -2
- data/lib/braintree/transaction/meta_checkout_token_details.rb +13 -3
- data/lib/braintree/transaction/paypal_details.rb +2 -0
- data/lib/braintree/transaction/visa_checkout_card_details.rb +10 -2
- data/lib/braintree/transaction.rb +3 -26
- data/lib/braintree/transaction_gateway.rb +52 -31
- data/lib/braintree/us_bank_account_verification.rb +3 -1
- data/lib/braintree/version.rb +1 -1
- data/lib/braintree/visa_checkout_card.rb +10 -5
- data/lib/braintree/webhook_notification.rb +1 -4
- data/lib/braintree/webhook_testing_gateway.rb +16 -33
- data/lib/braintree/xml/{libxml.rb → nokogiri.rb} +18 -16
- data/lib/braintree/xml/parser.rb +4 -4
- data/lib/braintree.rb +21 -4
- data/spec/integration/braintree/advanced_search_spec.rb +7 -4
- data/spec/integration/braintree/apple_pay_spec.rb +6 -7
- data/spec/integration/braintree/bank_account_instant_verification_spec.rb +191 -0
- data/spec/integration/braintree/client_api/spec_helper.rb +81 -0
- data/spec/integration/braintree/credit_card_spec.rb +115 -1
- data/spec/integration/braintree/credit_card_verification_spec.rb +149 -0
- data/spec/integration/braintree/customer_session_spec.rb +154 -0
- data/spec/integration/braintree/customer_spec.rb +94 -10
- data/spec/integration/braintree/disbursement_spec.rb +1 -1
- data/spec/integration/braintree/dispute_spec.rb +13 -2
- data/spec/integration/braintree/merchant_account_spec.rb +19 -359
- data/spec/integration/braintree/merchant_spec.rb +4 -4
- data/spec/integration/braintree/payment_method_nonce_spec.rb +55 -0
- data/spec/integration/braintree/payment_method_spec.rb +57 -7
- data/spec/integration/braintree/payment_method_us_bank_account_spec.rb +0 -3
- data/spec/integration/braintree/paypal_payment_resource_spec.rb +141 -0
- data/spec/integration/braintree/transaction_payment_facilitator_spec.rb +119 -0
- data/spec/integration/braintree/transaction_search_spec.rb +38 -33
- data/spec/integration/braintree/transaction_spec.rb +266 -350
- data/spec/integration/braintree/transaction_transfer_type_spec.rb +325 -0
- data/spec/integration/braintree/transaction_us_bank_account_spec.rb +0 -1
- data/spec/integration/braintree/us_bank_account_spec.rb +0 -3
- data/spec/integration/braintree/us_bank_account_verification_spec.rb +1 -1
- data/spec/spec_helper.rb +46 -12
- data/spec/unit/braintree/apple_pay_card_spec.rb +7 -0
- data/spec/unit/braintree/bank_account_instant_verification_gateway_spec.rb +98 -0
- data/spec/unit/braintree/bank_account_instant_verification_jwt_request_spec.rb +71 -0
- data/spec/unit/braintree/client_token_spec.rb +11 -0
- data/spec/unit/braintree/configuration_spec.rb +1 -1
- data/spec/unit/braintree/credit_card_spec.rb +27 -2
- data/spec/unit/braintree/credit_card_verification_gateway_spec.rb +1 -0
- data/spec/unit/braintree/credit_card_verification_spec.rb +17 -0
- data/spec/unit/braintree/customer_session_gateway_spec.rb +122 -0
- data/spec/unit/braintree/customer_spec.rb +2 -1
- data/spec/unit/braintree/dispute_spec.rb +6 -0
- data/spec/unit/braintree/error_result_spec.rb +28 -0
- data/spec/unit/braintree/google_pay_card_spec.rb +28 -0
- data/spec/unit/braintree/graphql/create_customer_session_input_spec.rb +102 -0
- data/spec/unit/braintree/graphql/customer_recommendations_input_spec.rb +80 -0
- data/spec/unit/braintree/graphql/customer_recommendations_spec.rb +40 -0
- data/spec/unit/braintree/graphql/customer_session_input_spec.rb +81 -0
- data/spec/unit/braintree/graphql/phone_input_spec.rb +51 -0
- data/spec/unit/braintree/graphql/update_customer_session_input_spec.rb +107 -0
- data/spec/unit/braintree/graphql_client_spec.rb +37 -0
- data/spec/unit/braintree/meta_checkout_card_spec.rb +61 -51
- data/spec/unit/braintree/meta_checkout_token_spec.rb +7 -1
- data/spec/unit/braintree/payment_method_nonce_spec.rb +11 -1
- data/spec/unit/braintree/payment_method_spec.rb +12 -0
- data/spec/unit/braintree/paypal_payment_resource_spec.rb +125 -0
- data/spec/unit/braintree/transaction/apple_pay_details_spec.rb +37 -0
- data/spec/unit/braintree/transaction/credit_card_details_spec.rb +15 -1
- data/spec/unit/braintree/transaction/google_pay_details_spec.rb +37 -0
- data/spec/unit/braintree/transaction/meta_checkout_card_details_spec.rb +28 -0
- data/spec/unit/braintree/transaction/meta_checkout_token_details_spec.rb +28 -0
- data/spec/unit/braintree/transaction/paypal_details_spec.rb +5 -0
- data/spec/unit/braintree/transaction/visa_checkout_card_details_spec.rb +28 -0
- data/spec/unit/braintree/transaction_ach_mandate_spec.rb +82 -0
- data/spec/unit/braintree/transaction_gateway_spec.rb +58 -11
- data/spec/unit/braintree/transaction_spec.rb +66 -0
- data/spec/unit/braintree/visa_checkout_card_spec.rb +28 -0
- data/spec/unit/braintree/webhook_notification_spec.rb +15 -51
- data/spec/unit/braintree/xml/{libxml_spec.rb → nokogiri_spec.rb} +7 -7
- data/spec/unit/braintree/xml/parser_spec.rb +57 -0
- data/spec/unit/credit_card_details_spec.rb +28 -0
- metadata +49 -10
- data/lib/braintree/merchant_account/business_details.rb +0 -17
- data/lib/braintree/merchant_account/funding_details.rb +0 -18
- data/lib/braintree/merchant_account/individual_details.rb +0 -20
- data/lib/ssl/securetrust_ca.crt +0 -44
- data/spec/unit/braintree/disbursement_spec.rb +0 -131
- data/spec/unit/braintree/merchant_account_spec.rb +0 -33
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
# under the MIT license, copyright (c) 2005-2009 David Heinemeier Hansson
|
|
3
3
|
module Braintree
|
|
4
4
|
module Xml
|
|
5
|
-
module
|
|
6
|
-
|
|
5
|
+
module Nokogiri
|
|
6
|
+
NOKOGIRI_XML_LIMIT = 30000000
|
|
7
7
|
|
|
8
8
|
def self.parse(xml_string)
|
|
9
|
-
|
|
10
|
-
::
|
|
11
|
-
|
|
12
|
-
_node_to_hash(root_node)
|
|
13
|
-
ensure
|
|
14
|
-
::LibXML::XML.default_keep_blanks = old_keep_blanks_setting
|
|
9
|
+
require "nokogiri" unless defined?(::Nokogiri)
|
|
10
|
+
doc = ::Nokogiri::XML(xml_string.strip)
|
|
11
|
+
_node_to_hash(doc.root)
|
|
15
12
|
end
|
|
16
13
|
|
|
17
14
|
def self._node_to_hash(node, hash = {})
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
sub_hash = node.text? ? hash : _build_sub_hash(hash, node.name)
|
|
16
|
+
|
|
17
|
+
if node.text? || (node.children.size == 1 && node.children.first.text?)
|
|
18
|
+
content = node.text? ? node.content : node.children.first.content
|
|
19
|
+
raise "Content too large" if content.length >= NOKOGIRI_XML_LIMIT
|
|
20
|
+
sub_hash[CONTENT_ROOT] = content
|
|
21
|
+
_attributes_to_hash(node, sub_hash) unless node.text?
|
|
21
22
|
else
|
|
22
|
-
sub_hash = _build_sub_hash(hash, node.name)
|
|
23
23
|
_attributes_to_hash(node, sub_hash)
|
|
24
24
|
if _array?(node)
|
|
25
25
|
_children_array_to_hash(node, sub_hash)
|
|
@@ -44,25 +44,27 @@ module Braintree
|
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def self._children_to_hash(node, hash={})
|
|
47
|
-
node.each { |child| _node_to_hash(child, hash) }
|
|
47
|
+
node.children.each { |child| _node_to_hash(child, hash) unless child.text? && child.content.strip.empty? }
|
|
48
48
|
_attributes_to_hash(node, hash)
|
|
49
49
|
hash
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def self._attributes_to_hash(node, hash={})
|
|
53
|
-
node.
|
|
53
|
+
node.attributes.each { |name, attr| hash[name] = attr.value }
|
|
54
54
|
hash
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def self._children_array_to_hash(node, hash={})
|
|
58
|
-
|
|
58
|
+
first_child = node.children.find { |child| !child.text? }
|
|
59
|
+
hash[first_child.name] = node.children.select { |child| !child.text? }.map do |child|
|
|
59
60
|
_children_to_hash(child, {})
|
|
60
61
|
end
|
|
61
62
|
hash
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
def self._array?(node)
|
|
65
|
-
|
|
66
|
+
non_text_children = node.children.select { |child| !child.text? }
|
|
67
|
+
non_text_children.size > 1 && non_text_children.first.name == non_text_children[1].name
|
|
66
68
|
end
|
|
67
69
|
end
|
|
68
70
|
end
|
data/lib/braintree/xml/parser.rb
CHANGED
|
@@ -18,10 +18,10 @@ module Braintree
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def self._determine_parser
|
|
21
|
-
# If
|
|
22
|
-
#
|
|
23
|
-
if defined?(::
|
|
24
|
-
::Braintree::Xml::
|
|
21
|
+
# If Nokogiri is available, use it for better performance
|
|
22
|
+
# Otherwise fall back to REXML for JRuby compatibility
|
|
23
|
+
if defined?(::Nokogiri)
|
|
24
|
+
::Braintree::Xml::Nokogiri
|
|
25
25
|
else
|
|
26
26
|
::Braintree::Xml::Rexml
|
|
27
27
|
end
|
data/lib/braintree.rb
CHANGED
|
@@ -35,6 +35,9 @@ require "braintree/apple_pay_card"
|
|
|
35
35
|
require "braintree/apple_pay_gateway"
|
|
36
36
|
require "braintree/apple_pay_options"
|
|
37
37
|
require "braintree/authorization_adjustment"
|
|
38
|
+
require "braintree/bank_account_instant_verification_gateway"
|
|
39
|
+
require "braintree/bank_account_instant_verification_jwt"
|
|
40
|
+
require "braintree/bank_account_instant_verification_jwt_request"
|
|
38
41
|
require "braintree/bin_data"
|
|
39
42
|
require "braintree/client_token"
|
|
40
43
|
require "braintree/client_token_gateway"
|
|
@@ -51,6 +54,7 @@ require "braintree/customer"
|
|
|
51
54
|
require "braintree/customer_gateway"
|
|
52
55
|
require "braintree/granted_payment_instrument_update"
|
|
53
56
|
require "braintree/customer_search"
|
|
57
|
+
require "braintree/customer_session_gateway"
|
|
54
58
|
require "braintree/descriptor"
|
|
55
59
|
require "braintree/digest"
|
|
56
60
|
require "braintree/discount"
|
|
@@ -75,6 +79,20 @@ require "braintree/exchange_rate_quote_input"
|
|
|
75
79
|
require "braintree/exchange_rate_quote_response"
|
|
76
80
|
require "braintree/exchange_rate_quote_request"
|
|
77
81
|
require "braintree/gateway"
|
|
82
|
+
require "braintree/graphql/enums/recommendations"
|
|
83
|
+
require "braintree/graphql/enums/recommended_payment_option"
|
|
84
|
+
require "braintree/graphql/inputs/create_customer_session_input"
|
|
85
|
+
require "braintree/graphql/inputs/customer_recommendations_input"
|
|
86
|
+
require "braintree/graphql/inputs/customer_session_input"
|
|
87
|
+
require "braintree/graphql/inputs/phone_input"
|
|
88
|
+
require "braintree/graphql/inputs/update_customer_session_input"
|
|
89
|
+
require "braintree/graphql/inputs/paypal_purchase_unit_input"
|
|
90
|
+
require "braintree/graphql/inputs/paypal_payee_input"
|
|
91
|
+
require "braintree/graphql/inputs/monetary_amount_input"
|
|
92
|
+
require "braintree/graphql/types/customer_recommendations_payload"
|
|
93
|
+
require "braintree/graphql/types/payment_options"
|
|
94
|
+
require "braintree/graphql/types/payment_recommendations"
|
|
95
|
+
require "braintree/graphql/unions/customer_recommendations"
|
|
78
96
|
require "braintree/graphql_client"
|
|
79
97
|
require "braintree/google_pay_card"
|
|
80
98
|
require "braintree/local_payment_completed"
|
|
@@ -87,9 +105,6 @@ require "braintree/merchant"
|
|
|
87
105
|
require "braintree/merchant_gateway"
|
|
88
106
|
require "braintree/merchant_account"
|
|
89
107
|
require "braintree/merchant_account_gateway"
|
|
90
|
-
require "braintree/merchant_account/individual_details"
|
|
91
|
-
require "braintree/merchant_account/business_details"
|
|
92
|
-
require "braintree/merchant_account/funding_details"
|
|
93
108
|
require "braintree/merchant_account/address_details"
|
|
94
109
|
require "braintree/meta_checkout_card"
|
|
95
110
|
require "braintree/meta_checkout_token"
|
|
@@ -106,6 +121,8 @@ require "braintree/payment_method_nonce_gateway"
|
|
|
106
121
|
require "braintree/payment_method_parser"
|
|
107
122
|
require "braintree/paypal_account"
|
|
108
123
|
require "braintree/paypal_account_gateway"
|
|
124
|
+
require "braintree/paypal_payment_resource"
|
|
125
|
+
require "braintree/paypal_payment_resource_gateway"
|
|
109
126
|
require "braintree/plan"
|
|
110
127
|
require "braintree/plan_gateway"
|
|
111
128
|
require "braintree/processor_response_types"
|
|
@@ -186,6 +203,6 @@ require "braintree/webhook_testing"
|
|
|
186
203
|
require "braintree/webhook_testing_gateway"
|
|
187
204
|
require "braintree/xml"
|
|
188
205
|
require "braintree/xml/generator"
|
|
189
|
-
require "braintree/xml/
|
|
206
|
+
require "braintree/xml/nokogiri"
|
|
190
207
|
require "braintree/xml/rexml"
|
|
191
208
|
require "braintree/xml/parser"
|
|
@@ -33,7 +33,8 @@ describe Braintree::AdvancedSearch do
|
|
|
33
33
|
expect(collection).not_to include(subscription2)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
# we are temporarily skipping this test until we have a more stable CI env
|
|
37
|
+
xit "is_not" do
|
|
37
38
|
id = rand(36**8).to_s(36)
|
|
38
39
|
subscription1 = Braintree::Subscription.create(
|
|
39
40
|
:payment_method_token => @credit_card.token,
|
|
@@ -80,7 +81,8 @@ describe Braintree::AdvancedSearch do
|
|
|
80
81
|
expect(collection).not_to include(subscription2)
|
|
81
82
|
end
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
# we are temporarily skipping this test until we have a more stable CI env
|
|
85
|
+
xit "ends_with" do
|
|
84
86
|
id = rand(36**8).to_s(36)
|
|
85
87
|
subscription1 = Braintree::Subscription.create(
|
|
86
88
|
:payment_method_token => @credit_card.token,
|
|
@@ -175,7 +177,8 @@ describe Braintree::AdvancedSearch do
|
|
|
175
177
|
expect(collection).not_to include(subscription2)
|
|
176
178
|
end
|
|
177
179
|
|
|
178
|
-
|
|
180
|
+
# ignore until more stable CI
|
|
181
|
+
xit "returns only matching results given an argument list" do
|
|
179
182
|
subscription1 = Braintree::Subscription.create(
|
|
180
183
|
:payment_method_token => @credit_card.token,
|
|
181
184
|
:plan_id => SpecHelper::TriallessPlan[:id],
|
|
@@ -262,7 +265,7 @@ describe Braintree::AdvancedSearch do
|
|
|
262
265
|
|
|
263
266
|
context "multiple_value_or_text_field" do
|
|
264
267
|
describe "in" do
|
|
265
|
-
|
|
268
|
+
xit "works for the in operator(temporarily disabling until more stable CI)" do
|
|
266
269
|
Braintree::Subscription.create(
|
|
267
270
|
:payment_method_token => @credit_card.token,
|
|
268
271
|
:plan_id => SpecHelper::TriallessPlan[:id],
|
|
@@ -2,20 +2,19 @@ require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
|
|
|
2
2
|
|
|
3
3
|
describe Braintree::ApplePayGateway do
|
|
4
4
|
before(:each) do
|
|
5
|
-
|
|
5
|
+
oauth_gateway = Braintree::Gateway.new(
|
|
6
6
|
:client_id => "client_id$#{Braintree::Configuration.environment}$integration_client_id",
|
|
7
7
|
:client_secret => "client_secret$#{Braintree::Configuration.environment}$integration_client_secret",
|
|
8
8
|
:logger => Logger.new("/dev/null"),
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
:
|
|
13
|
-
:
|
|
14
|
-
|
|
15
|
-
)
|
|
11
|
+
access_token = Braintree::OAuthTestHelper.create_token(oauth_gateway, {
|
|
12
|
+
:merchant_public_id => "integration_merchant_id",
|
|
13
|
+
:scope => "read_write"
|
|
14
|
+
}).credentials.access_token
|
|
16
15
|
|
|
17
16
|
@gateway = Braintree::Gateway.new(
|
|
18
|
-
:access_token =>
|
|
17
|
+
:access_token => access_token,
|
|
19
18
|
:logger => Logger.new("/dev/null"),
|
|
20
19
|
)
|
|
21
20
|
end
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
|
|
3
|
+
|
|
4
|
+
describe Braintree::BankAccountInstantVerificationGateway do
|
|
5
|
+
before do
|
|
6
|
+
@gateway = Braintree::Gateway.new(
|
|
7
|
+
:environment => :development,
|
|
8
|
+
:merchant_id => "integration2_merchant_id",
|
|
9
|
+
:public_key => "integration2_public_key",
|
|
10
|
+
:private_key => "integration2_private_key",
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
@us_bank_gateway = Braintree::Gateway.new(
|
|
14
|
+
:environment => :development,
|
|
15
|
+
:merchant_id => "integration_merchant_id",
|
|
16
|
+
:public_key => "integration_public_key",
|
|
17
|
+
:private_key => "integration_private_key",
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "create_jwt" do
|
|
22
|
+
it "creates a jwt with valid request" do
|
|
23
|
+
request = Braintree::BankAccountInstantVerificationJwtRequest.new(
|
|
24
|
+
:business_name => "15Ladders",
|
|
25
|
+
:return_url => "https://example.com/success",
|
|
26
|
+
:cancel_url => "https://example.com/cancel",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
result = @gateway.bank_account_instant_verification.create_jwt(request)
|
|
30
|
+
|
|
31
|
+
unless result.success?
|
|
32
|
+
puts "DEBUG: Result failed!"
|
|
33
|
+
puts "DEBUG: Errors: #{result.errors.inspect}" if result.respond_to?(:errors)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
expect(result.success?).to eq(true)
|
|
37
|
+
expect(result.bank_account_instant_verification_jwt).to have_attributes(
|
|
38
|
+
jwt: a_string_matching(/.+/),
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "fails with invalid business name" do
|
|
43
|
+
request = Braintree::BankAccountInstantVerificationJwtRequest.new(
|
|
44
|
+
:business_name => "", # Empty business name should cause validation error
|
|
45
|
+
:return_url => "https://example.com/return",
|
|
46
|
+
:cancel_url => "https://example.com/cancel",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
result = @gateway.bank_account_instant_verification.create_jwt(request)
|
|
50
|
+
|
|
51
|
+
expect(result.success?).to eq(false)
|
|
52
|
+
expect(result.errors).not_to be_nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "fails with invalid URLs" do
|
|
56
|
+
request = Braintree::BankAccountInstantVerificationJwtRequest.new(
|
|
57
|
+
:business_name => "15Ladders",
|
|
58
|
+
:return_url => "not-a-valid-url",
|
|
59
|
+
:cancel_url => "also-not-valid",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
result = @us_bank_gateway.bank_account_instant_verification.create_jwt(request)
|
|
63
|
+
|
|
64
|
+
expect(result.success?).to eq(false)
|
|
65
|
+
expect(result.errors).not_to be_nil
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe "charge US bank with ACH mandate" do
|
|
70
|
+
it "creates transaction directly with nonce and provides ACH mandate at transaction time (instant verification)" do
|
|
71
|
+
nonce = generate_us_bank_account_nonce_via_open_banking
|
|
72
|
+
|
|
73
|
+
mandate_accepted_at = Time.now - 300 # 5 minutes ago
|
|
74
|
+
|
|
75
|
+
# Create transaction directly with nonce and provide ACH mandate at transaction time (instant verification)
|
|
76
|
+
transaction_request = {
|
|
77
|
+
:amount => "12.34",
|
|
78
|
+
:payment_method_nonce => nonce,
|
|
79
|
+
:merchant_account_id => SpecHelper::UsBankMerchantAccountId, # could it be?
|
|
80
|
+
:us_bank_account => {
|
|
81
|
+
:ach_mandate_text => "I authorize this transaction and future debits",
|
|
82
|
+
:ach_mandate_accepted_at => mandate_accepted_at
|
|
83
|
+
},
|
|
84
|
+
:options => {
|
|
85
|
+
:submit_for_settlement => true
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
transaction_result = @us_bank_gateway.transaction.sale(transaction_request)
|
|
90
|
+
|
|
91
|
+
expect(transaction_result.success?).to eq(true), "Expected transaction success but got failure with validation errors (see console output)"
|
|
92
|
+
transaction = transaction_result.transaction
|
|
93
|
+
|
|
94
|
+
expected_transaction = {
|
|
95
|
+
id: a_string_matching(/.+/),
|
|
96
|
+
amount: BigDecimal("12.34"),
|
|
97
|
+
us_bank_account_details: have_attributes(
|
|
98
|
+
ach_mandate: have_attributes(
|
|
99
|
+
text: "I authorize this transaction and future debits",
|
|
100
|
+
accepted_at: be_a(Time),
|
|
101
|
+
),
|
|
102
|
+
account_holder_name: "Dan Schulman",
|
|
103
|
+
last_4: "1234",
|
|
104
|
+
routing_number: "021000021",
|
|
105
|
+
account_type: "checking",
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
expect(transaction).to have_attributes(expected_transaction)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
describe "Open Finance flow with INSTANT_VERIFICATION_ACCOUNT_VALIDATION" do
|
|
114
|
+
it "tokenizes bank account via Open Finance API, vaults with and charges" do
|
|
115
|
+
|
|
116
|
+
nonce = generate_us_bank_account_nonce_via_open_banking
|
|
117
|
+
|
|
118
|
+
customer_result = @us_bank_gateway.customer.create({})
|
|
119
|
+
expect(customer_result.success?).to eq(true)
|
|
120
|
+
customer = customer_result.customer
|
|
121
|
+
|
|
122
|
+
mandate_accepted_at = Time.now - 300
|
|
123
|
+
|
|
124
|
+
payment_method_request = {
|
|
125
|
+
:customer_id => customer.id,
|
|
126
|
+
:payment_method_nonce => nonce,
|
|
127
|
+
:us_bank_account => {
|
|
128
|
+
:ach_mandate_text => "I authorize this transaction and future debits",
|
|
129
|
+
:ach_mandate_accepted_at => mandate_accepted_at
|
|
130
|
+
},
|
|
131
|
+
:options => {
|
|
132
|
+
:verification_merchant_account_id => SpecHelper::UsBankMerchantAccountId,
|
|
133
|
+
:us_bank_account_verification_method => Braintree::UsBankAccountVerification::VerificationMethod::InstantVerificationAccountValidation
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
payment_method_result = @us_bank_gateway.payment_method.create(payment_method_request)
|
|
138
|
+
expect(payment_method_result.success?).to eq(true), "Expected payment method creation success but got failure with validation errors"
|
|
139
|
+
|
|
140
|
+
us_bank_account = payment_method_result.payment_method
|
|
141
|
+
|
|
142
|
+
expected_us_bank_account = {
|
|
143
|
+
verifications: a_collection_containing_exactly(
|
|
144
|
+
have_attributes(
|
|
145
|
+
verification_method: Braintree::UsBankAccountVerification::VerificationMethod::InstantVerificationAccountValidation,
|
|
146
|
+
status: "verified",
|
|
147
|
+
),
|
|
148
|
+
),
|
|
149
|
+
ach_mandate: have_attributes(
|
|
150
|
+
text: "I authorize this transaction and future debits",
|
|
151
|
+
accepted_at: be_a(Time),
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
expect(us_bank_account).to have_attributes(expected_us_bank_account)
|
|
156
|
+
|
|
157
|
+
verification = us_bank_account.verifications.first
|
|
158
|
+
expect(verification.verification_method).to eq(Braintree::UsBankAccountVerification::VerificationMethod::InstantVerificationAccountValidation)
|
|
159
|
+
|
|
160
|
+
transaction_request = {
|
|
161
|
+
:amount => "12.34",
|
|
162
|
+
:payment_method_token => us_bank_account.token,
|
|
163
|
+
:merchant_account_id => SpecHelper::UsBankMerchantAccountId,
|
|
164
|
+
:options => {
|
|
165
|
+
:submit_for_settlement => true
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
transaction_result = @us_bank_gateway.transaction.sale(transaction_request)
|
|
170
|
+
expect(transaction_result.success?).to eq(true), "Expected transaction success but got failure"
|
|
171
|
+
transaction = transaction_result.transaction
|
|
172
|
+
|
|
173
|
+
expected_transaction = {
|
|
174
|
+
id: a_string_matching(/.+/),
|
|
175
|
+
amount: BigDecimal("12.34"),
|
|
176
|
+
us_bank_account_details: have_attributes(
|
|
177
|
+
token: us_bank_account.token,
|
|
178
|
+
ach_mandate: have_attributes(
|
|
179
|
+
text: "I authorize this transaction and future debits",
|
|
180
|
+
accepted_at: be_a(Time),
|
|
181
|
+
),
|
|
182
|
+
last_4: "1234",
|
|
183
|
+
routing_number: "021000021",
|
|
184
|
+
account_type: "checking",
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
expect(transaction).to have_attributes(expected_transaction)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
@@ -147,6 +147,87 @@ def generate_invalid_us_bank_account_nonce
|
|
|
147
147
|
nonce + "_xxx"
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
+
def generate_us_bank_account_nonce_via_open_banking
|
|
151
|
+
|
|
152
|
+
config = Braintree::Configuration.new(
|
|
153
|
+
:environment => :development,
|
|
154
|
+
:merchant_id => "integration_merchant_id",
|
|
155
|
+
:public_key => "integration_public_key",
|
|
156
|
+
:private_key => "integration_private_key",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
request_body = {
|
|
160
|
+
:account_details => {
|
|
161
|
+
:account_number => "567891234",
|
|
162
|
+
:account_type => "CHECKING",
|
|
163
|
+
:classification => "PERSONAL",
|
|
164
|
+
:tokenized_account => true,
|
|
165
|
+
:last_4 => "1234"
|
|
166
|
+
},
|
|
167
|
+
:institution_details => {
|
|
168
|
+
:bank_id => {
|
|
169
|
+
:bank_code => "021000021",
|
|
170
|
+
:country_code => "US"
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
:account_holders => [
|
|
174
|
+
{
|
|
175
|
+
:ownership => "PRIMARY",
|
|
176
|
+
:full_name => {
|
|
177
|
+
:name => "Dan Schulman"
|
|
178
|
+
},
|
|
179
|
+
:name => {
|
|
180
|
+
:given_name => "Dan",
|
|
181
|
+
:surname => "Schulman",
|
|
182
|
+
:full_name => "Dan Schulman"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
graphql_base_url = config.graphql_base_url
|
|
189
|
+
atmosphere_base_url = graphql_base_url.gsub("/graphql", "")
|
|
190
|
+
url = "#{atmosphere_base_url}/v1/open-finance/tokenize-bank-account-details"
|
|
191
|
+
|
|
192
|
+
uri = URI.parse(url)
|
|
193
|
+
connection = Net::HTTP.new(uri.host, uri.port)
|
|
194
|
+
|
|
195
|
+
if uri.scheme == "https"
|
|
196
|
+
connection.use_ssl = true
|
|
197
|
+
connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
198
|
+
connection.ca_file = config.ca_file if config.ca_file
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
response = connection.start do |http|
|
|
202
|
+
request = Net::HTTP::Post.new(uri.path)
|
|
203
|
+
request["Content-Type"] = "application/json"
|
|
204
|
+
request["Accept"] = "application/json"
|
|
205
|
+
request["Braintree-Version"] = "2019-01-01"
|
|
206
|
+
request["User-Agent"] = "Braintree Ruby Library #{Braintree::Version::String}"
|
|
207
|
+
request["X-ApiVersion"] = config.api_version
|
|
208
|
+
|
|
209
|
+
# Basic auth like Node.js
|
|
210
|
+
auth_string = "#{config.public_key}:#{config.private_key}"
|
|
211
|
+
request["Authorization"] = "Basic #{Base64.strict_encode64(auth_string)}"
|
|
212
|
+
|
|
213
|
+
request.body = request_body.to_json
|
|
214
|
+
|
|
215
|
+
http.request(request)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
if response.code.to_i != 200
|
|
219
|
+
raise "HTTP #{response.code}: #{response.body}"
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
result = JSON.parse(response.body)
|
|
223
|
+
|
|
224
|
+
unless result["tenant_token"]
|
|
225
|
+
raise "Open Banking tokenization failed: #{result.inspect}"
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
result["tenant_token"]
|
|
229
|
+
end
|
|
230
|
+
|
|
150
231
|
def _cosmos_post(token, url, payload)
|
|
151
232
|
uri = URI::parse(url)
|
|
152
233
|
connection = Net::HTTP.new(uri.host, uri.port)
|
|
@@ -449,6 +449,66 @@ describe Braintree::CreditCard do
|
|
|
449
449
|
expect(credit_card.prepaid).to eq(Braintree::CreditCard::Prepaid::Yes)
|
|
450
450
|
end
|
|
451
451
|
|
|
452
|
+
it "sets the prepaid reloadable field if the card is prepaid reloadable" do
|
|
453
|
+
customer = Braintree::Customer.create!
|
|
454
|
+
result = Braintree::CreditCard.create(
|
|
455
|
+
:customer_id => customer.id,
|
|
456
|
+
:number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::PrepaidReloadable,
|
|
457
|
+
:expiration_date => "05/2014",
|
|
458
|
+
:options => {:verify_card => true},
|
|
459
|
+
)
|
|
460
|
+
credit_card = result.credit_card
|
|
461
|
+
expect(credit_card.prepaid_reloadable).to eq(Braintree::CreditCard::PrepaidReloadable::Yes)
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
it "sets the business field if the card is business" do
|
|
465
|
+
customer = Braintree::Customer.create!
|
|
466
|
+
result = Braintree::CreditCard.create(
|
|
467
|
+
:customer_id => customer.id,
|
|
468
|
+
:number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::Business,
|
|
469
|
+
:expiration_date => "05/2014",
|
|
470
|
+
:options => {:verify_card => true},
|
|
471
|
+
)
|
|
472
|
+
credit_card = result.credit_card
|
|
473
|
+
expect(credit_card.business).to eq(Braintree::CreditCard::Business::Yes)
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
it "sets the consumer field if the card is consumer" do
|
|
477
|
+
customer = Braintree::Customer.create!
|
|
478
|
+
result = Braintree::CreditCard.create(
|
|
479
|
+
:customer_id => customer.id,
|
|
480
|
+
:number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::Consumer,
|
|
481
|
+
:expiration_date => "05/2014",
|
|
482
|
+
:options => {:verify_card => true},
|
|
483
|
+
)
|
|
484
|
+
credit_card = result.credit_card
|
|
485
|
+
expect(credit_card.consumer).to eq(Braintree::CreditCard::Consumer::Yes)
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
it "sets the corporate field if the card is corporate" do
|
|
489
|
+
customer = Braintree::Customer.create!
|
|
490
|
+
result = Braintree::CreditCard.create(
|
|
491
|
+
:customer_id => customer.id,
|
|
492
|
+
:number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::Corporate,
|
|
493
|
+
:expiration_date => "05/2014",
|
|
494
|
+
:options => {:verify_card => true},
|
|
495
|
+
)
|
|
496
|
+
credit_card = result.credit_card
|
|
497
|
+
expect(credit_card.corporate).to eq(Braintree::CreditCard::Corporate::Yes)
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
it "sets the purchase field if the card is purchase" do
|
|
501
|
+
customer = Braintree::Customer.create!
|
|
502
|
+
result = Braintree::CreditCard.create(
|
|
503
|
+
:customer_id => customer.id,
|
|
504
|
+
:number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::Purchase,
|
|
505
|
+
:expiration_date => "05/2014",
|
|
506
|
+
:options => {:verify_card => true},
|
|
507
|
+
)
|
|
508
|
+
credit_card = result.credit_card
|
|
509
|
+
expect(credit_card.purchase).to eq(Braintree::CreditCard::Purchase::Yes)
|
|
510
|
+
end
|
|
511
|
+
|
|
452
512
|
it "sets the healthcare field if the card is healthcare" do
|
|
453
513
|
customer = Braintree::Customer.create!
|
|
454
514
|
result = Braintree::CreditCard.create(
|
|
@@ -1203,7 +1263,8 @@ describe Braintree::CreditCard do
|
|
|
1203
1263
|
end
|
|
1204
1264
|
|
|
1205
1265
|
describe "self.expiring_between" do
|
|
1206
|
-
|
|
1266
|
+
#Disabling this test until we have a more stable CI
|
|
1267
|
+
xit "finds payment methods expiring between the given dates" do
|
|
1207
1268
|
next_year = Time.now.year + 1
|
|
1208
1269
|
collection = Braintree::CreditCard.expiring_between(Time.mktime(next_year, 1), Time.mktime(next_year, 12))
|
|
1209
1270
|
expect(collection.maximum_size).to be > 0
|
|
@@ -1437,4 +1498,57 @@ describe Braintree::CreditCard do
|
|
|
1437
1498
|
expect(credit_card_vaulted.is_network_tokenized?).to eq(false)
|
|
1438
1499
|
end
|
|
1439
1500
|
end
|
|
1501
|
+
|
|
1502
|
+
describe "account information inquiry" do
|
|
1503
|
+
it "includes ani response when account information inquiry is sent in options" do
|
|
1504
|
+
customer = Braintree::Customer.create!
|
|
1505
|
+
result = Braintree::CreditCard.create(
|
|
1506
|
+
:cardholder_name => "John Doe",
|
|
1507
|
+
:customer_id => customer.id,
|
|
1508
|
+
:cvv => "123",
|
|
1509
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
|
1510
|
+
:expiration_date => "05/2027",
|
|
1511
|
+
:billing_address => {
|
|
1512
|
+
:first_name => "John",
|
|
1513
|
+
:last_name => "Doe",
|
|
1514
|
+
},
|
|
1515
|
+
:options => {
|
|
1516
|
+
:account_information_inquiry => "send_data",
|
|
1517
|
+
:verify_card => true,
|
|
1518
|
+
},
|
|
1519
|
+
)
|
|
1520
|
+
|
|
1521
|
+
expect(result).to be_success
|
|
1522
|
+
verification = result.credit_card.verification
|
|
1523
|
+
expect(verification.ani_first_name_response_code).not_to be_nil
|
|
1524
|
+
expect(verification.ani_last_name_response_code).not_to be_nil
|
|
1525
|
+
end
|
|
1526
|
+
|
|
1527
|
+
it "includes ani response after updating the options with account information inquiry" do
|
|
1528
|
+
customer = Braintree::Customer.create!
|
|
1529
|
+
credit_card = Braintree::CreditCard.create!(
|
|
1530
|
+
:cardholder_name => "Original Holder",
|
|
1531
|
+
:customer_id => customer.id,
|
|
1532
|
+
:cvv => "123",
|
|
1533
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
|
1534
|
+
:expiration_date => "05/2027",
|
|
1535
|
+
)
|
|
1536
|
+
updated_result = Braintree::CreditCard.update(credit_card.token,
|
|
1537
|
+
:options => {
|
|
1538
|
+
:verify_card => true,
|
|
1539
|
+
:account_information_inquiry => "send_data",
|
|
1540
|
+
},
|
|
1541
|
+
)
|
|
1542
|
+
|
|
1543
|
+
expect(updated_result).to be_success
|
|
1544
|
+
verification = updated_result.credit_card.verification
|
|
1545
|
+
expect(verification.ani_first_name_response_code).not_to be_nil
|
|
1546
|
+
expect(verification.ani_last_name_response_code).not_to be_nil
|
|
1547
|
+
end
|
|
1548
|
+
end
|
|
1440
1549
|
end
|
|
1550
|
+
|
|
1551
|
+
|
|
1552
|
+
|
|
1553
|
+
|
|
1554
|
+
|