braintree 3.4.0 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/braintree.gemspec +2 -2
  3. data/lib/braintree.rb +4 -0
  4. data/lib/braintree/address.rb +1 -0
  5. data/lib/braintree/apple_pay_card.rb +9 -0
  6. data/lib/braintree/credit_card_gateway.rb +11 -1
  7. data/lib/braintree/customer.rb +4 -2
  8. data/lib/braintree/customer_gateway.rb +2 -0
  9. data/lib/braintree/dispute.rb +14 -0
  10. data/lib/braintree/dispute/paypal_message.rb +15 -0
  11. data/lib/braintree/dispute_search.rb +1 -0
  12. data/lib/braintree/error_codes.rb +4 -6
  13. data/lib/braintree/google_pay_card.rb +9 -0
  14. data/lib/braintree/payment_method_gateway.rb +7 -4
  15. data/lib/braintree/payment_method_nonce.rb +7 -4
  16. data/lib/braintree/payment_method_nonce_details.rb +37 -0
  17. data/lib/braintree/payment_method_nonce_details_payer_info.rb +32 -0
  18. data/lib/braintree/transaction/paypal_details.rb +2 -0
  19. data/lib/braintree/transaction_gateway.rb +3 -3
  20. data/lib/braintree/version.rb +2 -2
  21. data/lib/braintree/webhook_notification.rb +2 -1
  22. data/lib/braintree/webhook_testing_gateway.rb +20 -0
  23. data/lib/braintree/xml/libxml.rb +0 -1
  24. data/lib/braintree/xml/parser.rb +12 -2
  25. data/lib/braintree/xml/rexml.rb +70 -0
  26. data/spec/integration/braintree/address_spec.rb +4 -0
  27. data/spec/integration/braintree/credit_card_spec.rb +89 -0
  28. data/spec/integration/braintree/customer_spec.rb +144 -0
  29. data/spec/integration/braintree/dispute_search_spec.rb +25 -0
  30. data/spec/integration/braintree/merchant_account_spec.rb +3 -3
  31. data/spec/integration/braintree/payment_method_nonce_spec.rb +16 -23
  32. data/spec/integration/braintree/payment_method_spec.rb +131 -0
  33. data/spec/integration/braintree/transaction_spec.rb +82 -2
  34. data/spec/spec_helper.rb +2 -0
  35. data/spec/unit/braintree/credit_card_spec.rb +6 -6
  36. data/spec/unit/braintree/customer_spec.rb +17 -7
  37. data/spec/unit/braintree/dispute_search_spec.rb +1 -0
  38. data/spec/unit/braintree/dispute_spec.rb +26 -1
  39. data/spec/unit/braintree/payment_method_nonce_details_payer_info_spec.rb +31 -0
  40. data/spec/unit/braintree/payment_method_nonce_details_spec.rb +43 -0
  41. data/spec/unit/braintree/payment_method_nonce_spec.rb +40 -0
  42. data/spec/unit/braintree/transaction/paypal_details_spec.rb +4 -0
  43. data/spec/unit/braintree/transaction_spec.rb +3 -3
  44. data/spec/unit/braintree/webhook_notification_spec.rb +16 -0
  45. data/spec/unit/braintree/xml/rexml_spec.rb +51 -0
  46. metadata +15 -7
@@ -1,7 +1,7 @@
1
1
  module Braintree
2
2
  module Version
3
- Major = 3
4
- Minor = 4
3
+ Major = 4
4
+ Minor = 3
5
5
  Tiny = 0
6
6
 
7
7
  String = "#{Major}.#{Minor}.#{Tiny}"
@@ -25,6 +25,7 @@ module Braintree
25
25
  GrantedPaymentInstrumentRevoked = "granted_payment_instrument_revoked"
26
26
 
27
27
  GrantorUpdatedGrantedPaymentMethod = "grantor_updated_granted_payment_method"
28
+ GrantedPaymentMethodRevoked = "granted_payment_method_revoked"
28
29
 
29
30
  LocalPaymentCompleted = "local_payment_completed"
30
31
  LocalPaymentReversed = "local_payment_reversed"
@@ -95,7 +96,7 @@ module Braintree
95
96
  @connected_merchant_status_transitioned = ConnectedMerchantStatusTransitioned._new(@subject[:connected_merchant_status_transitioned]) if @subject.has_key?(:connected_merchant_status_transitioned)
96
97
  @connected_merchant_paypal_status_changed = ConnectedMerchantPayPalStatusChanged._new(@subject[:connected_merchant_paypal_status_changed]) if @subject.has_key?(:connected_merchant_paypal_status_changed)
97
98
  @granted_payment_instrument_update = GrantedPaymentInstrumentUpdate._new(@subject[:granted_payment_instrument_update]) if @subject.has_key?(:granted_payment_instrument_update)
98
- @revoked_payment_method_metadata = RevokedPaymentMethodMetadata._new(gateway, @subject) if [Kind::GrantedPaymentInstrumentRevoked, Kind::PaymentMethodRevokedByCustomer].include?(@kind)
99
+ @revoked_payment_method_metadata = RevokedPaymentMethodMetadata._new(gateway, @subject) if [Kind::GrantedPaymentInstrumentRevoked, Kind::PaymentMethodRevokedByCustomer, Kind::GrantedPaymentMethodRevoked].include?(@kind)
99
100
  @local_payment_completed = LocalPaymentCompleted._new(@subject[:local_payment]) if @subject.has_key?(:local_payment) && Kind::LocalPaymentCompleted == @kind
100
101
  @local_payment_reversed = LocalPaymentReversed._new(@subject[:local_payment_reversed]) if @subject.has_key?(:local_payment_reversed) && Kind::LocalPaymentReversed == @kind
101
102
  end
@@ -82,6 +82,8 @@ module Braintree
82
82
  _granted_payment_instrument_update_sample_xml(id)
83
83
  when Braintree::WebhookNotification::Kind::RecipientUpdatedGrantedPaymentMethod
84
84
  _granted_payment_instrument_update_sample_xml(id)
85
+ when Braintree::WebhookNotification::Kind::GrantedPaymentMethodRevoked
86
+ _granted_payment_method_revoked_xml(id)
85
87
  when Braintree::WebhookNotification::Kind::PaymentMethodRevokedByCustomer
86
88
  _payment_method_revoked_by_customer_sample_xml(id)
87
89
  when Braintree::WebhookNotification::Kind::LocalPaymentCompleted
@@ -877,6 +879,24 @@ module Braintree
877
879
  XML
878
880
  end
879
881
 
882
+ def _granted_payment_method_revoked_xml(id)
883
+ <<-XML
884
+ <venmo-account>
885
+ <created-at type='dateTime'>2018-10-11T21:28:37Z</created-at>
886
+ <updated-at type='dateTime'>2018-10-11T21:28:37Z</updated-at>
887
+ <default type='boolean'>true</default>
888
+ <image-url>https://assets.braintreegateway.com/payment_method_logo/venmo.png?environment=test</image-url>
889
+ <token>#{id}</token>
890
+ <source-description>Venmo Account: venmojoe</source-description>
891
+ <username>venmojoe</username>
892
+ <venmo-user-id>456</venmo-user-id>
893
+ <subscriptions type='array'/>
894
+ <customer-id>venmo_customer_id</customer-id>
895
+ <global-id>cGF5bWVudG1ldGhvZF92ZW5tb2FjY291bnQ</global-id>
896
+ </venmo-account>
897
+ XML
898
+ end
899
+
880
900
  def _payment_method_revoked_by_customer_sample_xml(id)
881
901
  <<-XML
882
902
  <paypal-account>
@@ -1,4 +1,3 @@
1
- require "libxml"
2
1
  # Portions of this code were copied and modified from Ruby on Rails, released
3
2
  # under the MIT license, copyright (c) 2005-2009 David Heinemeier Hansson
4
3
  module Braintree
@@ -11,12 +11,22 @@ module Braintree
11
11
  "boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) },
12
12
  }
13
13
 
14
- def self.hash_from_xml(xml)
15
- standardized_hash_structure = ::Braintree::Xml::Libxml.parse(xml)
14
+ def self.hash_from_xml(xml, parser = _determine_parser)
15
+ standardized_hash_structure = parser.parse(xml)
16
16
  transformed_xml = _transform_xml(standardized_hash_structure)
17
17
  Util.symbolize_keys(transformed_xml)
18
18
  end
19
19
 
20
+ def self._determine_parser
21
+ # If LibXML is not available, we fall back to REXML
22
+ # This allows us to be compatible with JRuby, which LibXML does not support
23
+ if defined?(::LibXML::XML) && ::LibXML::XML.respond_to?(:default_keep_blanks=)
24
+ ::Braintree::Xml::Libxml
25
+ else
26
+ ::Braintree::Xml::Rexml
27
+ end
28
+ end
29
+
20
30
  # Transform into standard Ruby types and convert all keys to snake_case instead of dash-case
21
31
  def self._transform_xml(value)
22
32
  case value.class.to_s
@@ -0,0 +1,70 @@
1
+ # Portions of this code were copied and modified from Ruby on Rails, released
2
+ # under the MIT license, copyright (c) 2005-2009 David Heinemeier Hansson
3
+ module Braintree
4
+ module Xml # :nodoc:
5
+ module Rexml # :nodoc:
6
+
7
+ CONTENT_KEY = "__content__".freeze
8
+
9
+ def self.parse(string)
10
+ require "rexml/document" unless defined?(REXML::Document)
11
+ doc = REXML::Document.new(string)
12
+ _merge_element!({}, doc.root)
13
+ end
14
+
15
+ def self._merge_element!(hash, element)
16
+ _merge!(hash, element.name, _collapse(element))
17
+ end
18
+
19
+ def self._collapse(element)
20
+ hash = _get_attributes(element)
21
+
22
+ if element.has_elements?
23
+ element.each_element { |child| _merge_element!(hash, child) }
24
+ _merge_texts!(hash, element) unless _empty_content?(element)
25
+ hash
26
+ else
27
+ _merge_texts!(hash, element)
28
+ end
29
+ end
30
+
31
+ def self._merge_texts!(hash, element)
32
+ unless element.has_text?
33
+ hash
34
+ else
35
+ # must use value to prevent double-escaping
36
+ _merge!(
37
+ hash,
38
+ CONTENT_KEY,
39
+ element.texts.map { |t| t.value }.join,
40
+ )
41
+ end
42
+ end
43
+
44
+ def self._merge!(hash, key, value)
45
+ if hash.has_key?(key)
46
+ if hash[key].instance_of?(Array)
47
+ hash[key] << value
48
+ else
49
+ hash[key] = [hash[key], value]
50
+ end
51
+ elsif value.instance_of?(Array)
52
+ hash[key] = [value]
53
+ else
54
+ hash[key] = value
55
+ end
56
+ hash
57
+ end
58
+
59
+ def self._get_attributes(element)
60
+ attributes = {}
61
+ element.attributes.each { |n,v| attributes[n] = v }
62
+ attributes
63
+ end
64
+
65
+ def self._empty_content?(element)
66
+ element.texts.join.strip == ""
67
+ end
68
+ end
69
+ end
70
+ end
@@ -14,6 +14,7 @@ describe Braintree::Address do
14
14
  :extended_address => "Suite 200",
15
15
  :locality => "Chicago",
16
16
  :region => "Illinois",
17
+ :phone_number => "5551231234",
17
18
  :postal_code => "60622",
18
19
  :country_name => "United States of America",
19
20
  )
@@ -26,6 +27,7 @@ describe Braintree::Address do
26
27
  result.address.extended_address.should == "Suite 200"
27
28
  result.address.locality.should == "Chicago"
28
29
  result.address.region.should == "Illinois"
30
+ result.address.phone_number.should == "5551231234"
29
31
  result.address.postal_code.should == "60622"
30
32
  result.address.country_name.should == "United States of America"
31
33
  result.address.country_code_alpha2.should == "US"
@@ -131,6 +133,7 @@ describe Braintree::Address do
131
133
  :extended_address => "Suite 201",
132
134
  :locality => "Bartlett",
133
135
  :region => "IL",
136
+ :phone_number => "5551231234",
134
137
  :postal_code => "60623",
135
138
  :country_name => "United States of America",
136
139
  )
@@ -139,6 +142,7 @@ describe Braintree::Address do
139
142
  address.extended_address.should == "Suite 201"
140
143
  address.locality.should == "Bartlett"
141
144
  address.region.should == "IL"
145
+ address.phone_number.should == "5551231234"
142
146
  address.postal_code.should == "60623"
143
147
  address.country_name.should == "United States of America"
144
148
  end
@@ -157,6 +157,48 @@ describe Braintree::CreditCard do
157
157
  end
158
158
  end
159
159
 
160
+ it "includes risk data when skip_advanced_fraud_checking is false" do
161
+ with_fraud_protection_enterprise_merchant do
162
+ customer = Braintree::Customer.create!
163
+ result = Braintree::CreditCard.create(
164
+ :cardholder_name => "Original Holder",
165
+ :customer_id => customer.id,
166
+ :cvv => "123",
167
+ :number => Braintree::Test::CreditCardNumbers::Visa,
168
+ :expiration_date => "05/2020",
169
+ :options => {
170
+ :skip_advanced_fraud_checking => false,
171
+ :verify_card => true,
172
+ },
173
+ )
174
+
175
+ expect(result).to be_success
176
+ verification = result.credit_card.verification
177
+ expect(verification.risk_data).not_to be_nil
178
+ end
179
+ end
180
+
181
+ it "does not include risk data when skip_advanced_fraud_checking is true" do
182
+ with_fraud_protection_enterprise_merchant do
183
+ customer = Braintree::Customer.create!
184
+ result = Braintree::CreditCard.create(
185
+ :cardholder_name => "Original Holder",
186
+ :customer_id => customer.id,
187
+ :cvv => "123",
188
+ :number => Braintree::Test::CreditCardNumbers::Visa,
189
+ :expiration_date => "05/2020",
190
+ :options => {
191
+ :skip_advanced_fraud_checking => true,
192
+ :verify_card => true,
193
+ },
194
+ )
195
+
196
+ expect(result).to be_success
197
+ verification = result.credit_card.verification
198
+ expect(verification.risk_data).to be_nil
199
+ end
200
+ end
201
+
160
202
  it "exposes the gateway rejection reason on verification" do
161
203
  old_merchant = Braintree::Configuration.merchant_id
162
204
  old_public_key = Braintree::Configuration.public_key
@@ -852,7 +894,54 @@ describe Braintree::CreditCard do
852
894
  )
853
895
 
854
896
  result.success?.should == true
897
+ end
855
898
 
899
+ it "includes risk data when skip_advanced_fraud_checking is false" do
900
+ with_fraud_protection_enterprise_merchant do
901
+ customer = Braintree::Customer.create!
902
+ credit_card = Braintree::CreditCard.create!(
903
+ :cardholder_name => "Original Holder",
904
+ :customer_id => customer.id,
905
+ :cvv => "123",
906
+ :number => Braintree::Test::CreditCardNumbers::Visa,
907
+ :expiration_date => "05/2020",
908
+ )
909
+ updated_result = Braintree::CreditCard.update(credit_card.token,
910
+ :expiration_date => "05/2021",
911
+ :options => {
912
+ :verify_card => true,
913
+ :skip_advanced_fraud_checking => false,
914
+ },
915
+ )
916
+
917
+ expect(updated_result).to be_success
918
+ verification = updated_result.credit_card.verification
919
+ expect(verification.risk_data).not_to be_nil
920
+ end
921
+ end
922
+
923
+ it "does not include risk data when skip_advanced_fraud_checking is true" do
924
+ with_fraud_protection_enterprise_merchant do
925
+ customer = Braintree::Customer.create!
926
+ credit_card = Braintree::CreditCard.create!(
927
+ :cardholder_name => "Original Holder",
928
+ :customer_id => customer.id,
929
+ :cvv => "123",
930
+ :number => Braintree::Test::CreditCardNumbers::Visa,
931
+ :expiration_date => "05/2020",
932
+ )
933
+ updated_result = Braintree::CreditCard.update(credit_card.token,
934
+ :expiration_date => "05/2021",
935
+ :options => {
936
+ :verify_card => true,
937
+ :skip_advanced_fraud_checking => true,
938
+ },
939
+ )
940
+
941
+ expect(updated_result).to be_success
942
+ verification = updated_result.credit_card.verification
943
+ expect(verification.risk_data).to be_nil
944
+ end
856
945
  end
857
946
 
858
947
  context "billing address" do
@@ -40,6 +40,7 @@ describe Braintree::Customer do
40
40
  :phone => "312.555.1234",
41
41
  :fax => "614.555.5678",
42
42
  :website => "www.microsoft.com",
43
+ :tax_identifiers => [{:country_code => "US", :identifier => "987654321"}],
43
44
  )
44
45
  result.success?.should == true
45
46
  result.customer.id.should =~ /^\d{6,}$/
@@ -114,6 +115,57 @@ describe Braintree::Customer do
114
115
  result.should be_success
115
116
  end
116
117
 
118
+ it "includes risk data when skip_advanced_fraud_checking is false" do
119
+ with_fraud_protection_enterprise_merchant do
120
+ result = Braintree::Customer.create(
121
+ :credit_card => {
122
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
123
+ :expiration_date => "05/2010",
124
+ :cvv => "100",
125
+ :options => {
126
+ :skip_advanced_fraud_checking => false,
127
+ :verify_card => true,
128
+ },
129
+ },
130
+ )
131
+
132
+ expect(result).to be_success
133
+ verification = result.customer.credit_cards.first.verification
134
+ expect(verification.risk_data).not_to be_nil
135
+ end
136
+ end
137
+
138
+ it "does not include risk data when skip_advanced_fraud_checking is true" do
139
+ with_fraud_protection_enterprise_merchant do
140
+ result = Braintree::Customer.create(
141
+ :credit_card => {
142
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
143
+ :expiration_date => "05/2010",
144
+ :cvv => "100",
145
+ :options => {
146
+ :skip_advanced_fraud_checking => true,
147
+ :verify_card => true,
148
+ },
149
+ },
150
+ )
151
+
152
+ expect(result).to be_success
153
+ verification = result.customer.credit_cards.first.verification
154
+ expect(verification.risk_data).to be_nil
155
+ end
156
+ end
157
+
158
+ it "supports creation with tax_identifiers" do
159
+ result = Braintree::Customer.create(
160
+ :tax_identifiers => [
161
+ {:country_code => "US", :identifier => "987654321"},
162
+ {:country_code => "CL", :identifier => "123456789"}
163
+ ],
164
+ )
165
+
166
+ result.should be_success
167
+ end
168
+
117
169
  it "can create without any attributes" do
118
170
  result = Braintree::Customer.create
119
171
  result.success?.should == true
@@ -969,6 +1021,15 @@ describe Braintree::Customer do
969
1021
  apple_pay_card.token.should_not be_nil
970
1022
  apple_pay_card.expiration_year.should_not be_nil
971
1023
  apple_pay_card.payment_instrument_name.should == "AmEx 41002"
1024
+ apple_pay_card.commercial.should_not be_nil
1025
+ apple_pay_card.country_of_issuance.should_not be_nil
1026
+ apple_pay_card.debit.should_not be_nil
1027
+ apple_pay_card.durbin_regulated.should_not be_nil
1028
+ apple_pay_card.healthcare.should_not be_nil
1029
+ apple_pay_card.issuing_bank.should_not be_nil
1030
+ apple_pay_card.payroll.should_not be_nil
1031
+ apple_pay_card.prepaid.should_not be_nil
1032
+ apple_pay_card.product_id.should_not be_nil
972
1033
  end
973
1034
 
974
1035
  it "returns associated google pay proxy cards" do
@@ -985,6 +1046,15 @@ describe Braintree::Customer do
985
1046
  google_pay_card.token.should_not be_nil
986
1047
  google_pay_card.expiration_year.should_not be_nil
987
1048
  google_pay_card.is_network_tokenized?.should == false
1049
+ google_pay_card.commercial.should_not be_nil
1050
+ google_pay_card.country_of_issuance.should_not be_nil
1051
+ google_pay_card.debit.should_not be_nil
1052
+ google_pay_card.durbin_regulated.should_not be_nil
1053
+ google_pay_card.healthcare.should_not be_nil
1054
+ google_pay_card.issuing_bank.should_not be_nil
1055
+ google_pay_card.payroll.should_not be_nil
1056
+ google_pay_card.prepaid.should_not be_nil
1057
+ google_pay_card.product_id.should_not be_nil
988
1058
  end
989
1059
 
990
1060
  it "returns associated google pay network tokens" do
@@ -1001,6 +1071,15 @@ describe Braintree::Customer do
1001
1071
  google_pay_card.token.should_not be_nil
1002
1072
  google_pay_card.expiration_year.should_not be_nil
1003
1073
  google_pay_card.is_network_tokenized?.should == true
1074
+ google_pay_card.commercial.should_not be_nil
1075
+ google_pay_card.country_of_issuance.should_not be_nil
1076
+ google_pay_card.debit.should_not be_nil
1077
+ google_pay_card.durbin_regulated.should_not be_nil
1078
+ google_pay_card.healthcare.should_not be_nil
1079
+ google_pay_card.issuing_bank.should_not be_nil
1080
+ google_pay_card.payroll.should_not be_nil
1081
+ google_pay_card.prepaid.should_not be_nil
1082
+ google_pay_card.product_id.should_not be_nil
1004
1083
  end
1005
1084
 
1006
1085
  it "returns associated venmo accounts" do
@@ -1333,6 +1412,71 @@ describe Braintree::Customer do
1333
1412
  result.success?.should == true
1334
1413
  end
1335
1414
 
1415
+ it "includes risk data when skip_advanced_fraud_checking is false" do
1416
+ with_fraud_protection_enterprise_merchant do
1417
+ customer = Braintree::Customer.create!(
1418
+ :first_name => "Joe",
1419
+ )
1420
+
1421
+ updated_result = Braintree::Customer.update(
1422
+ customer.id,
1423
+ :credit_card => {
1424
+ :cardholder_name => "New Joe Cardholder",
1425
+ :number => Braintree::Test::CreditCardNumbers::Visa,
1426
+ :expiration_date => "12/2009",
1427
+ :options => {
1428
+ :skip_advanced_fraud_checking => false,
1429
+ :verify_card => true,
1430
+ },
1431
+ },
1432
+ )
1433
+
1434
+ expect(updated_result).to be_success
1435
+ verification = updated_result.customer.credit_cards.first.verification
1436
+ expect(verification.risk_data).not_to be_nil
1437
+ end
1438
+ end
1439
+
1440
+ it "does not include risk data when skip_advanced_fraud_checking is true" do
1441
+ with_fraud_protection_enterprise_merchant do
1442
+ customer = Braintree::Customer.create!(
1443
+ :first_name => "Joe",
1444
+ )
1445
+
1446
+ updated_result = Braintree::Customer.update(
1447
+ customer.id,
1448
+ :credit_card => {
1449
+ :cardholder_name => "New Joe Cardholder",
1450
+ :number => Braintree::Test::CreditCardNumbers::Visa,
1451
+ :expiration_date => "12/2009",
1452
+ :options => {
1453
+ :skip_advanced_fraud_checking => true,
1454
+ :verify_card => true,
1455
+ },
1456
+ },
1457
+ )
1458
+
1459
+ expect(updated_result).to be_success
1460
+ verification = updated_result.customer.credit_cards.first.verification
1461
+ expect(verification.risk_data).to be_nil
1462
+ end
1463
+ end
1464
+
1465
+ it "can update a tax_identifier" do
1466
+ customer = Braintree::Customer.create!(
1467
+ :tax_identifiers => [
1468
+ {:country_code => "US", :identifier => "987654321"},
1469
+ {:country_code => "CL", :identifier => "123456789"}
1470
+ ],
1471
+ )
1472
+
1473
+ result = Braintree::Customer.update(
1474
+ customer.id,
1475
+ :tax_identifiers => [{:country_code => "US", :identifier => "567891234"}],
1476
+ )
1477
+ result.success?.should == true
1478
+ end
1479
+
1336
1480
  it "validates presence of three_d_secure_version in 3ds pass thru params" do
1337
1481
  result = Braintree::Customer.create(
1338
1482
  :payment_method_nonce => Braintree::Test::Nonce::ThreeDSecureVisaFullAuthentication,