braintree 4.7.0 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb259ba1474b20f411b4046f978a7397599c88217b9f1b1a41a969036ca350fa
4
- data.tar.gz: 4d5dbdf190c5088dca938bf4ecae614db1d1e94f9eb921284523b604686667c9
3
+ metadata.gz: 67348684ea4b3f86ef0063df5559298bf7563901010c0d68ee5fce5a64710c4c
4
+ data.tar.gz: 3b32cd4ccfe99e604a42a871003e38fa1679afd62bd8a44ffca6e7524dc30e85
5
5
  SHA512:
6
- metadata.gz: 8b09ef27dc9c38dd0fc3fb03ec487f7d52112629043af3fb4c760274b267767f08e2b1052bbb2d4f67d0ebade4fe7dae0dfde850a3eca1e0114a15219f988204
7
- data.tar.gz: 6f5223eb5b90f99f9381245a580f766383102146daa4e095cf1e7f413f592ba9fac78f8cdd67b59a149d4c0a0a9c02d80f3a2650fa2187e2eab54443a24bd045
6
+ metadata.gz: 8f7f99a0d53c1e98faf5e0ef34fd47bee88be1a366412d267ada59d309b93d9119fcef2f2c0c535305a7de9340a044ddaf73550f72b69e0ab1e5ff403debf20e
7
+ data.tar.gz: ede1ae81a11c86079c8a7cd2f62673c4bbfefe5ef273bfb899d81583a302e39cb289fd9c1fdd5dfe83e573c55db6ff1ebf041a460f9a0089850b59468979b75a
@@ -0,0 +1,13 @@
1
+ module Braintree
2
+ class ExchangeRate
3
+ include BaseModule # :nodoc:
4
+
5
+ def initialize(gateway, attributes) # :nodoc:
6
+ set_instance_variables_from_hash(attributes)
7
+ end
8
+
9
+ def self.generate(exchange_rate_quote_request)
10
+ Configuration.gateway.exchange_rate_quote.generate(exchange_rate_quote_request)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ module Braintree
2
+ class ExchangeRateQuote
3
+ include BaseModule # :nodoc:
4
+
5
+ attr_reader :attrs
6
+ attr_reader :base_amount
7
+ attr_reader :exchange_rate
8
+ attr_reader :expires_at
9
+ attr_reader :id
10
+ attr_reader :quote_amount
11
+ attr_reader :refreshes_at
12
+ attr_reader :trade_rate
13
+
14
+ def initialize(attributes) # :nodoc:
15
+ @attrs = attributes.keys
16
+ set_instance_variables_from_hash(attributes)
17
+ end
18
+
19
+ def inspect # :nodoc:
20
+ inspected_attributes = @attrs.map { |attr| "#{attr}:#{send(attr).inspect}" }
21
+ "#<#{self.class} #{inspected_attributes.join(" ")}>"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ module Braintree
2
+ class ExchangeRateQuoteGateway # :nodoc
3
+ def initialize(gateway)
4
+ @gateway = gateway
5
+ end
6
+
7
+ DEFINITION = <<-GRAPHQL
8
+ mutation GenerateExchangeRateQuoteInput($input: GenerateExchangeRateQuoteInput!) {
9
+ generateExchangeRateQuote(input: $input) {
10
+ quotes {
11
+ id
12
+ baseAmount {value, currencyCode}
13
+ quoteAmount {value, currencyCode}
14
+ exchangeRate
15
+ tradeRate
16
+ expiresAt
17
+ refreshesAt
18
+ }
19
+ }
20
+ }
21
+ GRAPHQL
22
+
23
+ def generate(params)
24
+ response = @gateway.config.graphql_client.query(DEFINITION, {input: params})
25
+
26
+ if response.has_key?(:data) && response[:data][:generateExchangeRateQuote]
27
+ response[:data][:generateExchangeRateQuote]
28
+ elsif response[:errors]
29
+ ErrorResult.new(@gateway, response[:errors])
30
+ else
31
+ raise UnexpectedError, "expected :generateExchangeRateQuote or :api_error_response in GraphQL response"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ module Braintree
2
+ class ExchangeRateQuoteInput
3
+ include BaseModule # :nodoc:
4
+
5
+ attr_reader :attrs
6
+ attr_reader :base_currency
7
+ attr_reader :base_amount
8
+ attr_reader :markup
9
+ attr_reader :quote_currency
10
+
11
+ def initialize(attributes) # :nodoc:
12
+ @attrs = attributes.keys
13
+ set_instance_variables_from_hash(attributes)
14
+ end
15
+
16
+ def inspect # :nodoc:
17
+ inspected_attributes = @attrs.map { |attr| "#{attr}:#{send(attr).inspect}" }
18
+ "#<#{self.class} #{inspected_attributes.join(" ")}>"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module Braintree
2
+ class ExchangeRateQuoteRequest
3
+ include BaseModule # :nodoc:
4
+
5
+ attr_reader :quotes
6
+
7
+ def initialize(attributes) # :nodoc:
8
+ @attrs = attributes.keys
9
+ set_instance_variables_from_hash(attributes)
10
+ @quotes = (@quotes || []).map { |quote_hash| ExchangeRateQuoteInput.new(quote_hash) }
11
+ end
12
+
13
+ def inspect # :nodoc:
14
+ inspected_attributes = @attrs.map { |attr| "#{attr}:#{send(attr).inspect}" }
15
+ "#<#{self.class} #{inspected_attributes.join(" ")}>"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module Braintree
2
+ class ExchangeRateQuoteResponse
3
+ include BaseModule # :nodoc:
4
+
5
+ attr_reader :quotes
6
+
7
+ def initialize(attributes) # :nodoc:
8
+ @attrs = attributes.keys
9
+ set_instance_variables_from_hash(attributes)
10
+ @quotes = (@quotes || []).map { |quote_hash| ExchangeRateQuote.new(quote_hash) }
11
+ end
12
+
13
+ def inspect # :nodoc:
14
+ inspected_attributes = @attrs.map { |attr| "#{attr}:#{send(attr).inspect}" }
15
+ "#<#{self.class} #{inspected_attributes.join(" ")}>"
16
+ end
17
+ end
18
+ end
@@ -50,6 +50,10 @@ module Braintree
50
50
  DocumentUploadGateway.new(self)
51
51
  end
52
52
 
53
+ def exchange_rate_quote
54
+ ExchangeRateQuoteGateway.new(self)
55
+ end
56
+
53
57
  def oauth
54
58
  OAuthGateway.new(self)
55
59
  end
@@ -106,10 +106,10 @@ module Braintree
106
106
  response = @config.http.post("#{@config.base_merchant_path}#{path}", params)
107
107
  if response[:plan]
108
108
  SuccessfulResult.new(:plan => Plan._new(@gateway, response[:plan]))
109
- elsif response[:errors]
110
- ErrorResult.new(@gateway, response[:errors])
109
+ elsif response[:api_error_response]
110
+ ErrorResult.new(@gateway, response[:api_error_response])
111
111
  else
112
- raise UnexpectedError, "expected :plan or :errors"
112
+ raise UnexpectedError, "expected :plan or :api_error_response"
113
113
  end
114
114
  end
115
115
  end
@@ -0,0 +1,22 @@
1
+ module Braintree
2
+ class RiskData
3
+ class LiabilityShift
4
+ include BaseModule
5
+
6
+ attr_reader :responsible_party
7
+ attr_reader :conditions
8
+
9
+ def initialize(attributes)
10
+ set_instance_variables_from_hash attributes unless attributes.nil?
11
+ end
12
+
13
+ def inspect
14
+ attr_order = [:responsible_party, :conditions]
15
+ formatted_attrs = attr_order.map do |attr|
16
+ "#{attr}: #{send(attr).inspect}"
17
+ end
18
+ "#<LiabilityShift #{formatted_attrs.join(", ")}>"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -10,14 +10,16 @@ module Braintree
10
10
  attr_reader :device_data_captured
11
11
  attr_reader :fraud_service_provider
12
12
  attr_reader :id
13
+ attr_reader :liability_shift
13
14
  attr_reader :transaction_risk_score
14
15
 
15
16
  def initialize(attributes)
16
17
  set_instance_variables_from_hash attributes unless attributes.nil?
18
+ @liability_shift = LiabilityShift.new(attributes[:liability_shift]) if attributes[:liability_shift]
17
19
  end
18
20
 
19
21
  def inspect
20
- attr_order = [:id, :decision, :decision_reasons, :device_data_captured, :fraud_service_provider, :transaction_risk_score]
22
+ attr_order = [:id, :decision, :decision_reasons, :device_data_captured, :fraud_service_provider, :liability_shift, :transaction_risk_score]
21
23
  formatted_attrs = attr_order.map do |attr|
22
24
  "#{attr}: #{send(attr).inspect}"
23
25
  end
@@ -6,10 +6,12 @@ module Braintree
6
6
  attr_reader :apple_pay_options
7
7
  attr_reader :credentials
8
8
  attr_reader :credit_card
9
+ attr_reader :credit_card_verification
9
10
  attr_reader :customer
10
11
  attr_reader :disputes
11
12
  attr_reader :document_upload
12
13
  attr_reader :evidence
14
+ attr_reader :exchange_rate_quote_payload
13
15
  attr_reader :merchant
14
16
  attr_reader :merchant_account
15
17
  attr_reader :merchant_accounts
@@ -22,7 +24,6 @@ module Braintree
22
24
  attr_reader :supported_networks
23
25
  attr_reader :transaction
24
26
  attr_reader :us_bank_account_verification
25
- attr_reader :credit_card_verification
26
27
 
27
28
  def initialize(attributes = {}) # :nodoc:
28
29
  @attrs = attributes.keys
@@ -170,6 +170,7 @@ module Braintree
170
170
  attr_reader :venmo_account_details
171
171
  attr_reader :visa_checkout_card_details
172
172
  attr_reader :voice_referral_number
173
+ attr_reader :ach_return_responses
173
174
 
174
175
  def self.adjust_authorization(*args)
175
176
  Configuration.gateway.transaction.adjust_authorization(*args)
@@ -290,38 +291,40 @@ module Braintree
290
291
  def initialize(gateway, attributes) # :nodoc:
291
292
  @gateway = gateway
292
293
  set_instance_variables_from_hash(attributes)
294
+
293
295
  @amount = Util.to_big_decimal(amount)
296
+ @apple_pay_details = ApplePayDetails.new(@apple_pay)
297
+ @billing_details = AddressDetails.new(@billing)
294
298
  @credit_card_details = CreditCardDetails.new(@credit_card)
295
- @service_fee_amount = Util.to_big_decimal(service_fee_amount)
296
- @subscription_details = SubscriptionDetails.new(@subscription)
299
+ @custom_fields = attributes[:custom_fields].is_a?(Hash) ? attributes[:custom_fields] : {}
297
300
  @customer_details = CustomerDetails.new(@customer)
298
- @billing_details = AddressDetails.new(@billing)
299
- @disbursement_details = DisbursementDetails.new(@disbursement_details)
300
- @shipping_details = AddressDetails.new(@shipping)
301
- @status_history = attributes[:status_history] ? attributes[:status_history].map { |s| StatusDetails.new(s) } : []
302
- @tax_amount = Util.to_big_decimal(tax_amount)
303
301
  @descriptor = Descriptor.new(@descriptor)
302
+ @disbursement_details = DisbursementDetails.new(@disbursement_details)
303
+ @google_pay_details = GooglePayDetails.new(@google_pay_card)
304
304
  @local_payment_details = LocalPaymentDetails.new(@local_payment)
305
+ @payment_instrument_type = attributes[:payment_instrument_type]
305
306
  @paypal_details = PayPalDetails.new(@paypal)
306
307
  @paypal_here_details = PayPalHereDetails.new(@paypal_here)
307
- @apple_pay_details = ApplePayDetails.new(@apple_pay)
308
- @google_pay_details = GooglePayDetails.new(@google_pay_card)
308
+ @samsung_pay_card_details = SamsungPayCardDetails.new(attributes[:samsung_pay_card])
309
+ @sca_exemption_requested = attributes[:sca_exemption_requested]
310
+ @service_fee_amount = Util.to_big_decimal(service_fee_amount)
311
+ @shipping_details = AddressDetails.new(@shipping)
312
+ @status_history = attributes[:status_history] ? attributes[:status_history].map { |s| StatusDetails.new(s) } : []
313
+ @subscription_details = SubscriptionDetails.new(@subscription)
314
+ @tax_amount = Util.to_big_decimal(tax_amount)
309
315
  @venmo_account_details = VenmoAccountDetails.new(@venmo_account)
310
- disputes.map! { |attrs| Dispute._new(attrs) } if disputes
311
- @custom_fields = attributes[:custom_fields].is_a?(Hash) ? attributes[:custom_fields] : {}
312
- add_ons.map! { |attrs| AddOn._new(attrs) } if add_ons
313
- discounts.map! { |attrs| Discount._new(attrs) } if discounts
314
- @payment_instrument_type = attributes[:payment_instrument_type]
315
- @risk_data = RiskData.new(attributes[:risk_data]) if attributes[:risk_data]
316
+ @visa_checkout_card_details = VisaCheckoutCardDetails.new(attributes[:visa_checkout_card])
317
+
316
318
  @facilitated_details = FacilitatedDetails.new(attributes[:facilitated_details]) if attributes[:facilitated_details]
317
319
  @facilitator_details = FacilitatorDetails.new(attributes[:facilitator_details]) if attributes[:facilitator_details]
320
+ @risk_data = RiskData.new(attributes[:risk_data]) if attributes[:risk_data]
318
321
  @three_d_secure_info = ThreeDSecureInfo.new(attributes[:three_d_secure_info]) if attributes[:three_d_secure_info]
319
322
  @us_bank_account_details = UsBankAccountDetails.new(attributes[:us_bank_account]) if attributes[:us_bank_account]
320
- @visa_checkout_card_details = VisaCheckoutCardDetails.new(attributes[:visa_checkout_card])
321
- @samsung_pay_card_details = SamsungPayCardDetails.new(attributes[:samsung_pay_card])
322
- @sca_exemption_requested = attributes[:sca_exemption_requested]
323
- authorization_adjustments.map! { |attrs| AuthorizationAdjustment._new(attrs) } if authorization_adjustments
324
323
 
324
+ add_ons.map! { |attrs| AddOn._new(attrs) } if add_ons
325
+ authorization_adjustments.map! { |attrs| AuthorizationAdjustment._new(attrs) } if authorization_adjustments
326
+ discounts.map! { |attrs| Discount._new(attrs) } if discounts
327
+ disputes.map! { |attrs| Dispute._new(attrs) } if disputes
325
328
  installments.map! { |attrs| Installment.new(attrs) } if installments
326
329
  refunded_installments.map! { |attrs| Installment.new(attrs) } if refunded_installments
327
330
  end
@@ -61,12 +61,13 @@ module Braintree
61
61
  multiple_value_field :source
62
62
  multiple_value_field :type, :allows => Transaction::Type::All
63
63
  multiple_value_field :store_ids
64
+ multiple_value_field :reason_code
64
65
 
65
66
  key_value_fields :refund
66
67
 
67
68
  range_fields :amount, :created_at, :authorization_expired_at, :authorized_at,
68
69
  :failed_at, :gateway_rejected_at, :processor_declined_at,
69
70
  :settled_at, :submitted_for_settlement_at, :voided_at,
70
- :disbursement_date, :dispute_date
71
+ :disbursement_date, :dispute_date, :ach_return_responses_created_at
71
72
  end
72
73
  end
@@ -1,7 +1,7 @@
1
1
  module Braintree
2
2
  module Version
3
3
  Major = 4
4
- Minor = 7
4
+ Minor = 8
5
5
  Tiny = 0
6
6
 
7
7
  String = "#{Major}.#{Minor}.#{Tiny}"
data/lib/braintree.rb CHANGED
@@ -69,6 +69,12 @@ require "braintree/enriched_customer_data"
69
69
  require "braintree/error_codes"
70
70
  require "braintree/error_result"
71
71
  require "braintree/errors"
72
+ require "braintree/exchange_rate"
73
+ require "braintree/exchange_rate_quote"
74
+ require "braintree/exchange_rate_quote_gateway"
75
+ require "braintree/exchange_rate_quote_input"
76
+ require "braintree/exchange_rate_quote_response"
77
+ require "braintree/exchange_rate_quote_request"
72
78
  require "braintree/gateway"
73
79
  require "braintree/graphql_client"
74
80
  require "braintree/google_pay_card"
@@ -102,6 +108,7 @@ require "braintree/plan"
102
108
  require "braintree/plan_gateway"
103
109
  require "braintree/processor_response_types"
104
110
  require "braintree/risk_data"
111
+ require "braintree/risk_data/liability_shift"
105
112
  require "braintree/facilitated_details"
106
113
  require "braintree/facilitator_details"
107
114
  require "braintree/three_d_secure_info"
@@ -130,27 +137,27 @@ require "braintree/test/venmo_sdk"
130
137
  require "braintree/test/nonce"
131
138
  require "braintree/test/transaction_amounts"
132
139
  require "braintree/testing_gateway"
133
- require "braintree/transaction"
134
- require "braintree/transaction_line_item"
135
140
  require "braintree/test_transaction"
141
+ require "braintree/transaction"
136
142
  require "braintree/transaction/address_details"
137
143
  require "braintree/transaction/apple_pay_details"
138
144
  require "braintree/transaction/credit_card_details"
139
145
  require "braintree/transaction/customer_details"
140
146
  require "braintree/transaction/disbursement_details"
141
147
  require "braintree/transaction/google_pay_details"
148
+ require "braintree/transaction/installment"
149
+ require "braintree/transaction/installment/adjustment"
142
150
  require "braintree/transaction/paypal_details"
143
151
  require "braintree/transaction/paypal_here_details"
152
+ require "braintree/transaction/samsung_pay_card_details"
153
+ require "braintree/transaction/status_details"
144
154
  require "braintree/transaction/subscription_details"
155
+ require "braintree/transaction/venmo_account_details"
156
+ require "braintree/transaction/visa_checkout_card_details"
145
157
  require "braintree/transaction_gateway"
158
+ require "braintree/transaction_line_item"
146
159
  require "braintree/transaction_line_item_gateway"
147
160
  require "braintree/transaction_search"
148
- require "braintree/transaction/status_details"
149
- require "braintree/transaction/venmo_account_details"
150
- require "braintree/transaction/visa_checkout_card_details"
151
- require "braintree/transaction/samsung_pay_card_details"
152
- require "braintree/transaction/installment"
153
- require "braintree/transaction/installment/adjustment"
154
161
  require "braintree/unknown_payment_method"
155
162
  require "braintree/disbursement"
156
163
  require "braintree/dispute_search"
@@ -0,0 +1,97 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
2
+ require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
3
+
4
+ describe Braintree::ExchangeRateQuoteGateway do
5
+ let(:gateway) do
6
+ Braintree::Gateway.new(
7
+ :environment => :development,
8
+ :merchant_id => "integration_merchant_id",
9
+ :public_key => "integration_public_key",
10
+ :private_key => "integration_private_key",
11
+ )
12
+ end
13
+
14
+ describe "generate" do
15
+ def quote_input_request
16
+ gateway.exchange_rate_quote.generate({quotes: [quote_input]})
17
+ end
18
+
19
+ let(:quote_input) do
20
+ {
21
+ :baseCurrency => "EUR",
22
+ :quoteCurrency => "GBP",
23
+ :baseAmount => "20.00",
24
+ :markup => "4.00"
25
+ }
26
+ end
27
+
28
+ it "generates exchange rate quotes" do
29
+ result = quote_input_request
30
+ quotes = result[:quotes]
31
+
32
+ expect(quotes[0][:id]).not_to be_nil
33
+ expect(quotes[0][:baseAmount]).not_to be_nil
34
+ expect(quotes[0][:quoteAmount]).not_to be_nil
35
+ expect(quotes[0][:exchangeRate]).not_to be_nil
36
+ expect(quotes[0][:expiresAt]).not_to be_nil
37
+ expect(quotes[0][:refreshesAt]).not_to be_nil
38
+
39
+ expect(quotes[1][:id]).not_to be_nil
40
+ expect(quotes[1][:baseAmount]).not_to be_nil
41
+ expect(quotes[1][:quoteAmount]).not_to be_nil
42
+ expect(quotes[1][:exchangeRate]).not_to be_nil
43
+ expect(quotes[1][:expiresAt]).not_to be_nil
44
+ expect(quotes[1][:refreshesAt]).not_to be_nil
45
+ end
46
+
47
+ context "when base currency input param is not passed" do
48
+ let(:quote_input) do
49
+ {
50
+ :quoteCurrency => "GBP",
51
+ :baseAmount => "20.00",
52
+ :markup => "4.00"
53
+ }
54
+ end
55
+ let(:error_message) { "baseCurrency" }
56
+
57
+ it "raises an UnexpectedError" do
58
+ expect do
59
+ quote_input_request
60
+ end.to raise_error(Braintree::UnexpectedError, /#{error_message}/)
61
+ end
62
+ end
63
+
64
+ context "when quote currency input param is not passed" do
65
+ let(:quote_input) do
66
+ {
67
+ :baseCurrency => "GBP",
68
+ :baseAmount => "20.00",
69
+ :markup => "4.00"
70
+ }
71
+ end
72
+ let(:error_message) { "quoteCurrency" }
73
+
74
+ it "raises an UnexpectedError" do
75
+ expect do
76
+ quote_input_request
77
+ end.to raise_error(Braintree::UnexpectedError, /#{error_message}/)
78
+ end
79
+ end
80
+
81
+ context "when base and quote currency input params are not passed" do
82
+ let(:quote_input) do
83
+ {
84
+ :baseAmount => "20.00",
85
+ :markup => "4.00"
86
+ }
87
+ end
88
+ let(:error_message) { "baseCurrency" }
89
+
90
+ it "raises an UnexpectedError" do
91
+ expect do
92
+ quote_input_request
93
+ end.to raise_error(Braintree::UnexpectedError, /#{error_message}/)
94
+ end
95
+ end
96
+ end
97
+ end
@@ -28,7 +28,6 @@ describe Braintree::GraphQLClient do
28
28
  definition = <<-GRAPHQL
29
29
  mutation CreateClientToken($input: CreateClientTokenInput!) {
30
30
  createClientToken(input: $input) {
31
- clientMutationId
32
31
  clientToken
33
32
  }
34
33
  }
@@ -36,7 +35,6 @@ mutation CreateClientToken($input: CreateClientTokenInput!) {
36
35
 
37
36
  variables = {
38
37
  input: {
39
- clientMutationId: "abc123",
40
38
  clientToken: {
41
39
  merchantAccountId: "ABC123"
42
40
  }
@@ -174,6 +174,29 @@ describe Braintree::Transaction, "search" do
174
174
  collection.first.id.should == transaction_id
175
175
  end
176
176
 
177
+ it "searches on reason_code" do
178
+ transaction_id = "ach_txn_ret1"
179
+ reason_code = "R01"
180
+
181
+ collection = Braintree::Transaction.search do |search|
182
+ search.reason_code.in reason_code
183
+ end
184
+
185
+ collection.maximum_size.should == 1
186
+ collection.first.id.should == transaction_id
187
+ collection.first.ach_return_responses.first[:reason_code].should == "R01"
188
+ end
189
+
190
+ it "searches on reason_codes" do
191
+ reason_code = "any_reason_code"
192
+
193
+ collection = Braintree::Transaction.search do |search|
194
+ search.reason_code.is reason_code
195
+ end
196
+
197
+ collection.maximum_size.should == 2
198
+ end
199
+
177
200
  context "multiple value fields" do
178
201
  it "searches on created_using" do
179
202
  transaction = Braintree::Transaction.sale!(
@@ -532,6 +555,29 @@ describe Braintree::Transaction, "search" do
532
555
  collection.maximum_size.should == 1
533
556
  collection.first.id.should == transaction_id
534
557
  end
558
+
559
+ it "searches on reason_codes for 2 items" do
560
+ reason_code = ["R01", "R02"]
561
+
562
+ collection = Braintree::Transaction.search do |search|
563
+ search.reason_code.in reason_code
564
+ end
565
+
566
+ collection.maximum_size.should == 2
567
+ end
568
+
569
+ it "searches on a reason_code" do
570
+ reason_code = ["R01"]
571
+ transaction_id = "ach_txn_ret1"
572
+
573
+ collection = Braintree::Transaction.search do |search|
574
+ search.reason_code.in reason_code
575
+ end
576
+
577
+ collection.maximum_size.should == 1
578
+ collection.first.id.should == transaction_id
579
+ end
580
+
535
581
  end
536
582
 
537
583
  context "invalid search" do
@@ -736,6 +782,28 @@ describe Braintree::Transaction, "search" do
736
782
  end
737
783
  end
738
784
 
785
+ context "ach return response created at" do
786
+ it "it finds records within date range of the custom field" do
787
+ reason_code = "any_reason_code"
788
+
789
+ date_search = Braintree::Transaction.search do |search|
790
+ search.ach_return_responses_created_at.between(DateTime.now - 1.0, DateTime.now + 1.0)
791
+ end
792
+
793
+ date_search.maximum_size.should == 2
794
+ end
795
+
796
+ it "it does not find records not within date range of the custom field" do
797
+ reason_code = "any_reason_code"
798
+
799
+ neg_date_search = Braintree::Transaction.search do |search|
800
+ search.ach_return_responses_created_at.between(DateTime.now + 1.0, DateTime.now - 1.0)
801
+ end
802
+
803
+ neg_date_search.maximum_size.should == 0
804
+ end
805
+ end
806
+
739
807
  context "disbursement_date" do
740
808
  it "searches on disbursement_date in UTC, as a date" do
741
809
  disbursement_time = Date.parse("2013-04-10")
@@ -133,16 +133,36 @@ describe Braintree::Transaction do
133
133
  :expiration_date => "05/2009"
134
134
  },
135
135
  )
136
- result.transaction.risk_data.should be_a(Braintree::RiskData)
137
- result.transaction.risk_data.id.should_not be_nil
138
- result.transaction.risk_data.decision.should_not be_nil
139
- result.transaction.risk_data.decision_reasons.should_not be_nil
136
+ expect(result.transaction.risk_data).to be_a(Braintree::RiskData)
137
+ expect(result.transaction.risk_data.id).not_to be_nil
138
+ expect(result.transaction.risk_data.decision).not_to be_nil
139
+ expect(result.transaction.risk_data.decision_reasons).not_to be_nil
140
140
  expect(result.transaction.risk_data).to respond_to(:device_data_captured)
141
141
  expect(result.transaction.risk_data).to respond_to(:fraud_service_provider)
142
142
  expect(result.transaction.risk_data).to respond_to(:transaction_risk_score)
143
143
  end
144
144
  end
145
145
 
146
+ it "returns decision, device_data_captured, id, liability_shift, and decision_reasons" do
147
+ with_chargeback_protection_merchant do
148
+ result = Braintree::Transaction.create(
149
+ :type => "sale",
150
+ :amount => 1_00,
151
+ :credit_card => {
152
+ :number => "4111111111111111",
153
+ :expiration_date => "05/2009"
154
+ },
155
+ )
156
+ expect(result.transaction.risk_data).to be_a(Braintree::RiskData)
157
+ expect(result.transaction.risk_data.id).not_to be_nil
158
+ expect(result.transaction.risk_data.decision).not_to be_nil
159
+ expect(result.transaction.risk_data.decision_reasons).not_to be_nil
160
+ expect(result.transaction.risk_data).to respond_to(:device_data_captured)
161
+ expect(result.transaction.risk_data).to respond_to(:fraud_service_provider)
162
+ expect(result.transaction.risk_data).to respond_to(:liability_shift)
163
+ end
164
+ end
165
+
146
166
  it "handles validation errors for invalid risk data attributes" do
147
167
  with_advanced_fraud_kount_integration_merchant do
148
168
  result = Braintree::Transaction.create(
@@ -160,7 +180,7 @@ describe Braintree::Transaction do
160
180
  :customer_tenure => "20#{"0" * 500}"
161
181
  },
162
182
  )
163
- result.success?.should == false
183
+ expect(result.success?).to eq(false)
164
184
  result.errors.for(:transaction).for(:risk_data).on(:customer_device_id).map { |e| e.code }.should include Braintree::ErrorCodes::RiskData::CustomerDeviceIdIsTooLong
165
185
  result.errors.for(:transaction).for(:risk_data).on(:customer_location_zip).map { |e| e.code }.should include Braintree::ErrorCodes::RiskData::CustomerLocationZipInvalidCharacters
166
186
  result.errors.for(:transaction).for(:risk_data).on(:customer_tenure).map { |e| e.code }.should include Braintree::ErrorCodes::RiskData::CustomerTenureIsTooLong
@@ -54,6 +54,12 @@ unless defined?(INTEGRATION_SPEC_HELPER_LOADED)
54
54
  end
55
55
  end
56
56
 
57
+ def with_chargeback_protection_merchant(&block)
58
+ with_other_merchant("fraud_protection_effortless_chargeback_protection_merchant_id", "effortless_chargeback_protection_public_key", "effortless_chargeback_protection_private_key") do
59
+ block.call
60
+ end
61
+ end
62
+
57
63
  def with_altpay_merchant(&block)
58
64
  with_other_merchant("altpay_merchant", "altpay_merchant_public_key", "altpay_merchant_private_key", &block)
59
65
  end
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Braintree::ExchangeRateQuoteInput do
4
+ let(:exchange_rate_quote_input) do
5
+ {
6
+ base_currency: "USD",
7
+ quote_currency: "EUR",
8
+ base_amount: "10.00",
9
+ markup: "2.00"
10
+ }
11
+ end
12
+
13
+ describe "#initialize" do
14
+ it "initialize and sets the input keys to attrs variable" do
15
+ quote_input = described_class.new(exchange_rate_quote_input)
16
+
17
+ expect(quote_input.attrs).to include(:base_currency)
18
+ expect(quote_input.attrs).to include(:quote_currency)
19
+ expect(quote_input.attrs).to include(:base_amount)
20
+ expect(quote_input.attrs).to include(:markup)
21
+ expect(quote_input.attrs.length).to eq(4)
22
+ end
23
+ end
24
+
25
+ describe "inspect" do
26
+ it "includes the base_currency first" do
27
+ output = described_class.new(base_currency: "USD").inspect
28
+
29
+ expect(output).to include("#<Braintree::ExchangeRateQuoteInput base_currency:\"USD\">")
30
+ end
31
+
32
+ it "includes all quote input attributes" do
33
+ quote_input = described_class.new(exchange_rate_quote_input)
34
+ output = quote_input.inspect
35
+
36
+ expect(output).to include("base_currency:\"USD\"")
37
+ expect(output).to include("quote_currency:\"EUR\"")
38
+ expect(output).to include("base_amount:\"10.00\"")
39
+ expect(output).to include("markup:\"2.00\"")
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,82 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Braintree::ExchangeRateQuoteRequest do
4
+ describe "#initialize" do
5
+ it "creates and validates the exchange rate quote request" do
6
+ req = Braintree::ExchangeRateQuoteRequest.new(
7
+ :quotes => [
8
+ {
9
+ :base_currency => "USD",
10
+ :quote_currency => "EUR",
11
+ :base_amount => "10.00",
12
+ :markup => "2.00"
13
+ },
14
+ {
15
+ :base_currency => "EUR",
16
+ :quote_currency => "GBP",
17
+ :base_amount => "20.00",
18
+ :markup => "4.00"
19
+ }
20
+ ],
21
+ )
22
+
23
+ expect(req.quotes[0].base_currency).to eq("USD")
24
+ expect(req.quotes[0].quote_currency).to eq("EUR")
25
+ expect(req.quotes[0].base_amount).to eq("10.00")
26
+ expect(req.quotes[0].markup).to eq("2.00")
27
+
28
+ expect(req.quotes[1].base_currency).to eq("EUR")
29
+ expect(req.quotes[1].quote_currency).to eq("GBP")
30
+ expect(req.quotes[1].base_amount).to eq("20.00")
31
+ expect(req.quotes[1].markup).to eq("4.00")
32
+ end
33
+
34
+ it "creates and validates the exchange rate quote request without amount and markup" do
35
+ req = Braintree::ExchangeRateQuoteRequest.new(
36
+ :quotes => [
37
+ {
38
+ :base_currency => "USD",
39
+ :quote_currency => "EUR",
40
+ },
41
+ {
42
+ :base_currency => "EUR",
43
+ :quote_currency => "GBP",
44
+ }
45
+ ],
46
+ )
47
+
48
+ expect(req.quotes[0].base_currency).to eq("USD")
49
+ expect(req.quotes[0].quote_currency).to eq("EUR")
50
+ expect(req.quotes[0].base_amount).to be_nil
51
+ expect(req.quotes[0].markup).to be_nil
52
+
53
+ expect(req.quotes[1].base_currency).to eq("EUR")
54
+ expect(req.quotes[1].quote_currency).to eq("GBP")
55
+ expect(req.quotes[1].base_amount).to be_nil
56
+ expect(req.quotes[1].markup).to be_nil
57
+ end
58
+
59
+ end
60
+
61
+ describe "inspect" do
62
+ it "prints the attributes" do
63
+ exchange_rate_req = Braintree::ExchangeRateQuoteRequest.new(
64
+ :quotes => [
65
+ {
66
+ :base_currency => "USD",
67
+ :quote_currency => "EUR",
68
+ :base_amount => "10.00",
69
+ :markup => "2.00"
70
+ },
71
+ {
72
+ :base_currency => "EUR",
73
+ :quote_currency => "GBP",
74
+ :base_amount => "20.00",
75
+ :markup => "4.00"
76
+ }
77
+ ],
78
+ )
79
+ expect(exchange_rate_req.inspect).to eq(%(#<Braintree::ExchangeRateQuoteRequest quotes:[#<Braintree::ExchangeRateQuoteInput base_currency:"USD" quote_currency:"EUR" base_amount:"10.00" markup:"2.00">, #<Braintree::ExchangeRateQuoteInput base_currency:"EUR" quote_currency:"GBP" base_amount:"20.00" markup:"4.00">]>))
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Braintree::ExchangeRateQuoteResponse do
4
+ describe "#initialize" do
5
+ it "creates and validated the exchange rate quote payload" do
6
+ quote_payload = Braintree::ExchangeRateQuoteResponse.new(
7
+ quotes: [
8
+ {
9
+ :base_amount => "10.00",
10
+ :quote_amount => "9.03",
11
+ :exchange_rate => "0.90"
12
+ },
13
+ {
14
+ :base_amount => "20.00",
15
+ :quote_amount => "18.06",
16
+ :exchange_rate => "0.90"
17
+ }
18
+ ],
19
+ )
20
+
21
+ quote_1 = quote_payload.quotes[0]
22
+ quote_2 = quote_payload.quotes[1]
23
+
24
+ expect(quote_1.base_amount).to eq("10.00")
25
+ expect(quote_1.quote_amount).to eq("9.03")
26
+ expect(quote_1.exchange_rate).to eq("0.90")
27
+
28
+ expect(quote_2.base_amount).to eq("20.00")
29
+ expect(quote_2.quote_amount).to eq("18.06")
30
+ expect(quote_1.exchange_rate).to eq("0.90")
31
+ end
32
+ end
33
+
34
+ describe "inspect" do
35
+ it "prints the attributes" do
36
+ exchange_rate_quote_payload = Braintree::ExchangeRateQuoteResponse.new(
37
+ quotes: [
38
+ {
39
+ :base_amount => "10.00",
40
+ :quote_amount => "9.03"
41
+ },
42
+ {
43
+ :base_amount => "20.00",
44
+ :quote_amount => "18.06"
45
+ }
46
+ ],
47
+ )
48
+
49
+ expect(exchange_rate_quote_payload.inspect).to eq(%(#<Braintree::ExchangeRateQuoteResponse quotes:[#<Braintree::ExchangeRateQuote base_amount:"10.00" quote_amount:"9.03">, #<Braintree::ExchangeRateQuote base_amount:"20.00" quote_amount:"18.06">]>))
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Braintree::ExchangeRateQuote do
4
+ let(:rate_quote) do
5
+ {
6
+ id: "1234",
7
+ base_amount: "10.00",
8
+ exchange_rate: "74",
9
+ quote_amount: "740"
10
+ }
11
+ end
12
+
13
+ describe "#initialize" do
14
+ it "initialize and sets the input keys to attrs variable" do
15
+ quote = described_class.new(rate_quote)
16
+
17
+ expect(quote.attrs).to include(:id)
18
+ expect(quote.attrs).to include(:base_amount)
19
+ expect(quote.attrs).to include(:exchange_rate)
20
+ expect(quote.attrs).to include(:quote_amount)
21
+ expect(quote.attrs.length).to eq(4)
22
+ end
23
+ end
24
+
25
+ describe "inspect" do
26
+ it "includes the id first" do
27
+ output = described_class.new(id: "1234").inspect
28
+
29
+ expect(output).to include("#<Braintree::ExchangeRateQuote id:\"1234\">")
30
+ end
31
+
32
+ it "includes all quote attributes" do
33
+ quote = described_class.new(rate_quote)
34
+ output = quote.inspect
35
+
36
+ expect(output).to include("id:\"1234\"")
37
+ expect(output).to include("base_amount:\"10.00\"")
38
+ expect(output).to include("exchange_rate:\"74\"")
39
+ expect(output).to include("quote_amount:\"740\"")
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe ::Braintree::ExchangeRate do
4
+ let(:rate_quote) do
5
+ {
6
+ id: "1234",
7
+ base_amount: "10.00",
8
+ exchange_rate: "74",
9
+ quote_amount: "740"
10
+ }
11
+ end
12
+
13
+ describe "#initialize" do
14
+ it "initialize and sets the attributes" do
15
+ exchange_rate = described_class.new(:gateway, rate_quote).inspect
16
+
17
+ expect(exchange_rate).to include("@id=\"1234\"")
18
+ expect(exchange_rate).to include("@base_amount=\"10.00\"")
19
+ expect(exchange_rate).to include("@exchange_rate=\"74\"")
20
+ expect(exchange_rate).to include("@quote_amount=\"740\"")
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
2
+
3
+ describe Braintree::Transaction::LiabilityShift do
4
+ describe "#initialize" do
5
+ it "sets responsible party and conditions" do
6
+ liability_shift = Braintree::Transaction::LiabilityShift.new(
7
+ :responsible_party => "paypal",
8
+ :conditions => ["unauthorized","item_not_received"],
9
+ )
10
+
11
+ expect(liability_shift.responsible_party).to eql "paypal"
12
+ expect(liability_shift.conditions.first).to eql "unauthorized"
13
+ end
14
+ end
15
+
16
+ describe "inspect" do
17
+ it "prints the attributes" do
18
+ details = Braintree::Transaction::LiabilityShift.new(
19
+ :responsible_party => "paypal",
20
+ :conditions => ["unauthorized","item_not_received"],
21
+ )
22
+
23
+ expect(details.inspect).to eql %(#<LiabilityShift responsible_party: "paypal", conditions: ["unauthorized", "item_not_received"]>)
24
+ end
25
+ end
26
+ end
@@ -4,12 +4,29 @@ describe Braintree::RiskData do
4
4
  describe "#initialize" do
5
5
  it "sets id, decision, device_data_captured, decision_reasons and transaction_risk_score" do
6
6
  risk_data = Braintree::RiskData.new(:id => "123", :decision => "YOU WON $1000 DOLLARS", :device_data_captured => true, :fraud_service_provider => "fraud_protection", :decision_reasons => ["reason"], :transaction_risk_score => "12")
7
- risk_data.id.should == "123"
8
- risk_data.decision.should == "YOU WON $1000 DOLLARS"
9
- risk_data.device_data_captured.should be_truthy
10
- risk_data.fraud_service_provider.should == "fraud_protection"
11
- risk_data.decision_reasons.should == ["reason"]
12
- risk_data.transaction_risk_score.should == "12"
7
+ expect(risk_data.id).to eql "123"
8
+ expect(risk_data.decision).to eql "YOU WON $1000 DOLLARS"
9
+ expect(risk_data.device_data_captured).to be_truthy
10
+ expect(risk_data.fraud_service_provider).to eql "fraud_protection"
11
+ expect(risk_data.decision_reasons).to eql ["reason"]
12
+ expect(risk_data.transaction_risk_score).to eql "12"
13
+ expect(risk_data.liability_shift).to be_nil
14
+ end
15
+
16
+ it "sets liability shift info" do
17
+ risk_data = Braintree::RiskData.new(
18
+ :id => "123",
19
+ :decision => "YOU WON $1000 DOLLARS",
20
+ :device_data_captured => true,
21
+ :fraud_service_provider => "fraud_protection",
22
+ :decision_reasons => ["reason"],
23
+ :transaction_risk_score => "12",
24
+ :liability_shift => {
25
+ :responsible_party => "paypal",
26
+ :conditions => ["unauthorized"]},
27
+ )
28
+ expect(risk_data.liability_shift.responsible_party).to eql "paypal"
29
+ expect(risk_data.liability_shift.conditions).to eql ["unauthorized"]
13
30
  end
14
31
  end
15
32
 
@@ -23,7 +40,16 @@ describe Braintree::RiskData do
23
40
  :fraud_service_provider => "fraud_protection",
24
41
  :transaction_risk_score => "12",
25
42
  )
26
- details.inspect.should == %(#<RiskData id: "123", decision: "YOU WON $1000 DOLLARS", decision_reasons: ["reason"], device_data_captured: true, fraud_service_provider: "fraud_protection", transaction_risk_score: "12">)
43
+ expect(details.inspect).to eql %(#<RiskData id: "123", decision: "YOU WON $1000 DOLLARS", decision_reasons: ["reason"], device_data_captured: true, fraud_service_provider: "fraud_protection", liability_shift: nil, transaction_risk_score: "12">)
44
+ end
45
+
46
+ it "prints liability shift attributes, too" do
47
+ details = Braintree::RiskData.new(
48
+ :liability_shift => {
49
+ :responsible_party => "paypal",
50
+ :conditions => ["unauthorized"]},
51
+ )
52
+ expect(details.inspect).to eql %(#<RiskData id: nil, decision: nil, decision_reasons: nil, device_data_captured: nil, fraud_service_provider: nil, liability_shift: #<LiabilityShift responsible_party: "paypal", conditions: ["unauthorized"]>, transaction_risk_score: nil>)
27
53
  end
28
54
  end
29
55
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: braintree
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.0
4
+ version: 4.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Braintree
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-01 00:00:00.000000000 Z
11
+ date: 2022-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: builder
@@ -97,6 +97,12 @@ files:
97
97
  - lib/braintree/error_result.rb
98
98
  - lib/braintree/errors.rb
99
99
  - lib/braintree/exceptions.rb
100
+ - lib/braintree/exchange_rate.rb
101
+ - lib/braintree/exchange_rate_quote.rb
102
+ - lib/braintree/exchange_rate_quote_gateway.rb
103
+ - lib/braintree/exchange_rate_quote_input.rb
104
+ - lib/braintree/exchange_rate_quote_request.rb
105
+ - lib/braintree/exchange_rate_quote_response.rb
100
106
  - lib/braintree/facilitated_details.rb
101
107
  - lib/braintree/facilitator_details.rb
102
108
  - lib/braintree/gateway.rb
@@ -138,6 +144,7 @@ files:
138
144
  - lib/braintree/resource_collection.rb
139
145
  - lib/braintree/revoked_payment_method_metadata.rb
140
146
  - lib/braintree/risk_data.rb
147
+ - lib/braintree/risk_data/liability_shift.rb
141
148
  - lib/braintree/samsung_pay_card.rb
142
149
  - lib/braintree/settlement_batch_summary.rb
143
150
  - lib/braintree/settlement_batch_summary_gateway.rb
@@ -226,6 +233,7 @@ files:
226
233
  - spec/integration/braintree/dispute_spec.rb
227
234
  - spec/integration/braintree/document_upload_spec.rb
228
235
  - spec/integration/braintree/error_codes_spec.rb
236
+ - spec/integration/braintree/exchange_rate_quote_spec.rb
229
237
  - spec/integration/braintree/graphql_client_spec.rb
230
238
  - spec/integration/braintree/http_spec.rb
231
239
  - spec/integration/braintree/merchant_account_spec.rb
@@ -275,6 +283,11 @@ files:
275
283
  - spec/unit/braintree/enriched_customer_data_spec.rb
276
284
  - spec/unit/braintree/error_result_spec.rb
277
285
  - spec/unit/braintree/errors_spec.rb
286
+ - spec/unit/braintree/exchange_rate_quote_input_spec.rb
287
+ - spec/unit/braintree/exchange_rate_quote_request_spec.rb
288
+ - spec/unit/braintree/exchange_rate_quote_response_spec.rb
289
+ - spec/unit/braintree/exchange_rate_quote_spec.rb
290
+ - spec/unit/braintree/exchange_rate_spec.rb
278
291
  - spec/unit/braintree/http_spec.rb
279
292
  - spec/unit/braintree/local_payment_completed_spec.rb
280
293
  - spec/unit/braintree/local_payment_expired_spec.rb
@@ -288,6 +301,7 @@ files:
288
301
  - spec/unit/braintree/payment_method_spec.rb
289
302
  - spec/unit/braintree/paypal_account_spec.rb
290
303
  - spec/unit/braintree/resource_collection_spec.rb
304
+ - spec/unit/braintree/risk_data/liability_shift.rb
291
305
  - spec/unit/braintree/risk_data_spec.rb
292
306
  - spec/unit/braintree/sha256_digest_spec.rb
293
307
  - spec/unit/braintree/signature_service_spec.rb
@@ -340,7 +354,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
340
354
  - !ruby/object:Gem::Version
341
355
  version: '0'
342
356
  requirements: []
343
- rubygems_version: 3.3.10
357
+ rubygems_version: 3.3.18
344
358
  signing_key:
345
359
  specification_version: 4
346
360
  summary: Braintree Ruby Server SDK