braintree 4.34.0 → 4.36.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/braintree/apple_pay_card.rb +7 -0
  3. data/lib/braintree/apple_pay_gateway.rb +43 -0
  4. data/lib/braintree/base_module.rb +9 -0
  5. data/lib/braintree/credit_card_verification.rb +2 -0
  6. data/lib/braintree/customer.rb +2 -2
  7. data/lib/braintree/customer_gateway.rb +2 -0
  8. data/lib/braintree/error_codes.rb +20 -0
  9. data/lib/braintree/gateway.rb +4 -0
  10. data/lib/braintree/graphql/inputs/billing_address_input.rb +34 -0
  11. data/lib/braintree/graphql/inputs/create_local_payment_context_input.rb +44 -0
  12. data/lib/braintree/graphql/inputs/payer_info_input.rb +38 -0
  13. data/lib/braintree/graphql/inputs/shipping_address_input.rb +34 -0
  14. data/lib/braintree/local_payment_context.rb +108 -0
  15. data/lib/braintree/local_payment_context_gateway.rb +132 -0
  16. data/lib/braintree/local_payment_type.rb +6 -0
  17. data/lib/braintree/merchant_gateway.rb +16 -16
  18. data/lib/braintree/monetary_amount.rb +24 -0
  19. data/lib/braintree/payment_instrument_type.rb +1 -0
  20. data/lib/braintree/payment_method_parser.rb +1 -0
  21. data/lib/braintree/successful_result.rb +1 -0
  22. data/lib/braintree/test/nonce.rb +1 -0
  23. data/lib/braintree/test/transaction_amounts.rb +1 -0
  24. data/lib/braintree/transaction/visa_checkout_card_details.rb +2 -0
  25. data/lib/braintree/transaction.rb +8 -2
  26. data/lib/braintree/transaction_gateway.rb +12 -5
  27. data/lib/braintree/transaction_search.rb +1 -0
  28. data/lib/braintree/validation_error_collection.rb +1 -1
  29. data/lib/braintree/version.rb +1 -1
  30. data/lib/braintree/visa_checkout_card.rb +2 -0
  31. data/lib/braintree.rb +20 -3
  32. data/spec/integration/braintree/customer_spec.rb +550 -16
  33. data/spec/integration/braintree/http_spec.rb +1 -1
  34. data/spec/integration/braintree/local_payment_context_spec.rb +168 -0
  35. data/spec/integration/braintree/merchant_spec.rb +5 -169
  36. data/spec/integration/braintree/payment_method_spec.rb +174 -1
  37. data/spec/integration/braintree/payment_method_us_bank_account_spec.rb +1 -1
  38. data/spec/integration/braintree/test_transaction_spec.rb +6 -6
  39. data/spec/integration/braintree/transaction_idempotency_spec.rb +320 -0
  40. data/spec/integration/braintree/transaction_search_spec.rb +3 -2
  41. data/spec/integration/braintree/transaction_spec.rb +91 -0
  42. data/spec/integration/braintree/transaction_us_bank_account_spec.rb +42 -0
  43. data/spec/integration/braintree/visa_checkout_card_spec.rb +4 -100
  44. data/spec/spec_helper.rb +2 -0
  45. data/spec/unit/braintree/credit_card_verification_spec.rb +1 -1
  46. data/spec/unit/braintree/customer_spec.rb +67 -1
  47. data/spec/unit/braintree/graphql/billing_address_input_spec.rb +68 -0
  48. data/spec/unit/braintree/graphql/create_local_payment_context_input_spec.rb +63 -0
  49. data/spec/unit/braintree/graphql/monetary_amount_input_spec.rb +55 -0
  50. data/spec/unit/braintree/graphql/payer_info_input_spec.rb +92 -0
  51. data/spec/unit/braintree/local_payment_context_gateway_spec.rb +149 -0
  52. data/spec/unit/braintree/local_payment_context_spec.rb +141 -0
  53. data/spec/unit/braintree/monetary_amount_spec.rb +34 -0
  54. data/spec/unit/braintree/three_d_secure_info_spec.rb +3 -1
  55. data/spec/unit/braintree/transaction/apple_pay_details_spec.rb +7 -7
  56. data/spec/unit/braintree/transaction/google_pay_details_spec.rb +7 -7
  57. data/spec/unit/braintree/transaction/meta_checkout_card_details_spec.rb +6 -6
  58. data/spec/unit/braintree/transaction/meta_checkout_token_details_spec.rb +6 -6
  59. data/spec/unit/braintree/transaction/payment_receipt_spec.rb +4 -4
  60. data/spec/unit/braintree/transaction/visa_checkout_card_details_spec.rb +6 -6
  61. data/spec/unit/braintree/transaction_gateway_spec.rb +5 -3
  62. data/spec/unit/braintree/transaction_spec.rb +31 -0
  63. data/spec/unit/braintree/visa_checkout_card_spec.rb +1 -0
  64. data/spec/unit/credit_card_details_spec.rb +6 -6
  65. data/spec/unit/spec_helper.rb +9 -0
  66. metadata +23 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c3d511f196493254353d03633aedd94e6bc5ac4c0d075ab354a19435ca1e223
4
- data.tar.gz: dcfc72a09d796a25d40451abe117dda0ea63a2e53874f45de0ee5546b94fc440
3
+ metadata.gz: bddd5ecd987b2c8f75088ac1877e7273eebe8463165f9c1db10c92f61aa5961a
4
+ data.tar.gz: 7757bdac8b5bf0808812c073b5e8fcd50e759b4078c51c41def3590467651f12
5
5
  SHA512:
6
- metadata.gz: aa45eeeda00fb2a9d9999c8c2d41a3f9ef4385190598ade9d89ca2017222e893b31e9e3104ed81aa6f03a96bd4f9b0e1247b5e948d2687885eac5e5a0dbd7967
7
- data.tar.gz: d554568c2653f57c5b69ce9bec05655d84f8aa01b96357b3effda416bc1c1c3a8da473db9930669e3c65b7165d1b4fe131ca5578ed4f396fab201d61cbdf376c
6
+ metadata.gz: 37bba6f56222e7f56caca748920befd5d8f443669411cd42f998fe9c17d4c381605e50c38732ce5831f1e6368806ddb96ac0baa4438dd3dc34294d63db5cdfde
7
+ data.tar.gz: 7f2ae5944a6e3b08da6df35cb6c26aeffbac5c6baa6124d24ddf52abdc7216b6a6a3e77278124993cec2592513cff4ad9d2619eb7b65b15ea835f3fa37f239a5
@@ -44,12 +44,19 @@ module Braintree
44
44
  attr_reader :subscriptions
45
45
  attr_reader :token
46
46
  attr_reader :updated_at
47
+ attr_reader :verification
47
48
 
48
49
  def initialize(gateway, attributes)
49
50
  @gateway = gateway
50
51
  set_instance_variables_from_hash(attributes)
51
52
  @billing_address = attributes[:billing_address] ? Address._new(@gateway, attributes[:billing_address]) : nil
52
53
  @subscriptions = (@subscriptions || []).map { |subscription_hash| Subscription._new(@gateway, subscription_hash) }
54
+ @verification = _most_recent_verification(attributes)
55
+ end
56
+
57
+ def _most_recent_verification(attributes)
58
+ sorted_verifications = (attributes[:verifications] || []).sort_by { |verification| verification[:created_at] }.reverse.first
59
+ CreditCardVerification._new(sorted_verifications) if sorted_verifications
53
60
  end
54
61
 
55
62
  def default?
@@ -33,5 +33,48 @@ module Braintree
33
33
  raise "expected :response or :api_error_response"
34
34
  end
35
35
  end
36
+
37
+ def self._card_signature(type)
38
+ billing_address_params = AddressGateway._shared_signature
39
+
40
+ options = [
41
+ :verification_account_type,
42
+ :verification_amount,
43
+ :verification_merchant_account_id,
44
+ :verify_card
45
+ ]
46
+
47
+ signature = [
48
+ :cardholder_name,
49
+ :cryptogram,
50
+ :eci_indicator,
51
+ :expiration_month,
52
+ :expiration_year,
53
+ :network_transaction_id,
54
+ :number,
55
+ :token,
56
+ {:billing_address => billing_address_params},
57
+ {:options => options}
58
+ ]
59
+
60
+ case type
61
+ when :create
62
+ nil
63
+ when :update
64
+ options << :make_default
65
+ else
66
+ raise ArgumentError, "Invalid signature type: #{type}"
67
+ end
68
+
69
+ signature
70
+ end
71
+
72
+ def self._create_card_signature
73
+ _card_signature(:create)
74
+ end
75
+
76
+ def self._update_card_signature
77
+ _card_signature(:update)
78
+ end
36
79
  end
37
80
  end
@@ -35,6 +35,15 @@ module Braintree
35
35
  def singleton_class
36
36
  class << self; self; end
37
37
  end
38
+
39
+ private
40
+
41
+ def _format_hash(hash)
42
+ formatted_pairs = hash.map do |key, value|
43
+ ":#{key}=>#{value.inspect}"
44
+ end
45
+ "{#{formatted_pairs.join(", ")}}"
46
+ end
38
47
  end
39
48
 
40
49
  def self.included(klass)
@@ -28,6 +28,7 @@ module Braintree
28
28
  attr_reader :amount
29
29
  attr_reader :ani_first_name_response_code
30
30
  attr_reader :ani_last_name_response_code
31
+ attr_reader :apple_pay
31
32
  attr_reader :avs_error_response_code
32
33
  attr_reader :avs_postal_code_response_code
33
34
  attr_reader :avs_street_address_response_code
@@ -64,6 +65,7 @@ module Braintree
64
65
  :amount,
65
66
  :ani_first_name_response_code,
66
67
  :ani_last_name_response_code,
68
+ :apple_pay,
67
69
  :avs_error_response_code,
68
70
  :avs_postal_code_response_code,
69
71
  :avs_street_address_response_code,
@@ -90,7 +90,7 @@ module Braintree
90
90
  @google_pay_cards = (@google_pay_cards || []).map { |pm| GooglePayCard._new gateway, pm }
91
91
  @venmo_accounts = (@venmo_accounts || []).map { |pm| VenmoAccount._new gateway, pm }
92
92
  @us_bank_accounts = (@us_bank_accounts || []).map { |pm| UsBankAccount._new gateway, pm }
93
- @visa_checkout_cards = (@visa_checkout_cards|| []).map { |pm| VisaCheckoutCard._new gateway, pm }
93
+ @visa_checkout_cards = (@visa_checkout_cards|| []).map { |pm| VisaCheckoutCard._new gateway, pm } # Deprecated
94
94
  @sepa_direct_debit_accounts = (@sepa_debit_accounts || []).map { |pm| SepaDirectDebitAccount._new gateway, pm }
95
95
  @samsung_pay_cards = (@samsung_pay_cards|| []).map { |pm| SamsungPayCard._new gateway, pm } # Deprecated
96
96
  @addresses = (@addresses || []).map { |addr| Address._new gateway, addr }
@@ -129,7 +129,7 @@ module Braintree
129
129
  def inspect
130
130
  first = [:id]
131
131
  last = [:addresses, :credit_cards, :paypal_accounts, :tax_identifiers]
132
- order = first + (self.class._attributes - first - last) + last
132
+ order = (first + ((self.class._attributes - first) - last)) + last
133
133
  nice_attributes = order.map do |attr|
134
134
  "#{attr}: #{send(attr).inspect}"
135
135
  end
@@ -82,6 +82,7 @@ module Braintree
82
82
  :last_name, :phone, :website,
83
83
  :device_data, :payment_method_nonce,
84
84
  {:risk_data => [:customer_browser, :customer_ip]},
85
+ {:apple_pay_card => ApplePayGateway._create_card_signature},
85
86
  {:credit_card => credit_card_signature},
86
87
  {:paypal_account => paypal_account_signature},
87
88
  {:tax_identifiers => [:country_code, :identifier]},
@@ -147,6 +148,7 @@ module Braintree
147
148
  {:international_phone => [:country_code, :national_number]},
148
149
  :last_name, :phone, :website,
149
150
  :device_data, :payment_method_nonce, :default_payment_method_token,
151
+ {:apple_pay_card => ApplePayGateway._update_card_signature},
150
152
  {:credit_card => credit_card_signature},
151
153
  {:tax_identifiers => [:country_code, :identifier]},
152
154
  {:options => options},
@@ -51,6 +51,7 @@ module Braintree
51
51
  MerchantKeysAlreadyConfigured = "93515"
52
52
  MerchantKeysNotConfigured = "93516"
53
53
  MerchantNotConfigured = "93514"
54
+ NetworkTransactionIdNotAllowed = "93532"
54
55
  NumberIsRequired = "93508"
55
56
  PaymentMethodNonceCardTypeIsNotAccepted = "83518"
56
57
  PaymentMethodNonceConsumed = "93504"
@@ -58,6 +59,17 @@ module Braintree
58
59
  PaymentMethodNonceUnknown = "93505"
59
60
  PrivateKeyMismatch = "93521"
60
61
  TokenIsInUse = "93503"
62
+
63
+ module Options
64
+ VerificationAccountTypeIsInvalid = "93538"
65
+ VerificationAccountTypeNotSupported = "93543"
66
+ VerificationAmountCannotBeNegative = "93535"
67
+ VerificationAmountFormatIsInvalid = "93534"
68
+ VerificationAmountIsTooLarge = "93537"
69
+ VerificationAmountNotSupportedByProcessor = "93536"
70
+ VerificationMerchantAccountIdIsInvalid = "93540"
71
+ VerificationMerchantAccountIsSuspended = "93541"
72
+ end
61
73
  end
62
74
 
63
75
  module CreditCard
@@ -136,6 +148,8 @@ module Braintree
136
148
  IdIsNotAllowed = "91611"
137
149
  IdIsRequired = "91613"
138
150
  IdIsTooLong = "91612"
151
+ InternationalPhoneCountryCodeIsInvalid = "91625"
152
+ InternationalPhoneNationalNumberIsInvalid = "91626"
139
153
  LastNameIsTooLong = "81613"
140
154
  PhoneIsTooLong = "81614"
141
155
  VaultedPaymentInstrumentNonceBelongsToDifferentCustomer = "91617"
@@ -365,6 +379,12 @@ module Braintree
365
379
  DiscountAmountFormatIsInvalid = "915159"
366
380
  DiscountAmountIsTooLarge = "915161"
367
381
  ExchangeRateQuoteIdTooLong = "915229"
382
+ ApiRequestKeyTooLong = "915230"
383
+ ApiRequestKeyNotAllowed = "915231"
384
+ ApiRequestKeyCanBeReusedOnlyWithTheSameRequest = "915232"
385
+ ApiRequestKeyIsInFlight = "915233"
386
+ ApiRequestKeyWithFailedRequest = "915234"
387
+ ApiRequestKeyServerError = "915235"
368
388
  FailedAuthAdjustmentAllowRetry = "95603"
369
389
  FailedAuthAdjustmentHardDecline = "95602"
370
390
  FinalAuthSubmitForSettlementForDifferentAmount = "95601"
@@ -46,6 +46,10 @@ module Braintree
46
46
  CustomerSessionGateway.new(self, graphql_client)
47
47
  end
48
48
 
49
+ def local_payment_context
50
+ LocalPaymentContextGateway.new(self, graphql_client)
51
+ end
52
+
49
53
  def discount
50
54
  DiscountGateway.new(self)
51
55
  end
@@ -0,0 +1,34 @@
1
+ module Braintree
2
+ class BillingAddressInput
3
+ include BaseModule
4
+
5
+ attr_reader :attrs
6
+ attr_reader :country_code_alpha2
7
+ attr_reader :extended_address
8
+ attr_reader :locality
9
+ attr_reader :postal_code
10
+ attr_reader :region
11
+ attr_reader :street_address
12
+
13
+ def initialize(attributes)
14
+ @attrs = attributes.keys
15
+ set_instance_variables_from_hash(attributes)
16
+ end
17
+
18
+ def inspect
19
+ inspected_attributes = @attrs.map { |attr| "#{attr}:#{send(attr).inspect}" }
20
+ "#<#{self.class} #{inspected_attributes.join(" ")}>"
21
+ end
22
+
23
+ def to_graphql_variables
24
+ {
25
+ "countryCode" => country_code_alpha2,
26
+ "extendedAddress" => extended_address,
27
+ "locality" => locality,
28
+ "postalCode" => postal_code,
29
+ "region" => region,
30
+ "streetAddress" => street_address
31
+ }.compact
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ module Braintree
2
+ class CreateLocalPaymentContextInput
3
+ include BaseModule
4
+
5
+ attr_reader :amount
6
+ attr_reader :attrs
7
+ attr_reader :cancel_url
8
+ attr_reader :country_code
9
+ attr_reader :expiry_date
10
+ attr_reader :merchant_account_id
11
+ attr_reader :order_id
12
+ attr_reader :payer_info
13
+ attr_reader :return_url
14
+ attr_reader :type
15
+
16
+ def initialize(attributes)
17
+ @attrs = attributes.keys
18
+ set_instance_variables_from_hash(attributes)
19
+ @amount = attributes[:amount] ? MonetaryAmountInput.new(attributes[:amount]) : nil
20
+ @payer_info = attributes[:payer_info] ? PayerInfoInput.new(attributes[:payer_info]) : nil
21
+ end
22
+
23
+ def inspect
24
+ inspected_attributes = @attrs.map { |attr| "#{attr}:#{send(attr).inspect}" }
25
+ "#<#{self.class} #{inspected_attributes.join(" ")}>"
26
+ end
27
+
28
+ def to_graphql_variables
29
+ {
30
+ "paymentContext" => {
31
+ "amount" => amount&.to_graphql_variables,
32
+ "cancelUrl" => cancel_url,
33
+ "countryCode" => country_code,
34
+ "expiryDate" => expiry_date,
35
+ "merchantAccountId" => merchant_account_id,
36
+ "orderId" => order_id,
37
+ "payerInfo" => payer_info&.to_graphql_variables,
38
+ "returnUrl" => return_url,
39
+ "type" => type
40
+ }.compact
41
+ }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,38 @@
1
+ module Braintree
2
+ class PayerInfoInput
3
+ include BaseModule
4
+
5
+ attr_reader :attrs
6
+ attr_reader :billing_address
7
+ attr_reader :email
8
+ attr_reader :given_name
9
+ attr_reader :phone_country_code
10
+ attr_reader :phone_number
11
+ attr_reader :shipping_address
12
+ attr_reader :surname
13
+
14
+ def initialize(attributes)
15
+ @attrs = attributes.keys
16
+ set_instance_variables_from_hash(attributes)
17
+ @billing_address = attributes[:billing_address] ? BillingAddressInput.new(attributes[:billing_address]) : nil
18
+ @shipping_address = attributes[:shipping_address] ? ShippingAddressInput.new(attributes[:shipping_address]) : nil
19
+ end
20
+
21
+ def inspect
22
+ inspected_attributes = @attrs.map { |attr| "#{attr}:#{send(attr).inspect}" }
23
+ "#<#{self.class} #{inspected_attributes.join(" ")}>"
24
+ end
25
+
26
+ def to_graphql_variables
27
+ {
28
+ "billingAddress" => billing_address&.to_graphql_variables,
29
+ "email" => email,
30
+ "givenName" => given_name,
31
+ "phoneCountryCode" => phone_country_code,
32
+ "phoneNumber" => phone_number,
33
+ "shippingAddress" => shipping_address&.to_graphql_variables,
34
+ "surname" => surname
35
+ }.compact
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ module Braintree
2
+ class ShippingAddressInput
3
+ include BaseModule
4
+
5
+ attr_reader :attrs
6
+ attr_reader :country_code_alpha2
7
+ attr_reader :extended_address
8
+ attr_reader :locality
9
+ attr_reader :postal_code
10
+ attr_reader :region
11
+ attr_reader :street_address
12
+
13
+ def initialize(attributes)
14
+ @attrs = attributes.keys
15
+ set_instance_variables_from_hash(attributes)
16
+ end
17
+
18
+ def inspect
19
+ inspected_attributes = @attrs.map { |attr| "#{attr}:#{send(attr).inspect}" }
20
+ "#<#{self.class} #{inspected_attributes.join(" ")}>"
21
+ end
22
+
23
+ def to_graphql_variables
24
+ {
25
+ "countryCode" => country_code_alpha2,
26
+ "extendedAddress" => extended_address,
27
+ "locality" => locality,
28
+ "postalCode" => postal_code,
29
+ "region" => region,
30
+ "streetAddress" => street_address
31
+ }.compact
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,108 @@
1
+ module Braintree
2
+ class LocalPaymentContext
3
+ include BaseModule
4
+
5
+ attr_reader :amount
6
+ attr_reader :approval_url
7
+ attr_reader :approved_at
8
+ attr_reader :attrs
9
+ attr_reader :created_at
10
+ attr_reader :expired_at
11
+ attr_reader :id
12
+ attr_reader :legacy_id
13
+ attr_reader :merchant_account_id
14
+ attr_reader :order_id
15
+ attr_reader :payment_id
16
+ attr_reader :transacted_at
17
+ attr_reader :type
18
+ attr_reader :updated_at
19
+
20
+ def initialize(attributes)
21
+ @attrs = [:amount, :approval_url, :approved_at, :attrs, :created_at, :expired_at, :id, :legacy_id,
22
+ :merchant_account_id, :order_id, :payment_id, :transacted_at, :type, :updated_at]
23
+
24
+ if attributes.key?(:response)
25
+ response = attributes[:response]
26
+ @id = _get_value(response, "paymentContext.id")
27
+ @legacy_id = _get_value_optional(response, "paymentContext.legacyId")
28
+ @type = _get_value(response, "paymentContext.type")
29
+ @payment_id = _get_value_optional(response, "paymentContext.paymentId")
30
+ @order_id = _get_value_optional(response, "paymentContext.orderId")
31
+ @approval_url = _get_value_optional(response, "paymentContext.approvalUrl")
32
+ @merchant_account_id = _get_value_optional(response, "paymentContext.merchantAccountId")
33
+ @created_at = _get_value_optional(response, "paymentContext.createdAt")
34
+ @updated_at = _get_value_optional(response, "paymentContext.updatedAt")
35
+ @transacted_at = _get_value_optional(response, "paymentContext.transactedAt")
36
+ @approved_at = _get_value_optional(response, "paymentContext.approvedAt")
37
+ @expired_at = _get_value_optional(response, "paymentContext.expiredAt")
38
+ @amount = _extract_amount(response)
39
+ else
40
+ set_instance_variables_from_hash(attributes)
41
+ end
42
+ end
43
+
44
+ def inspect
45
+ inspected_attributes = @attrs.map { |attr| "#{attr}:#{send(attr).inspect}" }
46
+ "#<#{self.class} #{inspected_attributes.join(" ")}>"
47
+ end
48
+
49
+ class << self
50
+ protected :new
51
+ end
52
+
53
+ def self._new(*args)
54
+ self.new(*args)
55
+ end
56
+
57
+ private
58
+
59
+ def _extract_amount(response)
60
+ amount_hash = _get_value_optional(response, "paymentContext.amount")
61
+ return nil unless amount_hash
62
+
63
+ currency = amount_hash[:currencyCode] || amount_hash["currencyCode"] ||
64
+ amount_hash[:currencyIsoCode] || amount_hash["currencyIsoCode"]
65
+
66
+ MonetaryAmount._new({
67
+ value: amount_hash[:value] || amount_hash["value"],
68
+ currency_code: currency
69
+ })
70
+ end
71
+
72
+ def _get_value(response, key)
73
+ current_map = response
74
+ key_parts = key.split(".")
75
+
76
+ (0...key_parts.length - 1).each do |i|
77
+ sub_key = key_parts[i]
78
+ current_map = _pop_value(current_map, sub_key)
79
+ end
80
+
81
+ last_key = key_parts[-1]
82
+ _pop_value(current_map, last_key)
83
+ end
84
+
85
+ def _get_value_optional(response, key)
86
+ _get_value(response, key)
87
+ rescue ServerError
88
+ nil
89
+ end
90
+
91
+ def _pop_value(response, key)
92
+ if response.key?(key)
93
+ return response[key]
94
+ end
95
+
96
+ symkey = key.to_sym
97
+ if response.key?(symkey)
98
+ return response[symkey]
99
+ end
100
+
101
+ if response.key?(key.to_s)
102
+ return response[key.to_s]
103
+ end
104
+
105
+ raise ServerError.new("Couldn't parse response")
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,132 @@
1
+ module Braintree
2
+ class LocalPaymentContextGateway
3
+ CREATE_LOCAL_PAYMENT_CONTEXT = <<~GRAPHQL
4
+ mutation CreateLocalPaymentContext($input: CreateLocalPaymentContextInput!) {
5
+ createLocalPaymentContext(input: $input) {
6
+ paymentContext {
7
+ id
8
+ legacyId
9
+ type
10
+ paymentId
11
+ approvalUrl
12
+ merchantAccountId
13
+ orderId
14
+ createdAt
15
+ transactedAt
16
+ approvedAt
17
+ amount {
18
+ value
19
+ currencyCode
20
+ }
21
+ }
22
+ }
23
+ }
24
+ GRAPHQL
25
+
26
+ FIND_LOCAL_PAYMENT_CONTEXT = <<~GRAPHQL
27
+ query Node($id: ID!) {
28
+ node(id: $id) {
29
+ ... on LocalPaymentContext {
30
+ id
31
+ legacyId
32
+ type
33
+ amount {
34
+ value
35
+ currencyIsoCode
36
+ }
37
+ approvalUrl
38
+ merchantAccountId
39
+ transactedAt
40
+ approvedAt
41
+ createdAt
42
+ updatedAt
43
+ expiredAt
44
+ paymentId
45
+ orderId
46
+ }
47
+ }
48
+ }
49
+ GRAPHQL
50
+
51
+ def initialize(gateway, graphql_client)
52
+ @gateway = gateway
53
+ @graphql_client = graphql_client
54
+ end
55
+
56
+ def create(input)
57
+ variables = {"input" => input.to_graphql_variables}
58
+
59
+ begin
60
+ response = @graphql_client.query(CREATE_LOCAL_PAYMENT_CONTEXT, variables)
61
+ errors = GraphQLClient.get_validation_errors(response)
62
+
63
+ if errors
64
+ ErrorResult.new(@gateway, {errors: errors})
65
+ else
66
+ payment_context = extract_payment_context(response)
67
+ SuccessfulResult.new(:payment_context => payment_context)
68
+ end
69
+ rescue StandardError => e
70
+ raise UnexpectedError, e.message
71
+ end
72
+ end
73
+
74
+ def find(id)
75
+ variables = {"id" => id}
76
+
77
+ begin
78
+ response = @graphql_client.query(FIND_LOCAL_PAYMENT_CONTEXT, variables)
79
+ errors = GraphQLClient.get_validation_errors(response)
80
+
81
+ if errors
82
+ ErrorResult.new(@gateway, {errors: errors})
83
+ else
84
+ payment_context = extract_node_payment_context(response)
85
+ SuccessfulResult.new(:payment_context => payment_context)
86
+ end
87
+ rescue NotFoundError
88
+ raise
89
+ rescue StandardError => e
90
+ raise UnexpectedError, e.message
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def extract_payment_context(response)
97
+ context_hash = get_value(response, "data.createLocalPaymentContext.paymentContext")
98
+ LocalPaymentContext._new({:response => {"paymentContext" => context_hash}})
99
+ end
100
+
101
+ def extract_node_payment_context(response)
102
+ node_hash = get_value(response, "data.node")
103
+
104
+ if node_hash.nil?
105
+ raise NotFoundError, "Payment context not found"
106
+ end
107
+
108
+ LocalPaymentContext._new({:response => {"paymentContext" => node_hash}})
109
+ end
110
+
111
+ def get_value(response, key)
112
+ map = response
113
+ key_parts = key.split(".")
114
+
115
+ key_parts[0..-2].each do |sub_key|
116
+ map = pop_value(map, sub_key)
117
+ raise UnexpectedError, "Couldn't parse response" unless map.is_a?(Hash)
118
+ end
119
+
120
+ pop_value(map, key_parts.last)
121
+ end
122
+
123
+ def pop_value(map, key)
124
+ key = key.to_sym
125
+ if map.key?(key)
126
+ map[key]
127
+ else
128
+ raise UnexpectedError, "Couldn't parse response"
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,6 @@
1
+ module Braintree
2
+ module LocalPaymentType
3
+ CRYPTO = "CRYPTO"
4
+ MBWAY = "MBWAY"
5
+ end
6
+ end
@@ -5,22 +5,10 @@ module Braintree
5
5
  @config = gateway.config
6
6
  end
7
7
 
8
- def provision_raw_apple_pay
9
- response = @config.http.put("#{@config.base_merchant_path}/provision_raw_apple_pay")
10
- if response[:apple_pay]
11
- SuccessfulResult.new(response[:apple_pay])
12
- elsif response[:api_error_response]
13
- ErrorResult.new(@gateway, response[:api_error_response])
14
- else
15
- raise UnexpectedError, "expected :apple_pay or :api_error_response"
16
- end
17
- end
18
-
8
+ # NEXT_MAJOR_VERSION remove this method
9
+ # The create_via_api endpoint has been disabled; this method always raises a server error
19
10
  def create(params)
20
- _create_merchant(params)
21
- end
22
-
23
- def _create_merchant(params)
11
+ warn "[DEPRECATED] Merchant.create is deprecated and will be removed in a future version."
24
12
  response = @config.http.post("/merchants/create_via_api", :merchant => params)
25
13
 
26
14
  if response.has_key?(:response) && response[:response][:merchant]
@@ -31,8 +19,20 @@ module Braintree
31
19
  elsif response[:api_error_response]
32
20
  ErrorResult.new(@gateway, response[:api_error_response])
33
21
  else
34
- raise "expected :merchant or :api_error_response"
22
+ raise UnexpectedError, "expected :merchant or :api_error_response"
35
23
  end
36
24
  end
25
+
26
+ def provision_raw_apple_pay
27
+ response = @config.http.put("#{@config.base_merchant_path}/provision_raw_apple_pay")
28
+ if response[:apple_pay]
29
+ SuccessfulResult.new(response[:apple_pay])
30
+ elsif response[:api_error_response]
31
+ ErrorResult.new(@gateway, response[:api_error_response])
32
+ else
33
+ raise UnexpectedError, "expected :apple_pay or :api_error_response"
34
+ end
35
+ end
36
+
37
37
  end
38
38
  end
@@ -0,0 +1,24 @@
1
+ module Braintree
2
+ class MonetaryAmount
3
+ include BaseModule
4
+
5
+ attr_reader :currency_code
6
+ attr_reader :value
7
+
8
+ def initialize(attributes)
9
+ set_instance_variables_from_hash(attributes)
10
+ end
11
+
12
+ def inspect
13
+ "#<MonetaryAmount currency_code:#{currency_code.inspect} value:#{value.inspect}>"
14
+ end
15
+
16
+ class << self
17
+ protected :new
18
+ end
19
+
20
+ def self._new(*args)
21
+ self.new(*args)
22
+ end
23
+ end
24
+ end