braintree 2.84.0 → 2.85.0

Sign up to get free protection for your applications and to get access to all the features.
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