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.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/lib/braintree/address_gateway.rb +5 -0
  3. data/lib/braintree/apple_pay_card.rb +6 -0
  4. data/lib/braintree/bank_account_instant_verification_gateway.rb +38 -0
  5. data/lib/braintree/bank_account_instant_verification_jwt.rb +23 -0
  6. data/lib/braintree/bank_account_instant_verification_jwt_request.rb +21 -0
  7. data/lib/braintree/bin_data.rb +8 -2
  8. data/lib/braintree/configuration.rb +1 -1
  9. data/lib/braintree/credit_card.rb +12 -5
  10. data/lib/braintree/credit_card_gateway.rb +1 -0
  11. data/lib/braintree/credit_card_verification_gateway.rb +5 -2
  12. data/lib/braintree/customer_session_gateway.rb +195 -0
  13. data/lib/braintree/dispute.rb +1 -0
  14. data/lib/braintree/error_codes.rb +58 -104
  15. data/lib/braintree/error_result.rb +1 -1
  16. data/lib/braintree/errors.rb +2 -1
  17. data/lib/braintree/gateway.rb +12 -0
  18. data/lib/braintree/google_pay_card.rb +5 -0
  19. data/lib/braintree/graphql/enums/recommendations.rb +9 -0
  20. data/lib/braintree/graphql/enums/recommended_payment_option.rb +10 -0
  21. data/lib/braintree/graphql/inputs/create_customer_session_input.rb +44 -0
  22. data/lib/braintree/graphql/inputs/customer_recommendations_input.rb +40 -0
  23. data/lib/braintree/graphql/inputs/customer_session_input.rb +45 -0
  24. data/lib/braintree/graphql/inputs/monetary_amount_input.rb +28 -0
  25. data/lib/braintree/graphql/inputs/paypal_payee_input.rb +28 -0
  26. data/lib/braintree/graphql/inputs/paypal_purchase_unit_input.rb +31 -0
  27. data/lib/braintree/graphql/inputs/phone_input.rb +34 -0
  28. data/lib/braintree/graphql/inputs/update_customer_session_input.rb +42 -0
  29. data/lib/braintree/graphql/types/customer_recommendations_payload.rb +129 -0
  30. data/lib/braintree/graphql/types/payment_options.rb +35 -0
  31. data/lib/braintree/graphql/types/payment_recommendations.rb +35 -0
  32. data/lib/braintree/graphql/unions/customer_recommendations.rb +47 -0
  33. data/lib/braintree/graphql_client.rb +16 -0
  34. data/lib/braintree/merchant_account.rb +1 -25
  35. data/lib/braintree/merchant_account_gateway.rb +0 -81
  36. data/lib/braintree/meta_checkout_card.rb +11 -6
  37. data/lib/braintree/meta_checkout_token.rb +11 -6
  38. data/lib/braintree/payment_method_gateway.rb +9 -0
  39. data/lib/braintree/paypal_payment_resource.rb +22 -0
  40. data/lib/braintree/paypal_payment_resource_gateway.rb +36 -0
  41. data/lib/braintree/successful_result.rb +3 -0
  42. data/lib/braintree/test/credit_card.rb +5 -0
  43. data/lib/braintree/transaction/apple_pay_details.rb +7 -0
  44. data/lib/braintree/transaction/credit_card_details.rb +22 -10
  45. data/lib/braintree/transaction/google_pay_details.rb +16 -10
  46. data/lib/braintree/transaction/meta_checkout_card_details.rb +11 -2
  47. data/lib/braintree/transaction/meta_checkout_token_details.rb +13 -3
  48. data/lib/braintree/transaction/paypal_details.rb +2 -0
  49. data/lib/braintree/transaction/visa_checkout_card_details.rb +10 -2
  50. data/lib/braintree/transaction.rb +3 -26
  51. data/lib/braintree/transaction_gateway.rb +52 -31
  52. data/lib/braintree/us_bank_account_verification.rb +3 -1
  53. data/lib/braintree/version.rb +1 -1
  54. data/lib/braintree/visa_checkout_card.rb +10 -5
  55. data/lib/braintree/webhook_notification.rb +1 -4
  56. data/lib/braintree/webhook_testing_gateway.rb +16 -33
  57. data/lib/braintree/xml/{libxml.rb → nokogiri.rb} +18 -16
  58. data/lib/braintree/xml/parser.rb +4 -4
  59. data/lib/braintree.rb +21 -4
  60. data/spec/integration/braintree/advanced_search_spec.rb +7 -4
  61. data/spec/integration/braintree/apple_pay_spec.rb +6 -7
  62. data/spec/integration/braintree/bank_account_instant_verification_spec.rb +191 -0
  63. data/spec/integration/braintree/client_api/spec_helper.rb +81 -0
  64. data/spec/integration/braintree/credit_card_spec.rb +115 -1
  65. data/spec/integration/braintree/credit_card_verification_spec.rb +149 -0
  66. data/spec/integration/braintree/customer_session_spec.rb +154 -0
  67. data/spec/integration/braintree/customer_spec.rb +94 -10
  68. data/spec/integration/braintree/disbursement_spec.rb +1 -1
  69. data/spec/integration/braintree/dispute_spec.rb +13 -2
  70. data/spec/integration/braintree/merchant_account_spec.rb +19 -359
  71. data/spec/integration/braintree/merchant_spec.rb +4 -4
  72. data/spec/integration/braintree/payment_method_nonce_spec.rb +55 -0
  73. data/spec/integration/braintree/payment_method_spec.rb +57 -7
  74. data/spec/integration/braintree/payment_method_us_bank_account_spec.rb +0 -3
  75. data/spec/integration/braintree/paypal_payment_resource_spec.rb +141 -0
  76. data/spec/integration/braintree/transaction_payment_facilitator_spec.rb +119 -0
  77. data/spec/integration/braintree/transaction_search_spec.rb +38 -33
  78. data/spec/integration/braintree/transaction_spec.rb +266 -350
  79. data/spec/integration/braintree/transaction_transfer_type_spec.rb +325 -0
  80. data/spec/integration/braintree/transaction_us_bank_account_spec.rb +0 -1
  81. data/spec/integration/braintree/us_bank_account_spec.rb +0 -3
  82. data/spec/integration/braintree/us_bank_account_verification_spec.rb +1 -1
  83. data/spec/spec_helper.rb +46 -12
  84. data/spec/unit/braintree/apple_pay_card_spec.rb +7 -0
  85. data/spec/unit/braintree/bank_account_instant_verification_gateway_spec.rb +98 -0
  86. data/spec/unit/braintree/bank_account_instant_verification_jwt_request_spec.rb +71 -0
  87. data/spec/unit/braintree/client_token_spec.rb +11 -0
  88. data/spec/unit/braintree/configuration_spec.rb +1 -1
  89. data/spec/unit/braintree/credit_card_spec.rb +27 -2
  90. data/spec/unit/braintree/credit_card_verification_gateway_spec.rb +1 -0
  91. data/spec/unit/braintree/credit_card_verification_spec.rb +17 -0
  92. data/spec/unit/braintree/customer_session_gateway_spec.rb +122 -0
  93. data/spec/unit/braintree/customer_spec.rb +2 -1
  94. data/spec/unit/braintree/dispute_spec.rb +6 -0
  95. data/spec/unit/braintree/error_result_spec.rb +28 -0
  96. data/spec/unit/braintree/google_pay_card_spec.rb +28 -0
  97. data/spec/unit/braintree/graphql/create_customer_session_input_spec.rb +102 -0
  98. data/spec/unit/braintree/graphql/customer_recommendations_input_spec.rb +80 -0
  99. data/spec/unit/braintree/graphql/customer_recommendations_spec.rb +40 -0
  100. data/spec/unit/braintree/graphql/customer_session_input_spec.rb +81 -0
  101. data/spec/unit/braintree/graphql/phone_input_spec.rb +51 -0
  102. data/spec/unit/braintree/graphql/update_customer_session_input_spec.rb +107 -0
  103. data/spec/unit/braintree/graphql_client_spec.rb +37 -0
  104. data/spec/unit/braintree/meta_checkout_card_spec.rb +61 -51
  105. data/spec/unit/braintree/meta_checkout_token_spec.rb +7 -1
  106. data/spec/unit/braintree/payment_method_nonce_spec.rb +11 -1
  107. data/spec/unit/braintree/payment_method_spec.rb +12 -0
  108. data/spec/unit/braintree/paypal_payment_resource_spec.rb +125 -0
  109. data/spec/unit/braintree/transaction/apple_pay_details_spec.rb +37 -0
  110. data/spec/unit/braintree/transaction/credit_card_details_spec.rb +15 -1
  111. data/spec/unit/braintree/transaction/google_pay_details_spec.rb +37 -0
  112. data/spec/unit/braintree/transaction/meta_checkout_card_details_spec.rb +28 -0
  113. data/spec/unit/braintree/transaction/meta_checkout_token_details_spec.rb +28 -0
  114. data/spec/unit/braintree/transaction/paypal_details_spec.rb +5 -0
  115. data/spec/unit/braintree/transaction/visa_checkout_card_details_spec.rb +28 -0
  116. data/spec/unit/braintree/transaction_ach_mandate_spec.rb +82 -0
  117. data/spec/unit/braintree/transaction_gateway_spec.rb +58 -11
  118. data/spec/unit/braintree/transaction_spec.rb +66 -0
  119. data/spec/unit/braintree/visa_checkout_card_spec.rb +28 -0
  120. data/spec/unit/braintree/webhook_notification_spec.rb +15 -51
  121. data/spec/unit/braintree/xml/{libxml_spec.rb → nokogiri_spec.rb} +7 -7
  122. data/spec/unit/braintree/xml/parser_spec.rb +57 -0
  123. data/spec/unit/credit_card_details_spec.rb +28 -0
  124. metadata +49 -10
  125. data/lib/braintree/merchant_account/business_details.rb +0 -17
  126. data/lib/braintree/merchant_account/funding_details.rb +0 -18
  127. data/lib/braintree/merchant_account/individual_details.rb +0 -20
  128. data/lib/ssl/securetrust_ca.crt +0 -44
  129. data/spec/unit/braintree/disbursement_spec.rb +0 -131
  130. data/spec/unit/braintree/merchant_account_spec.rb +0 -33
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Braintree::MetaCheckoutCardDetails do
4
+ it "initializes prepaid reloadable correctly" do
5
+ card = Braintree::MetaCheckoutCardDetails._new(:gateway, {:prepaid_reloadable => "No"})
6
+ expect(card.prepaid_reloadable).to eq("No")
7
+ end
8
+
9
+ it "initializes business correctly" do
10
+ card = Braintree::MetaCheckoutCardDetails._new(:gateway, {:business => "No"})
11
+ expect(card.business).to eq("No")
12
+ end
13
+
14
+ it "initializes consumer correctly" do
15
+ card = Braintree::MetaCheckoutCardDetails._new(:gateway, {:consumer => "No"})
16
+ expect(card.consumer).to eq("No")
17
+ end
18
+
19
+ it "initializes corporate correctly" do
20
+ card = Braintree::MetaCheckoutCardDetails._new(:gateway, {:corporate => "No"})
21
+ expect(card.corporate).to eq("No")
22
+ end
23
+
24
+ it "initializes purchase correctly" do
25
+ card = Braintree::MetaCheckoutCardDetails._new(:gateway, {:purchase => "No"})
26
+ expect(card.purchase).to eq("No")
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Braintree::MetaCheckoutTokenDetails do
4
+ it "initializes prepaid reloadable correctly" do
5
+ card = Braintree::MetaCheckoutTokenDetails._new(:gateway, {:prepaid_reloadable => "No"})
6
+ expect(card.prepaid_reloadable).to eq("No")
7
+ end
8
+
9
+ it "initializes business correctly" do
10
+ card = Braintree::MetaCheckoutTokenDetails._new(:gateway, {:business => "No"})
11
+ expect(card.business).to eq("No")
12
+ end
13
+
14
+ it "initializes consumer correctly" do
15
+ card = Braintree::MetaCheckoutTokenDetails._new(:gateway, {:consumer => "No"})
16
+ expect(card.consumer).to eq("No")
17
+ end
18
+
19
+ it "initializes corporate correctly" do
20
+ card = Braintree::MetaCheckoutTokenDetails._new(:gateway, {:corporate => "No"})
21
+ expect(card.corporate).to eq("No")
22
+ end
23
+
24
+ it "initializes purchase correctly" do
25
+ card = Braintree::MetaCheckoutTokenDetails._new(:gateway, {:purchase => "No"})
26
+ expect(card.purchase).to eq("No")
27
+ end
28
+ end
@@ -21,6 +21,8 @@ describe Braintree::Transaction::PayPalDetails do
21
21
  :payer_last_name => "Hopper",
22
22
  :payer_status =>"status",
23
23
  :payment_id => "payment-id",
24
+ :recipient_email => "test@paypal.com",
25
+ :recipient_phone => [:country_code => "1", :national_number => "4082222222"],
24
26
  :refund_from_transaction_fee_amount => "1.00",
25
27
  :refund_from_transaction_fee_currency_iso_code => "123",
26
28
  :refund_id => "refund-id",
@@ -49,6 +51,9 @@ describe Braintree::Transaction::PayPalDetails do
49
51
  expect(details.payer_last_name).to eq("Hopper")
50
52
  expect(details.payer_status).to eq("status")
51
53
  expect(details.payment_id).to eq("payment-id")
54
+ expect(details.recipient_email).to eq("test@paypal.com")
55
+ expect(details.recipient_phone.country_code).to eq("1")
56
+ expect(details.recipient_phone.national_number).to eq("4082222222")
52
57
  expect(details.refund_from_transaction_fee_amount).to eq("1.00")
53
58
  expect(details.refund_from_transaction_fee_currency_iso_code).to eq("123")
54
59
  expect(details.refund_id).to eq("refund-id")
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Braintree::VisaCheckoutCardDetails do
4
+ it "initializes prepaid reloadable correctly" do
5
+ card = Braintree::VisaCheckoutCardDetails._new(:gateway, {:prepaid_reloadable => "No"})
6
+ expect(card.prepaid_reloadable).to eq("No")
7
+ end
8
+
9
+ it "initializes business correctly" do
10
+ card = Braintree::VisaCheckoutCardDetails._new(:gateway, {:business => "No"})
11
+ expect(card.business).to eq("No")
12
+ end
13
+
14
+ it "initializes consumer correctly" do
15
+ card = Braintree::VisaCheckoutCardDetails._new(:gateway, {:consumer => "No"})
16
+ expect(card.consumer).to eq("No")
17
+ end
18
+
19
+ it "initializes corporate correctly" do
20
+ card = Braintree::VisaCheckoutCardDetails._new(:gateway, {:corporate => "No"})
21
+ expect(card.corporate).to eq("No")
22
+ end
23
+
24
+ it "initializes purchase correctly" do
25
+ card = Braintree::VisaCheckoutCardDetails._new(:gateway, {:purchase => "No"})
26
+ expect(card.purchase).to eq("No")
27
+ end
28
+ end
@@ -0,0 +1,82 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe "Transaction ACH Mandate" do
4
+ describe "transaction request handling" do
5
+ let(:gateway) { Braintree::Gateway.new(:environment => :sandbox, :merchant_id => "test", :public_key => "test", :private_key => "test") }
6
+ let(:transaction_gateway) { gateway.transaction }
7
+
8
+ it "processes us_bank_account ACH mandate fields" do
9
+ mandate_time = Time.now
10
+
11
+ # Mock the HTTP response for transaction creation
12
+ allow(gateway.config.http).to receive(:post).and_return({
13
+ :transaction => {
14
+ :id => "test_transaction_id",
15
+ :amount => "100.00",
16
+ :status => "authorized",
17
+ :us_bank_account => {
18
+ :token => "test_token",
19
+ :ach_mandate => {
20
+ :text => "I authorize this ACH debit",
21
+ :accepted_at => mandate_time.iso8601
22
+ }
23
+ }
24
+ }
25
+ })
26
+
27
+ transaction_attributes = {
28
+ :amount => "100.00",
29
+ :payment_method_token => "test_token",
30
+ :us_bank_account => {
31
+ :ach_mandate_text => "I authorize this ACH debit",
32
+ :ach_mandate_accepted_at => mandate_time
33
+ }
34
+ }
35
+
36
+ # This should not raise an error due to signature validation
37
+ expect {
38
+ Braintree::Util.verify_keys(Braintree::TransactionGateway._create_signature, transaction_attributes)
39
+ }.not_to raise_error
40
+ end
41
+
42
+ it "allows ACH mandate text only" do
43
+ transaction_attributes = {
44
+ :amount => "50.00",
45
+ :payment_method_token => "test_token",
46
+ :us_bank_account => {
47
+ :ach_mandate_text => "I authorize this ACH debit"
48
+ }
49
+ }
50
+
51
+ expect {
52
+ Braintree::Util.verify_keys(Braintree::TransactionGateway._create_signature, transaction_attributes)
53
+ }.not_to raise_error
54
+ end
55
+
56
+ it "allows ACH mandate accepted_at only" do
57
+ transaction_attributes = {
58
+ :amount => "50.00",
59
+ :payment_method_token => "test_token",
60
+ :us_bank_account => {
61
+ :ach_mandate_accepted_at => Time.now
62
+ }
63
+ }
64
+
65
+ expect {
66
+ Braintree::Util.verify_keys(Braintree::TransactionGateway._create_signature, transaction_attributes)
67
+ }.not_to raise_error
68
+ end
69
+
70
+ it "allows empty us_bank_account hash" do
71
+ transaction_attributes = {
72
+ :amount => "50.00",
73
+ :payment_method_token => "test_token",
74
+ :us_bank_account => {}
75
+ }
76
+
77
+ expect {
78
+ Braintree::Util.verify_keys(Braintree::TransactionGateway._create_signature, transaction_attributes)
79
+ }.not_to raise_error
80
+ end
81
+ end
82
+ end
@@ -35,7 +35,7 @@ describe Braintree::TransactionGateway do
35
35
  expect(Braintree::TransactionGateway._create_signature).to match([
36
36
  :amount, :billing_address_id, :channel, :currency_iso_code, :customer_id, :device_data,
37
37
  :discount_amount, :exchange_rate_quote_id, :foreign_retailer,
38
- :merchant_account_id, :order_id, :payment_method_nonce, :payment_method_token,
38
+ :merchant_account_id, :order_id, :payment_method_nonce, :payment_method_token, :processing_merchant_category_code,
39
39
  :product_sku, :purchase_order_number, :service_fee_amount, :shared_billing_address_id,
40
40
  :shared_customer_id, :shared_payment_method_nonce, :shared_payment_method_token,
41
41
  :shared_shipping_address_id, :shipping_address_id, :shipping_amount, :shipping_tax_amount,
@@ -73,27 +73,46 @@ describe Braintree::TransactionGateway do
73
73
  {:installments => [:count]},
74
74
  {:line_items => [:commodity_code, :description, :discount_amount, :image_url, :kind, :name, :product_code, :quantity, :tax_amount, :total_amount, :unit_amount, :unit_of_measure, :unit_tax_amount, :upc_code, :upc_type, :url]},
75
75
  {:options => [
76
- :hold_in_escrow,
77
- :store_in_vault,
78
- :store_in_vault_on_success,
79
- :submit_for_settlement,
80
76
  :add_billing_address_to_payment_method,
81
- :store_shipping_address_in_vault,
82
- :venmo_sdk_session, # Deprecated
77
+ {:amex_rewards => [:request_id, :points, :currency_amount, :currency_iso_code]},
78
+ {:credit_card => [:account_type, :process_debit_as_credit]},
79
+ :hold_in_escrow,
83
80
  :payee_id,
84
81
  :payee_email,
82
+ {:paypal => [:custom_field, :description, :payee_id, :payee_email, :recipient_email, {:recipient_phone => [:country_code, :national_number]}, {:supplementary_data => :_any_key_}]},
83
+ {:processing_overrides => [:customer_email, :customer_first_name, :customer_last_name, :customer_tax_identifier]},
85
84
  :skip_advanced_fraud_checking,
86
85
  :skip_avs,
87
86
  :skip_cvv,
88
- {:paypal => [:custom_field, :payee_id, :payee_email, :description, {:supplementary_data => :_any_key_}]},
89
- {:processing_overrides => [:customer_email, :customer_first_name, :customer_last_name, :customer_tax_identifier]},
87
+ :store_in_vault,
88
+ :store_in_vault_on_success,
89
+ :store_shipping_address_in_vault,
90
+ :submit_for_settlement,
90
91
  {:three_d_secure => [:required]},
91
- {:amex_rewards => [:request_id, :points, :currency_amount, :currency_iso_code]},
92
92
  {:venmo => [:profile_id]},
93
- {:credit_card => [:account_type, :process_debit_as_credit]},
93
+ :venmo_sdk_session, # Deprecated
94
94
  ]
95
95
  },
96
96
  {:paypal_account => [:email, :token, :paypal_data, :payee_id, :payee_email, :payer_id, :payment_id]},
97
+ {:payment_facilitator => [
98
+ :payment_facilitator_id,
99
+ {:sub_merchant => [
100
+ :reference_number,
101
+ :tax_id,
102
+ :legal_name,
103
+ {:address => [
104
+ :street_address,
105
+ :locality,
106
+ :region,
107
+ :country_code_alpha2,
108
+ :postal_code,
109
+ {:international_phone => [
110
+ :country_code,
111
+ :national_number
112
+ ]}
113
+ ]}
114
+ ]}
115
+ ]},
97
116
  {:risk_data => [:customer_browser, :customer_device_id, :customer_ip, :customer_location_zip, :customer_tenure]},
98
117
  {
99
118
  :shipping => Braintree::AddressGateway._shared_signature + [:shipping_method],
@@ -110,6 +129,34 @@ describe Braintree::TransactionGateway do
110
129
  :ds_transaction_id,
111
130
  ]
112
131
  },
132
+ {
133
+ :transfer => [
134
+ :type,
135
+ {:sender => [
136
+ :account_reference_number,
137
+ :date_of_birth,
138
+ :first_name,
139
+ :last_name,
140
+ :middle_name,
141
+ :tax_id,
142
+ :address => Braintree::AddressGateway._address_attributes
143
+ ]},
144
+ {:receiver => [
145
+ :account_reference_number,
146
+ :first_name,
147
+ :last_name,
148
+ :middle_name,
149
+ :tax_id,
150
+ :address => Braintree::AddressGateway._address_attributes
151
+ ]},
152
+ ]
153
+ },
154
+ {
155
+ :us_bank_account => [
156
+ :ach_mandate_text,
157
+ :ach_mandate_accepted_at,
158
+ ]
159
+ },
113
160
  ])
114
161
  end
115
162
 
@@ -119,12 +119,17 @@ describe Braintree::Transaction do
119
119
  :expiration_year => "2009",
120
120
  :customer_location => "US",
121
121
  :prepaid => "Yes",
122
+ :prepaid_reloadable => "Yes",
122
123
  :healthcare => "Yes",
123
124
  :durbin_regulated => "Yes",
124
125
  :debit => "Yes",
126
+ :business => "Yes",
125
127
  :commercial => "No",
128
+ :consumer => "No",
129
+ :corporate => "No",
126
130
  :payroll => "Unknown",
127
131
  :product_id => "Unknown",
132
+ :purchase => "No",
128
133
  :country_of_issuance => "Narnia",
129
134
  :issuing_bank => "Mr Tumnus"
130
135
  },
@@ -137,16 +142,59 @@ describe Braintree::Transaction do
137
142
  expect(transaction.credit_card_details.expiration_year).to eq("2009")
138
143
  expect(transaction.credit_card_details.customer_location).to eq("US")
139
144
  expect(transaction.credit_card_details.prepaid).to eq(Braintree::CreditCard::Prepaid::Yes)
145
+ expect(transaction.credit_card_details.prepaid_reloadable).to eq(Braintree::CreditCard::PrepaidReloadable::Yes)
140
146
  expect(transaction.credit_card_details.healthcare).to eq(Braintree::CreditCard::Healthcare::Yes)
141
147
  expect(transaction.credit_card_details.durbin_regulated).to eq(Braintree::CreditCard::DurbinRegulated::Yes)
142
148
  expect(transaction.credit_card_details.debit).to eq(Braintree::CreditCard::Debit::Yes)
149
+ expect(transaction.credit_card_details.business).to eq(Braintree::CreditCard::Business::Yes)
143
150
  expect(transaction.credit_card_details.commercial).to eq(Braintree::CreditCard::Commercial::No)
151
+ expect(transaction.credit_card_details.consumer).to eq(Braintree::CreditCard::Consumer::No)
152
+ expect(transaction.credit_card_details.corporate).to eq(Braintree::CreditCard::Corporate::No)
144
153
  expect(transaction.credit_card_details.payroll).to eq(Braintree::CreditCard::Payroll::Unknown)
145
154
  expect(transaction.credit_card_details.product_id).to eq(Braintree::CreditCard::ProductId::Unknown)
155
+ expect(transaction.credit_card_details.purchase).to eq(Braintree::CreditCard::Purchase::No)
146
156
  expect(transaction.credit_card_details.country_of_issuance).to eq("Narnia")
147
157
  expect(transaction.credit_card_details.issuing_bank).to eq("Mr Tumnus")
148
158
  end
149
159
 
160
+ describe "payment_account_reference in transaction details" do
161
+ it "exposes payment_account_reference in credit_card_details" do
162
+ transaction = Braintree::Transaction._new(
163
+ :gateway,
164
+ :credit_card => {
165
+ :bin => "401288",
166
+ :last_4 => "1881",
167
+ :card_type => "Visa",
168
+ :payment_account_reference => "V0010013019339005665779448477"
169
+ },
170
+ )
171
+ expect(transaction.credit_card_details.payment_account_reference).to eq("V0010013019339005665779448477")
172
+ end
173
+
174
+ it "exposes payment_account_reference in apple_pay_details" do
175
+ transaction = Braintree::Transaction._new(
176
+ :gateway,
177
+ :apple_pay => {
178
+ :payment_instrument_name => "Apple Pay",
179
+ :payment_account_reference => "V0010013019339005665779448477"
180
+ },
181
+ )
182
+ expect(transaction.apple_pay_details.payment_account_reference).to eq("V0010013019339005665779448477")
183
+ end
184
+
185
+ it "exposes payment_account_reference in google_pay_details" do
186
+ transaction = Braintree::Transaction._new(
187
+ :gateway,
188
+ :android_pay_card => {
189
+ :virtual_card_type => "Visa",
190
+ :payment_account_reference => "V0010013019339005665779448477"
191
+ },
192
+ )
193
+ expect(transaction.google_pay_details.payment_account_reference).to eq("V0010013019339005665779448477")
194
+ end
195
+
196
+ end
197
+
150
198
  it "sets up network token attributes in network_token_details" do
151
199
  transaction = Braintree::Transaction._new(
152
200
  :gateway,
@@ -257,6 +305,14 @@ describe Braintree::Transaction do
257
305
  expect(transaction.retried_transaction_id).to eq("original_retried_tranction_id")
258
306
  end
259
307
 
308
+ it "accepts upcoming_retry_date attribute in a transaction" do
309
+ transaction = Braintree::Transaction._new(
310
+ :gateway,
311
+ :upcoming_retry_date => "2024-12-25",
312
+ )
313
+ expect(transaction.upcoming_retry_date).to eq("2024-12-25")
314
+ end
315
+
260
316
  it "handles receiving custom as an empty string" do
261
317
  Braintree::Transaction._new(
262
318
  :gateway,
@@ -299,6 +355,16 @@ describe Braintree::Transaction do
299
355
  expect(transaction.ach_return_code).to eq("R01")
300
356
  end
301
357
 
358
+ it "accepts ach_reject_reason" do
359
+ transaction = Braintree::Transaction._new(
360
+ :gateway,
361
+ :ach_return_code => "RJCT",
362
+ :ach_reject_reason => "some reject reason",
363
+ )
364
+ expect(transaction.ach_return_code).to eq("RJCT")
365
+ expect(transaction.ach_reject_reason).to eq("some reject reason")
366
+ end
367
+
302
368
  it "accepts network_response code and network_response_text" do
303
369
  transaction = Braintree::Transaction._new(
304
370
  :gateway,
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Braintree::VisaCheckoutCard do
4
+ it "initializes prepaid reloadable correctly" do
5
+ card = Braintree::VisaCheckoutCard._new(:gateway, {:prepaid_reloadable => "No"})
6
+ expect(card.prepaid_reloadable).to eq("No")
7
+ end
8
+
9
+ it "initializes business correctly" do
10
+ card = Braintree::VisaCheckoutCard._new(:gateway, {:business => "No"})
11
+ expect(card.business).to eq("No")
12
+ end
13
+
14
+ it "initializes consumer correctly" do
15
+ card = Braintree::VisaCheckoutCard._new(:gateway, {:consumer => "No"})
16
+ expect(card.consumer).to eq("No")
17
+ end
18
+
19
+ it "initializes corporate correctly" do
20
+ card = Braintree::VisaCheckoutCard._new(:gateway, {:corporate => "No"})
21
+ expect(card.corporate).to eq("No")
22
+ end
23
+
24
+ it "initializes purchase correctly" do
25
+ card = Braintree::VisaCheckoutCard._new(:gateway, {:purchase => "No"})
26
+ expect(card.purchase).to eq("No")
27
+ end
28
+ end
@@ -310,42 +310,40 @@ describe Braintree::WebhookNotification do
310
310
  expect(notification.transaction.disbursement_details.disbursement_date).to eq(Date.parse("2013-07-09"))
311
311
  end
312
312
 
313
- it "builds a sample notification for a disbursement_exception webhook" do
313
+ it "builds a sample notification for a disbursement webhook" do
314
314
  sample_notification = Braintree::WebhookTesting.sample_notification(
315
- Braintree::WebhookNotification::Kind::DisbursementException,
315
+ Braintree::WebhookNotification::Kind::Disbursement,
316
316
  "my_id",
317
317
  )
318
318
 
319
319
  notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
320
320
 
321
- expect(notification.kind).to eq(Braintree::WebhookNotification::Kind::DisbursementException)
321
+ expect(notification.kind).to eq(Braintree::WebhookNotification::Kind::Disbursement)
322
322
  expect(notification.disbursement.id).to eq("my_id")
323
323
  expect(notification.disbursement.transaction_ids).to eq(%W{ afv56j kj8hjk })
324
324
  expect(notification.disbursement.retry).to be(false)
325
- expect(notification.disbursement.success).to be(false)
326
- expect(notification.disbursement.exception_message).to eq("bank_rejected")
325
+ expect(notification.disbursement.success).to be(true)
326
+ expect(notification.disbursement.exception_message).to be_nil
327
327
  expect(notification.disbursement.disbursement_date).to eq(Date.parse("2014-02-10"))
328
- expect(notification.disbursement.follow_up_action).to eq("update_funding_information")
328
+ expect(notification.disbursement.follow_up_action).to be_nil
329
329
  expect(notification.disbursement.merchant_account.id).to eq("merchant_account_token")
330
330
  end
331
+ end
331
332
 
332
- it "builds a sample notification for a disbursement webhook" do
333
+ context "transaction retried" do
334
+ it "builds a sample notification for a transaction retried webhook" do
333
335
  sample_notification = Braintree::WebhookTesting.sample_notification(
334
- Braintree::WebhookNotification::Kind::Disbursement,
336
+ Braintree::WebhookNotification::Kind::TransactionRetried,
335
337
  "my_id",
336
338
  )
337
339
 
338
340
  notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
339
341
 
340
- expect(notification.kind).to eq(Braintree::WebhookNotification::Kind::Disbursement)
341
- expect(notification.disbursement.id).to eq("my_id")
342
- expect(notification.disbursement.transaction_ids).to eq(%W{ afv56j kj8hjk })
343
- expect(notification.disbursement.retry).to be(false)
344
- expect(notification.disbursement.success).to be(true)
345
- expect(notification.disbursement.exception_message).to be_nil
346
- expect(notification.disbursement.disbursement_date).to eq(Date.parse("2014-02-10"))
347
- expect(notification.disbursement.follow_up_action).to be_nil
348
- expect(notification.disbursement.merchant_account.id).to eq("merchant_account_token")
342
+ expect(notification.kind).to eq(Braintree::WebhookNotification::Kind::TransactionRetried)
343
+ expect(notification.transaction.id).to eq("my_id")
344
+ expect(notification.transaction.amount).to eq(1_00)
345
+ expect(notification.transaction.status).to eq("submitted_for_settlement")
346
+ expect(notification.transaction.retried_transaction_id).to eq("original_txn_id")
349
347
  end
350
348
  end
351
349
 
@@ -403,40 +401,6 @@ describe Braintree::WebhookNotification do
403
401
  end
404
402
  end
405
403
 
406
- context "merchant account" do
407
- it "builds a sample notification for a merchant account approved webhook" do
408
- sample_notification = Braintree::WebhookTesting.sample_notification(
409
- Braintree::WebhookNotification::Kind::SubMerchantAccountApproved,
410
- "my_id",
411
- )
412
-
413
- notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
414
-
415
- expect(notification.kind).to eq(Braintree::WebhookNotification::Kind::SubMerchantAccountApproved)
416
- expect(notification.merchant_account.id).to eq("my_id")
417
- expect(notification.merchant_account.status).to eq(Braintree::MerchantAccount::Status::Active)
418
- expect(notification.merchant_account.master_merchant_account.id).to eq("master_ma_for_my_id")
419
- expect(notification.merchant_account.master_merchant_account.status).to eq(Braintree::MerchantAccount::Status::Active)
420
- end
421
-
422
- it "builds a sample notification for a merchant account declined webhook" do
423
- sample_notification = Braintree::WebhookTesting.sample_notification(
424
- Braintree::WebhookNotification::Kind::SubMerchantAccountDeclined,
425
- "my_id",
426
- )
427
-
428
- notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
429
-
430
- expect(notification.kind).to eq(Braintree::WebhookNotification::Kind::SubMerchantAccountDeclined)
431
- expect(notification.merchant_account.id).to eq("my_id")
432
- expect(notification.merchant_account.status).to eq(Braintree::MerchantAccount::Status::Suspended)
433
- expect(notification.merchant_account.master_merchant_account.id).to eq("master_ma_for_my_id")
434
- expect(notification.merchant_account.master_merchant_account.status).to eq(Braintree::MerchantAccount::Status::Suspended)
435
- expect(notification.message).to eq("Credit score is too low")
436
- expect(notification.errors.for(:merchant_account).on(:base).first.code).to eq(Braintree::ErrorCodes::MerchantAccount::DeclinedOFAC)
437
- end
438
- end
439
-
440
404
  context "subscription" do
441
405
  it "builds a sample notification for a subscription billing skipped webhook" do
442
406
  sample_notification = Braintree::WebhookTesting.sample_notification(
@@ -1,10 +1,10 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
2
2
 
3
- describe Braintree::Xml::Libxml do
3
+ describe Braintree::Xml::Nokogiri do
4
4
  describe "self.parse" do
5
5
  it "typecasts integers" do
6
6
  xml = "<root><foo type=\"integer\">123</foo></root>"
7
- expect(Braintree::Xml::Libxml.parse(xml)).to eq({"root"=>{"foo"=>{"__content__"=>"123", "type"=>"integer"}}})
7
+ expect(Braintree::Xml::Nokogiri.parse(xml)).to eq({"root"=>{"foo"=>{"__content__"=>"123", "type"=>"integer"}}})
8
8
  end
9
9
 
10
10
  it "works with dashes or underscores" do
@@ -14,7 +14,7 @@ describe Braintree::Xml::Libxml do
14
14
  <under_scores />
15
15
  </root>
16
16
  END
17
- expect(Braintree::Xml::Libxml.parse(xml)).to eq({"root"=>{"dash-es"=>{}, "under_scores"=>{}}})
17
+ expect(Braintree::Xml::Nokogiri.parse(xml)).to eq({"root"=>{"dash-es"=>{}, "under_scores"=>{}}})
18
18
  end
19
19
 
20
20
  it "uses nil if nil=true, otherwise uses empty string" do
@@ -24,7 +24,7 @@ describe Braintree::Xml::Libxml do
24
24
  <an_empty_string></an_empty_string>
25
25
  </root>
26
26
  END
27
- expect(Braintree::Xml::Libxml.parse(xml)).to eq({"root"=>{"a_nil_value"=>{"nil"=>"true"}, "an_empty_string"=>{}}})
27
+ expect(Braintree::Xml::Nokogiri.parse(xml)).to eq({"root"=>{"a_nil_value"=>{"nil"=>"true"}, "an_empty_string"=>{}}})
28
28
  end
29
29
 
30
30
  it "typecasts dates and times" do
@@ -33,7 +33,7 @@ describe Braintree::Xml::Libxml do
33
33
  <created-at type="datetime">2009-10-28T10:19:49Z</created-at>
34
34
  </root>
35
35
  END
36
- expect(Braintree::Xml::Libxml.parse(xml)).to eq({"root"=>{"created-at"=>{"__content__"=>"2009-10-28T10:19:49Z", "type"=>"datetime"}}})
36
+ expect(Braintree::Xml::Nokogiri.parse(xml)).to eq({"root"=>{"created-at"=>{"__content__"=>"2009-10-28T10:19:49Z", "type"=>"datetime"}}})
37
37
  end
38
38
 
39
39
  it "builds an array if type=array" do
@@ -45,7 +45,7 @@ describe Braintree::Xml::Libxml do
45
45
  </customers>
46
46
  </root>
47
47
  END
48
- expect(Braintree::Xml::Libxml.parse(xml)).to eq({"root"=>{"customers"=>{"type"=>"array", "customer"=>[{"name"=>{"__content__"=>"Adam"}}, {"name"=>{"__content__"=>"Ben"}}]}}})
48
+ expect(Braintree::Xml::Nokogiri.parse(xml)).to eq({"root"=>{"customers"=>{"type"=>"array", "customer"=>[{"name"=>{"__content__"=>"Adam"}}, {"name"=>{"__content__"=>"Ben"}}]}}})
49
49
  end
50
50
  end
51
- end
51
+ end
@@ -81,5 +81,62 @@ describe Braintree::Xml::Parser do
81
81
  END
82
82
  expect(xml).to parse_to(:root => {:paypal_details => {:deets => [{:secret_code => "1234"}], :payer_email => "abc@test.com", :payment_id => "1234567890"}})
83
83
  end
84
+
85
+ it "does not collapse nested structures with single-child elements" do
86
+ xml = "<api-error-response><message>Test</message><errors><errors type=\"array\"></errors></errors></api-error-response>"
87
+ expect(xml).to parse_to({:api_error_response=>{:message=>"Test", :errors=>{:errors=>[]}}})
88
+ end
89
+
90
+ it "preserves hash structure when one key has array value" do
91
+ xml = <<-END
92
+ <root>
93
+ <message>Error message</message>
94
+ <items type="array">
95
+ <item>Value1</item>
96
+ </items>
97
+ </root>
98
+ END
99
+ expect(xml).to parse_to({:root => {:message => "Error message", :items => ["Value1"]}})
100
+ end
101
+
102
+ it "handles error response with nested errors correctly" do
103
+ xml = <<-END
104
+ <api-error-response>
105
+ <message>Validation failed</message>
106
+ <errors>
107
+ <errors type="array">
108
+ <error>
109
+ <code>81234</code>
110
+ <message>Field is required</message>
111
+ </error>
112
+ </errors>
113
+ </errors>
114
+ </api-error-response>
115
+ END
116
+ expect(xml).to parse_to({
117
+ :api_error_response => {
118
+ :message => "Validation failed",
119
+ :errors => {
120
+ :errors => [{:code => "81234", :message => "Field is required"}]
121
+ }
122
+ }
123
+ })
124
+ end
125
+
126
+ it "handles client token error response structure" do
127
+ xml = <<-END
128
+ <api-error-response>
129
+ <message>Invalid request</message>
130
+ <errors>
131
+ <errors type="array"></errors>
132
+ </errors>
133
+ </api-error-response>
134
+ END
135
+ result = Braintree::Xml::Parser.hash_from_xml(xml)
136
+ expect(result[:api_error_response]).to be_a(Hash)
137
+ expect(result[:api_error_response][:message]).to eq("Invalid request")
138
+ expect(result[:api_error_response][:errors]).to be_a(Hash)
139
+ expect(result[:api_error_response][:errors][:errors]).to eq([])
140
+ end
84
141
  end
85
142
  end