braintree 4.7.0 → 4.8.0

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