braintree 2.84.0 → 2.85.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/braintree.rb +3 -0
  3. data/lib/braintree/advanced_search.rb +8 -0
  4. data/lib/braintree/credit_card_verification_gateway.rb +1 -1
  5. data/lib/braintree/error_codes.rb +6 -0
  6. data/lib/braintree/gateway.rb +4 -0
  7. data/lib/braintree/payment_method_gateway.rb +3 -1
  8. data/lib/braintree/us_bank_account.rb +8 -0
  9. data/lib/braintree/us_bank_account_verification.rb +75 -0
  10. data/lib/braintree/us_bank_account_verification_gateway.rb +32 -0
  11. data/lib/braintree/us_bank_account_verification_search.rb +19 -0
  12. data/lib/braintree/version.rb +1 -1
  13. data/lib/braintree/webhook_notification.rb +3 -0
  14. data/lib/braintree/webhook_testing_gateway.rb +10 -0
  15. data/spec/httpsd.pid +1 -1
  16. data/spec/integration/braintree/client_api/spec_helper.rb +33 -5
  17. data/spec/integration/braintree/credit_card_spec.rb +2 -2
  18. data/spec/integration/braintree/customer_spec.rb +9 -4
  19. data/spec/integration/braintree/dispute_search_spec.rb +14 -3
  20. data/spec/integration/braintree/payment_method_spec.rb +0 -35
  21. data/spec/integration/braintree/payment_method_us_bank_account_spec.rb +412 -0
  22. data/spec/integration/braintree/transaction_search_spec.rb +49 -51
  23. data/spec/integration/braintree/transaction_spec.rb +3 -93
  24. data/spec/integration/braintree/transaction_us_bank_account_spec.rb +432 -0
  25. data/spec/integration/braintree/us_bank_account_spec.rb +36 -15
  26. data/spec/integration/braintree/us_bank_account_verification_search_spec.rb +178 -0
  27. data/spec/integration/braintree/us_bank_account_verification_spec.rb +79 -0
  28. data/spec/spec_helper.rb +2 -1
  29. data/spec/unit/braintree/us_bank_account_verification_search_spec.rb +60 -0
  30. data/spec/unit/braintree/us_bank_account_verification_spec.rb +67 -0
  31. data/spec/unit/braintree/webhook_notification_spec.rb +13 -0
  32. metadata +12 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 363bcd4d73f995c9a4d466742eeec1496685280b
4
- data.tar.gz: a1cd82c6bb218c247760888361869e070290a74f
3
+ metadata.gz: b0d64ca677afdd3bc219c98009af627b4cbfaaaa
4
+ data.tar.gz: a5c8eafe9e54ce75579959bface19399b59ecf8e
5
5
  SHA512:
6
- metadata.gz: 07ef9f0eafcf69cd852a6a296d3a3662915cd13460574b11af1dc111cf6c50febb6036563f27d625397a268e317f08156714064ce230797b4008a839bb8a2249
7
- data.tar.gz: c85e68010fb8f18916c7ed9d71dec1e5ed9b97e494db6fc3e47b63561bd5fa1a42d4e4ececf6d8849ad4f0d1e37192ad5c0df006e67f10ae5a114d331821f568
6
+ metadata.gz: fc4bed06b88725a62739b7f2c2b014b19b42aaeb55a4ab7eb2d559aeb2c136b6d14ff60c684fbe44f2943a3c3119ec1be4eaba9adfda8a17601d05f63f79d993
7
+ data.tar.gz: 93eac87bd236a4923440f96413c19aad8ddf09bbbd7c2ab633bfe6ccd6645d70c737ce643de9204833bf585b2a811308a1f84f3d89c7526f8c9e691410523dd7
@@ -105,6 +105,9 @@ require "braintree/paginated_result"
105
105
  require "braintree/europe_bank_account"
106
106
  require "braintree/europe_bank_account_gateway"
107
107
  require "braintree/us_bank_account"
108
+ require "braintree/us_bank_account_verification"
109
+ require "braintree/us_bank_account_verification_gateway"
110
+ require "braintree/us_bank_account_verification_search"
108
111
  require "braintree/us_bank_account_gateway"
109
112
  require "braintree/transaction/us_bank_account_details"
110
113
  require "braintree/sha256_digest"
@@ -62,6 +62,10 @@ module Braintree
62
62
  end
63
63
  end
64
64
 
65
+ class EndsWithNode < SearchNode # :nodoc:
66
+ operators :ends_with
67
+ end
68
+
65
69
  class MultipleValueOrTextNode < MultipleValueNode
66
70
  extend Forwardable
67
71
  def_delegators :@text_node, :contains, :ends_with, :is, :is_not, :starts_with
@@ -129,6 +133,10 @@ module Braintree
129
133
  _create_field_accessors(fields, DateRangeNode)
130
134
  end
131
135
 
136
+ def self.ends_with_fields(*fields)
137
+ _create_field_accessors(fields, EndsWithNode)
138
+ end
139
+
132
140
  def self._create_field_accessors(fields, node_class)
133
141
  fields.each do |field|
134
142
  define_method(field) do |*args|
@@ -7,7 +7,7 @@ module Braintree
7
7
  end
8
8
 
9
9
  def find(id)
10
- raise ArgumentError if id.nil? || id.strip.to_s == ""
10
+ raise ArgumentError if id.nil? || id.to_s.strip == ""
11
11
  response = @config.http.get("#{@config.base_merchant_path}/verifications/#{id}")
12
12
  CreditCardVerification._new(response[:verification])
13
13
  rescue NotFoundError
@@ -343,6 +343,8 @@ module Braintree
343
343
  PaymentMethodNonceCardTypeIsNotAccepted = "91567"
344
344
  PaymentMethodNonceConsumed = "91564"
345
345
  PaymentMethodNonceHasNoValidPaymentInstrumentType = "91569"
346
+ UsBankAccountNonceMustBePlaidVerified = "915171"
347
+ UsBankAccountNotVerified = "915172"
346
348
  PaymentMethodNonceLocked = "91566"
347
349
  PaymentMethodNonceUnknown = "91565"
348
350
  PaymentMethodTokenCardTypeIsNotAccepted = "91517"
@@ -612,6 +614,10 @@ module Braintree
612
614
  PaymentMethodNonceLocked = "93109"
613
615
  CannotForwardPaymentMethodType = "93107"
614
616
  PaymentMethodNoLongerSupported = "93117"
617
+
618
+ module Options
619
+ UsBankAccountVerificationMethodIsInvalid = "93121"
620
+ end
615
621
  end
616
622
 
617
623
  module AuthorizationFingerprint
@@ -112,6 +112,10 @@ module Braintree
112
112
  TestingGateway.new(self)
113
113
  end
114
114
 
115
+ def us_bank_account_verification
116
+ UsBankAccountVerificationGateway.new(self)
117
+ end
118
+
115
119
  def verification
116
120
  CreditCardVerificationGateway.new(self)
117
121
  end
@@ -139,6 +139,8 @@ module Braintree
139
139
  SuccessfulResult.new(:payment_method => CoinbaseAccount._new(@gateway, response[:coinbase_account]))
140
140
  elsif response[:api_error_response]
141
141
  ErrorResult.new(@gateway, response[:api_error_response])
142
+ elsif response[:us_bank_account]
143
+ SuccessfulResult.new(:payment_method => UsBankAccount._new(@gateway, response[:us_bank_account]))
142
144
  elsif response
143
145
  SuccessfulResult.new(:payment_method => UnknownPaymentMethod._new(@gateway, response))
144
146
  else
@@ -163,7 +165,7 @@ module Braintree
163
165
  paypal_options_shipping_signature = AddressGateway._shared_signature
164
166
  options = [
165
167
  :make_default, :verification_merchant_account_id, :verify_card, :venmo_sdk_session,
166
- :verification_amount,
168
+ :verification_amount, :us_bank_account_verification_method,
167
169
  :paypal => [
168
170
  :payee_email,
169
171
  :order_id,
@@ -11,11 +11,19 @@ module Braintree
11
11
  attr_reader :last_4
12
12
  attr_reader :routing_number
13
13
  attr_reader :token
14
+ attr_reader :verifications
15
+ attr_reader :verified
14
16
 
15
17
  def initialize(gateway, attributes) # :nodoc:
16
18
  @gateway = gateway
17
19
  set_instance_variables_from_hash(attributes)
18
20
  @ach_mandate = AchMandate.new(attributes[:ach_mandate]) if attributes[:ach_mandate]
21
+
22
+ if attributes[:verifications]
23
+ @verifications = attributes[:verifications].map do |v|
24
+ UsBankAccountVerification._new(v)
25
+ end
26
+ end
19
27
  end
20
28
 
21
29
  def default?
@@ -0,0 +1,75 @@
1
+ module Braintree
2
+ class UsBankAccountVerification
3
+ include BaseModule
4
+ include Braintree::Util::IdEquality
5
+
6
+ module Status
7
+ Failed = "failed"
8
+ GatewayRejected = "gateway_rejected"
9
+ ProcessorDeclined = "processor_declined"
10
+ Verified = "verified"
11
+
12
+ All = [Failed, GatewayRejected, ProcessorDeclined, Verified]
13
+ end
14
+
15
+ module VerificationMethod
16
+ IndependentCheck = "independent_check"
17
+ NetworkCheck = "network_check"
18
+ TokenizedCheck = "tokenized_check"
19
+
20
+ All = [IndependentCheck, NetworkCheck, TokenizedCheck]
21
+ end
22
+
23
+ attr_reader :id
24
+ attr_reader :status
25
+ attr_reader :verification_determined_at
26
+ attr_reader :verification_method
27
+ attr_reader :processor_response_code
28
+ attr_reader :processor_response_text
29
+ attr_reader :merchant_account_id
30
+ attr_reader :gateway_rejection_reason
31
+ attr_reader :us_bank_account
32
+ attr_reader :created_at
33
+
34
+ def initialize(attributes) # :nodoc:
35
+ set_instance_variables_from_hash(attributes)
36
+ end
37
+
38
+ def inspect # :nodoc:
39
+ attr_order = [
40
+ :status,
41
+ :processor_response_code,
42
+ :processor_response_text,
43
+ :merchant_account_id,
44
+ :gateway_rejection_reason,
45
+ :id,
46
+ :us_bank_account,
47
+ :verification_method,
48
+ :verification_determined_at,
49
+ :created_at
50
+ ]
51
+
52
+ formatted_attrs = attr_order.map do |attr|
53
+ "#{attr}: #{send(attr).inspect}"
54
+ end
55
+
56
+ "#<#{self.class} #{formatted_attrs.join(", ")}>"
57
+ end
58
+
59
+ class << self
60
+ protected :new
61
+ end
62
+
63
+ def self._new(*args) # :nodoc:
64
+ self.new *args
65
+ end
66
+
67
+ def self.find(*args)
68
+ Configuration.gateway.us_bank_account_verification.find(*args)
69
+ end
70
+
71
+ def self.search(&block)
72
+ Configuration.gateway.us_bank_account_verification.search(&block)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,32 @@
1
+ module Braintree
2
+ class UsBankAccountVerificationGateway
3
+ def initialize(gateway)
4
+ @gateway = gateway
5
+ @config = gateway.config
6
+ @config.assert_has_access_token_or_keys
7
+ end
8
+
9
+ def find(id)
10
+ raise ArgumentError if id.nil? || id.to_s.strip == ""
11
+ response = @config.http.get("#{@config.base_merchant_path}/us_bank_account_verifications/#{id}")
12
+ UsBankAccountVerification._new(response[:us_bank_account_verification])
13
+ rescue NotFoundError
14
+ raise NotFoundError, "verification with id #{id.inspect} not found"
15
+ end
16
+
17
+ def search(&block)
18
+ search = UsBankAccountVerificationSearch.new
19
+ block.call(search) if block
20
+
21
+ response = @config.http.post("#{@config.base_merchant_path}/us_bank_account_verifications/advanced_search_ids", {:search => search.to_hash})
22
+ ResourceCollection.new(response) { |ids| _fetch_verifications(search, ids) }
23
+ end
24
+
25
+ def _fetch_verifications(search, ids)
26
+ search.ids.in ids
27
+ response = @config.http.post("#{@config.base_merchant_path}/us_bank_account_verifications/advanced_search", {:search => search.to_hash})
28
+ attributes = response[:us_bank_account_verifications]
29
+ Util.extract_attribute_as_array(attributes, :us_bank_account_verification).map { |attrs| UsBankAccountVerification._new(attrs) }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ module Braintree
2
+ class UsBankAccountVerificationSearch < AdvancedSearch # :nodoc:
3
+ text_fields(
4
+ :id,
5
+ :account_holder_name,
6
+ :routing_number,
7
+ :payment_method_token,
8
+ :customer_id,
9
+ :customer_email,
10
+ )
11
+
12
+ multiple_value_field :verification_method, :allows => UsBankAccountVerification::VerificationMethod::All
13
+ multiple_value_field :status, :allows => UsBankAccountVerification::Status::All
14
+ multiple_value_field :ids
15
+ ends_with_fields :account_number
16
+ range_fields :created_at
17
+ equality_fields :account_type
18
+ end
19
+ end
@@ -1,7 +1,7 @@
1
1
  module Braintree
2
2
  module Version
3
3
  Major = 2
4
- Minor = 84
4
+ Minor = 85
5
5
  Tiny = 0
6
6
 
7
7
  String = "#{Major}.#{Minor}.#{Tiny}"
@@ -30,6 +30,7 @@ module Braintree
30
30
  PartnerMerchantConnected = "partner_merchant_connected"
31
31
  PartnerMerchantDisconnected = "partner_merchant_disconnected"
32
32
  PartnerMerchantDeclined = "partner_merchant_declined"
33
+ OAuthAccessRevoked = "oauth_access_revoked"
33
34
 
34
35
  AccountUpdaterDailyReport = "account_updater_daily_report"
35
36
 
@@ -51,6 +52,7 @@ module Braintree
51
52
  attr_reader :ideal_payment
52
53
  attr_reader :kind
53
54
  attr_reader :partner_merchant
55
+ attr_reader :oauth_access_revocation
54
56
  attr_reader :source_merchant_id
55
57
  attr_reader :subscription
56
58
  attr_reader :timestamp
@@ -70,6 +72,7 @@ module Braintree
70
72
  @error_result = ErrorResult.new(gateway, @subject[:api_error_response]) if @subject.has_key?(:api_error_response)
71
73
  @merchant_account = MerchantAccount._new(gateway, @subject[:merchant_account]) if @subject.has_key?(:merchant_account)
72
74
  @partner_merchant = OpenStruct.new(@subject[:partner_merchant]) if @subject.has_key?(:partner_merchant)
75
+ @oauth_access_revocation = OpenStruct.new(@subject[:oauth_application_revocation]) if @subject.has_key?(:oauth_application_revocation)
73
76
  @subscription = Subscription._new(gateway, @subject[:subscription]) if @subject.has_key?(:subscription)
74
77
  @transaction = Transaction._new(gateway, @subject[:transaction]) if @subject.has_key?(:transaction)
75
78
  @disbursement = Disbursement._new(gateway, @subject[:disbursement]) if @subject.has_key?(:disbursement)
@@ -46,6 +46,8 @@ module Braintree
46
46
  _partner_merchant_disconnected_sample_xml(id)
47
47
  when Braintree::WebhookNotification::Kind::PartnerMerchantDeclined
48
48
  _partner_merchant_declined_sample_xml(id)
49
+ when Braintree::WebhookNotification::Kind::OAuthAccessRevoked
50
+ _oauth_access_revoked_sample_xml(id)
49
51
  when Braintree::WebhookNotification::Kind::SubMerchantAccountApproved
50
52
  _merchant_account_approved_sample_xml(id)
51
53
  when Braintree::WebhookNotification::Kind::SubMerchantAccountDeclined
@@ -151,6 +153,14 @@ module Braintree
151
153
  XML
152
154
  end
153
155
 
156
+ def _oauth_access_revoked_sample_xml(id)
157
+ <<-XML
158
+ <oauth-application-revocation>
159
+ <merchant-id>abc123</merchant-id>
160
+ </oauth-application-revocation>
161
+ XML
162
+ end
163
+
154
164
  def _merchant_account_approved_sample_xml(id)
155
165
 
156
166
  <<-XML
@@ -1 +1 @@
1
- 1590
1
+ 2671
@@ -1,6 +1,5 @@
1
1
  require 'json'
2
2
 
3
-
4
3
  def decode_client_token(raw_client_token)
5
4
  decoded_client_token_string = Base64.decode64(raw_client_token)
6
5
  JSON.parse(decoded_client_token_string)
@@ -56,7 +55,7 @@ def nonce_for_paypal_account(paypal_account_details)
56
55
  body["paypalAccounts"][0]["nonce"]
57
56
  end
58
57
 
59
- def generate_valid_us_bank_account_nonce()
58
+ def generate_non_plaid_us_bank_account_nonce
60
59
  raw_client_token = Braintree::ClientToken.generate
61
60
  client_token = decode_client_token(raw_client_token)
62
61
 
@@ -72,8 +71,37 @@ def generate_valid_us_bank_account_nonce()
72
71
  },
73
72
  :account_type => "checking",
74
73
  :routing_number => "021000021",
75
- :account_number => "567891234",
76
- :account_holder_name => "Dan Schulman",
74
+ :account_number => "1000000000",
75
+ :first_name => "John",
76
+ :last_name => "Doe",
77
+ :ownership_type => "personal",
78
+ :ach_mandate => {
79
+ :text => "cl mandate text"
80
+ }
81
+ }
82
+
83
+ json = _cosmos_post(token, url, payload)
84
+ json["data"]["id"]
85
+ end
86
+
87
+ def generate_valid_plaid_us_bank_account_nonce
88
+ raw_client_token = Braintree::ClientToken.generate
89
+ client_token = decode_client_token(raw_client_token)
90
+
91
+ url = client_token["braintree_api"]["url"] + "/tokens"
92
+ token = client_token["braintree_api"]["access_token"]
93
+ payload = {
94
+ :type => "plaid_public_token",
95
+ :public_token => "good",
96
+ :account_id => "plaid_account_id",
97
+ :ownership_type => "business",
98
+ :business_name => "PayPal, Inc.",
99
+ :billing_address => {
100
+ :street_address => "123 Ave",
101
+ :region => "CA",
102
+ :locality => "San Francisco",
103
+ :postal_code => "94112"
104
+ },
77
105
  :ach_mandate => {
78
106
  :text => "cl mandate text"
79
107
  }
@@ -126,7 +154,7 @@ def _cosmos_post(token, url, payload)
126
154
  resp = connection.start do |http|
127
155
  request = Net::HTTP::Post.new(uri.path)
128
156
  request["Content-Type"] = "application/json"
129
- request["Braintree-Version"] = "2015-11-01"
157
+ request["Braintree-Version"] = "2016-10-07"
130
158
  request["Authorization"] = "Bearer #{token}"
131
159
  request.body = payload.to_json
132
160
  http.request(request)
@@ -459,7 +459,7 @@ describe Braintree::CreditCard do
459
459
  :venmo_sdk_payment_method_code => Braintree::Test::VenmoSDK::VisaPaymentMethodCode
460
460
  )
461
461
  result.success?.should == true
462
- result.credit_card.venmo_sdk?.should == true
462
+ result.credit_card.venmo_sdk?.should == false
463
463
  result.credit_card.bin.should == "400934"
464
464
  result.credit_card.last_4.should == "1881"
465
465
  end
@@ -490,7 +490,7 @@ describe Braintree::CreditCard do
490
490
  }
491
491
  )
492
492
  result.success?.should == true
493
- result.credit_card.venmo_sdk?.should == true
493
+ result.credit_card.venmo_sdk?.should == false
494
494
  end
495
495
 
496
496
  it "venmo_sdk? returns false when given an invalid session" do
@@ -456,7 +456,7 @@ describe Braintree::Customer do
456
456
  }
457
457
  )
458
458
  result.success?.should == true
459
- result.customer.credit_cards.first.venmo_sdk?.should == true
459
+ result.customer.credit_cards.first.venmo_sdk?.should == false
460
460
  end
461
461
  end
462
462
 
@@ -973,7 +973,12 @@ describe Braintree::Customer do
973
973
 
974
974
  it "returns associated us bank accounts" do
975
975
  result = Braintree::Customer.create(
976
- :payment_method_nonce => generate_valid_us_bank_account_nonce
976
+ :payment_method_nonce => generate_non_plaid_us_bank_account_nonce,
977
+ :credit_card => {
978
+ :options => {
979
+ :verification_merchant_account_id => SpecHelper::UsBankMerchantAccountId,
980
+ }
981
+ }
977
982
  )
978
983
  result.should be_success
979
984
 
@@ -984,9 +989,9 @@ describe Braintree::Customer do
984
989
  us_bank_account = found_customer.us_bank_accounts.first
985
990
  us_bank_account.should be_a(Braintree::UsBankAccount)
986
991
  us_bank_account.routing_number.should == "021000021"
987
- us_bank_account.last_4.should == "1234"
992
+ us_bank_account.last_4.should == "0000"
988
993
  us_bank_account.account_type.should == "checking"
989
- us_bank_account.account_holder_name.should == "Dan Schulman"
994
+ us_bank_account.account_holder_name.should == "John Doe"
990
995
  us_bank_account.bank_name.should =~ /CHASE/
991
996
  end
992
997
 
@@ -10,7 +10,7 @@ describe Braintree::Dispute, "search" do
10
10
  :email => "jen@example.com",
11
11
  :phone => "312.555.1234",
12
12
  :fax => "614.555.5678",
13
- :website => "www.example.com"
13
+ :website => "www.example.com",
14
14
  )
15
15
 
16
16
  result.customer
@@ -21,12 +21,12 @@ describe Braintree::Dispute, "search" do
21
21
  :amount => '10.00',
22
22
  :credit_card => {
23
23
  :expiration_date => '01/2020',
24
- :number => Braintree::Test::CreditCardNumbers::Disputes::Chargeback
24
+ :number => Braintree::Test::CreditCardNumbers::Disputes::Chargeback,
25
25
  },
26
26
  :customer_id => customer.id,
27
27
  :merchant_account_id => "14LaddersLLC_instant",
28
28
  :options => {
29
- :submit_for_settlement => true
29
+ :submit_for_settlement => true,
30
30
  }
31
31
  )
32
32
 
@@ -114,5 +114,16 @@ describe Braintree::Dispute, "search" do
114
114
 
115
115
  expect(dispute.received_date).to eq(Date.new(2014, 3, 4))
116
116
  end
117
+
118
+ it "correctly returns disputes by reply_by_date range" do
119
+ reply_by_date = transaction.disputes.first.reply_by_date
120
+
121
+ collection = Braintree::Dispute.search do |search|
122
+ search.reply_by_date.between(reply_by_date, reply_by_date + 1)
123
+ end
124
+
125
+ dispute_ids = collection.disputes.map { |d| d.id }
126
+ expect(dispute_ids).to include(transaction.disputes.first.id)
127
+ end
117
128
  end
118
129
  end