braintree 2.90.0 → 2.91.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/braintree.gemspec +5 -0
- data/lib/braintree/configuration.rb +39 -1
- data/lib/braintree/credit_card.rb +1 -0
- data/lib/braintree/error_codes.rb +8 -0
- data/lib/braintree/graphql_client.rb +28 -0
- data/lib/braintree/http.rb +21 -9
- data/lib/braintree/local_payment_completed.rb +20 -0
- data/lib/braintree/test/credit_card.rb +2 -0
- data/lib/braintree/transaction.rb +8 -0
- data/lib/braintree/transaction_gateway.rb +4 -0
- data/lib/braintree/util.rb +44 -3
- data/lib/braintree/validation_error.rb +10 -2
- data/lib/braintree/validation_error_collection.rb +2 -1
- data/lib/braintree/version.rb +1 -1
- data/lib/braintree/webhook_notification.rb +5 -1
- data/lib/braintree/webhook_testing_gateway.rb +34 -3
- data/lib/braintree.rb +3 -1
- data/spec/integration/braintree/credit_card_spec.rb +14 -0
- data/spec/integration/braintree/dispute_spec.rb +3 -0
- data/spec/integration/braintree/graphql_client_spec.rb +74 -0
- data/spec/integration/braintree/http_spec.rb +1 -1
- data/spec/integration/braintree/transaction_search_spec.rb +19 -0
- data/spec/integration/braintree/transaction_spec.rb +203 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/braintree/configuration_spec.rb +37 -0
- data/spec/unit/braintree/http_spec.rb +65 -0
- data/spec/unit/braintree/local_payment_completed_spec.rb +24 -0
- data/spec/unit/braintree/transaction_spec.rb +8 -0
- data/spec/unit/braintree/util_spec.rb +109 -0
- data/spec/unit/braintree/validation_error_collection_spec.rb +335 -132
- data/spec/unit/braintree/webhook_notification_spec.rb +31 -0
- metadata +10 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 703d5a600446c3eccc5d310b70091319b9d426c2db3826851bbcd55fed478ecc
|
4
|
+
data.tar.gz: d98833b2c0937b365e18817b5bf5c0335695282e4aad32ecf08537fc5f36e3b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83411d93215207167d8aa5f3f52a2af58b0744f502c0ec64989dee900f87b415861563f11809e9f9f428c09ed63b7a4f47afb6a419708cfc78d5a3ae7ae3c847
|
7
|
+
data.tar.gz: bd72dec425b6f7164c5ca5f2560aacc5a62e3db20ea3b01afee70683fe964f888fd4e77f35139d7034e8dbc083a5bd15f5138844d01569b21614f675b64aed77
|
data/braintree.gemspec
CHANGED
@@ -14,5 +14,10 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.has_rdoc = false
|
15
15
|
s.files = Dir.glob ["README.rdoc", "LICENSE", "lib/**/*.{rb,crt}", "spec/**/*", "*.gemspec"]
|
16
16
|
s.add_dependency "builder", ">= 2.0.0"
|
17
|
+
s.metadata = {
|
18
|
+
"bug_tracker_uri" => "https://github.com/braintree/braintree_ruby/issues",
|
19
|
+
"changelog_uri" => "https://github.com/braintree/braintree_ruby/blob/master/CHANGELOG.md",
|
20
|
+
"source_code_uri" => "https://github.com/braintree/braintree_ruby",
|
21
|
+
}
|
17
22
|
end
|
18
23
|
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module Braintree
|
2
2
|
class Configuration
|
3
|
-
API_VERSION = "
|
3
|
+
API_VERSION = "5" # :nodoc:
|
4
4
|
DEFAULT_ENDPOINT = "api" # :nodoc:
|
5
|
+
GRAPHQL_API_VERSION = "2018-09-10" # :nodoc:
|
5
6
|
|
6
7
|
READABLE_ATTRIBUTES = [
|
7
8
|
:merchant_id,
|
@@ -44,6 +45,7 @@ module Braintree
|
|
44
45
|
end
|
45
46
|
attr_reader *READABLE_ATTRIBUTES
|
46
47
|
attr_reader *NON_REQUIRED_READABLE_ATTRIBUTES
|
48
|
+
attr_writer *WRITABLE_ATTRIBUTES
|
47
49
|
|
48
50
|
def self.expectant_reader(*attributes) # :nodoc:
|
49
51
|
attributes.each do |attribute|
|
@@ -113,6 +115,8 @@ module Braintree
|
|
113
115
|
instance_variable_set "@#{attr}", options[attr]
|
114
116
|
end
|
115
117
|
|
118
|
+
@environment = @environment.to_sym if @environment
|
119
|
+
|
116
120
|
_check_for_mixed_credentials(options)
|
117
121
|
|
118
122
|
parser = Braintree::CredentialsParser.new
|
@@ -158,6 +162,10 @@ module Braintree
|
|
158
162
|
API_VERSION
|
159
163
|
end
|
160
164
|
|
165
|
+
def graphql_api_version # :nodoc:
|
166
|
+
GRAPHQL_API_VERSION
|
167
|
+
end
|
168
|
+
|
161
169
|
def base_merchant_path # :nodoc:
|
162
170
|
"/merchants/#{merchant_id}"
|
163
171
|
end
|
@@ -166,6 +174,10 @@ module Braintree
|
|
166
174
|
"#{protocol}://#{server}:#{port}"
|
167
175
|
end
|
168
176
|
|
177
|
+
def graphql_base_url
|
178
|
+
"#{protocol}://#{graphql_server}:#{graphql_port}/graphql"
|
179
|
+
end
|
180
|
+
|
169
181
|
def base_merchant_url # :nodoc:
|
170
182
|
"#{base_url}#{base_merchant_path}"
|
171
183
|
end
|
@@ -182,6 +194,10 @@ module Braintree
|
|
182
194
|
Http.new(self)
|
183
195
|
end
|
184
196
|
|
197
|
+
def graphql_client
|
198
|
+
GraphQLClient.new(self)
|
199
|
+
end
|
200
|
+
|
185
201
|
def logger
|
186
202
|
@logger ||= self.class._default_logger
|
187
203
|
end
|
@@ -195,6 +211,15 @@ module Braintree
|
|
195
211
|
end
|
196
212
|
end
|
197
213
|
|
214
|
+
def graphql_port # :nodoc:
|
215
|
+
case @environment
|
216
|
+
when :development, :integration
|
217
|
+
ENV['GRAPHQL_PORT'] || 8080
|
218
|
+
when :production, :qa, :sandbox
|
219
|
+
443
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
198
223
|
def protocol # :nodoc:
|
199
224
|
ssl? ? "https" : "http"
|
200
225
|
end
|
@@ -220,6 +245,19 @@ module Braintree
|
|
220
245
|
end
|
221
246
|
end
|
222
247
|
|
248
|
+
def graphql_server # :nodoc:
|
249
|
+
case @environment
|
250
|
+
when :development, :integration
|
251
|
+
ENV['GRAPHQL_HOST'] || "graphql.bt.local"
|
252
|
+
when :production
|
253
|
+
"payments.braintree-api.com"
|
254
|
+
when :qa
|
255
|
+
"payments-qa.dev.braintree-api.com"
|
256
|
+
when :sandbox
|
257
|
+
"payments.sandbox.braintree-api.com"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
223
261
|
def auth_url
|
224
262
|
case @environment
|
225
263
|
when :development, :integration
|
@@ -328,6 +328,7 @@ module Braintree
|
|
328
328
|
FinalAuthSubmitForSettlementForDifferentAmount = "95601"
|
329
329
|
HasAlreadyBeenRefunded = "91512"
|
330
330
|
IdealPaymentNotComplete = "815141"
|
331
|
+
PaymentInstrumentWithExternalVaultIsInvalid = "915176"
|
331
332
|
TooManyLineItems = "915157"
|
332
333
|
LineItemsExpected = "915158"
|
333
334
|
DiscountAmountFormatIsInvalid = "915159"
|
@@ -439,6 +440,13 @@ module Braintree
|
|
439
440
|
LodgingCheckOutDateIsInvalid = "93413"
|
440
441
|
end
|
441
442
|
end
|
443
|
+
|
444
|
+
module ExternalVault
|
445
|
+
StatusIsInvalid = "915175"
|
446
|
+
CardTypeIsInvalid = "915178"
|
447
|
+
StatusWithPreviousNetworkTransactionIdIsInvalid = "915177"
|
448
|
+
PreviousNetworkTransactionIdIsInvalid = "915179"
|
449
|
+
end
|
442
450
|
end
|
443
451
|
|
444
452
|
module TransactionLineItem
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Braintree
|
2
|
+
class GraphQLClient < Http # :nodoc:
|
3
|
+
|
4
|
+
def initialize(config)
|
5
|
+
@config = config
|
6
|
+
@graphql_headers = {
|
7
|
+
'Accept' => 'application/json',
|
8
|
+
'Braintree-Version' => @config.graphql_api_version,
|
9
|
+
'Content-Type' => 'application/json'
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def query(definition, variables = {}, operationName = nil)
|
14
|
+
graphql_connection = _setup_connection(@config.graphql_server, @config.graphql_port)
|
15
|
+
|
16
|
+
request = {}
|
17
|
+
request['query'] = definition
|
18
|
+
request['operationName'] = operationName if operationName
|
19
|
+
request['variables'] = variables
|
20
|
+
|
21
|
+
response = _http_do Net::HTTP::Post, @config.graphql_base_url, request.to_json, nil, graphql_connection, @graphql_headers
|
22
|
+
data = JSON.parse(response.body, :symbolize_names => true)
|
23
|
+
Util.raise_exception_for_graphql_error(data)
|
24
|
+
|
25
|
+
data
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/braintree/http.rb
CHANGED
@@ -67,19 +67,34 @@ module Braintree
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
def
|
70
|
+
def _setup_connection(server = @config.server, port = @config.port)
|
71
71
|
if @config.proxy_address
|
72
72
|
connection = Net::HTTP.new(
|
73
|
-
|
74
|
-
|
73
|
+
server,
|
74
|
+
port,
|
75
75
|
@config.proxy_address,
|
76
76
|
@config.proxy_port,
|
77
77
|
@config.proxy_user,
|
78
78
|
@config.proxy_pass
|
79
79
|
)
|
80
80
|
else
|
81
|
-
connection = Net::HTTP.new(
|
81
|
+
connection = Net::HTTP.new(server, port)
|
82
82
|
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def _compose_headers(header_overrides = {})
|
86
|
+
headers = {}
|
87
|
+
headers["Accept"] = "application/xml"
|
88
|
+
headers["User-Agent"] = @config.user_agent
|
89
|
+
headers["Accept-Encoding"] = "gzip"
|
90
|
+
headers["X-ApiVersion"] = @config.api_version
|
91
|
+
headers["Content-Type"] = "application/xml"
|
92
|
+
|
93
|
+
headers.merge(header_overrides)
|
94
|
+
end
|
95
|
+
|
96
|
+
def _http_do(http_verb, path, body = nil, file = nil, connection = nil, header_overrides = {})
|
97
|
+
connection ||= _setup_connection
|
83
98
|
|
84
99
|
connection.open_timeout = @config.http_open_timeout
|
85
100
|
connection.read_timeout = @config.http_read_timeout
|
@@ -90,12 +105,10 @@ module Braintree
|
|
90
105
|
connection.ca_file = @config.ca_file
|
91
106
|
connection.verify_callback = proc { |preverify_ok, ssl_context| _verify_ssl_certificate(preverify_ok, ssl_context) }
|
92
107
|
end
|
108
|
+
|
93
109
|
connection.start do |http|
|
94
110
|
request = http_verb.new(path)
|
95
|
-
request[
|
96
|
-
request["User-Agent"] = @config.user_agent
|
97
|
-
request["Accept-Encoding"] = "gzip"
|
98
|
-
request["X-ApiVersion"] = @config.api_version
|
111
|
+
_compose_headers(header_overrides).each { |header, value| request[header] = value }
|
99
112
|
if @config.client_credentials?
|
100
113
|
request.basic_auth @config.client_id, @config.client_secret
|
101
114
|
elsif @config.access_token
|
@@ -117,7 +130,6 @@ module Braintree
|
|
117
130
|
request.body = form_params.collect {|p| "--" + boundary + "#{LINE_FEED}" + p}.join("") + "--" + boundary + "--"
|
118
131
|
@config.logger.debug _format_and_sanitize_body_for_log(_build_xml(body))
|
119
132
|
else
|
120
|
-
request["Content-Type"] = "application/xml"
|
121
133
|
request.body = body
|
122
134
|
@config.logger.debug _format_and_sanitize_body_for_log(body)
|
123
135
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Braintree
|
2
|
+
class LocalPaymentCompleted
|
3
|
+
include BaseModule
|
4
|
+
|
5
|
+
attr_reader :payment_id
|
6
|
+
attr_reader :payer_id
|
7
|
+
|
8
|
+
def initialize(attributes) # :nodoc:
|
9
|
+
set_instance_variables_from_hash(attributes)
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
protected :new
|
14
|
+
end
|
15
|
+
|
16
|
+
def self._new(*args) # :nodoc:
|
17
|
+
self.new *args
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -21,6 +21,7 @@ module Braintree
|
|
21
21
|
CarteBlanches = %w[30569309025904] # :nodoc:
|
22
22
|
DinersClubs = %w[38520000023237] # :nodoc:
|
23
23
|
|
24
|
+
Discover = "6011111111111117"
|
24
25
|
Discovers = %w[6011111111111117 6011000990139424]
|
25
26
|
JCBs = %w[3530111333300000 3566002020360505] # :nodoc:
|
26
27
|
|
@@ -30,6 +31,7 @@ module Braintree
|
|
30
31
|
|
31
32
|
MasterCards = %w[5105105105105100 5555555555554444]
|
32
33
|
|
34
|
+
Elo = "5066991111111118"
|
33
35
|
Visa = "4012888888881881"
|
34
36
|
VisaInternational = "4009348888881881" # :nodoc:
|
35
37
|
VisaPrepaid = "4500600000000061"
|
@@ -69,6 +69,13 @@ module Braintree
|
|
69
69
|
All = constants.map { |c| const_get(c) }
|
70
70
|
end
|
71
71
|
|
72
|
+
module ExternalVault
|
73
|
+
module Status
|
74
|
+
WillVault = "will_vault"
|
75
|
+
Vaulted = "vaulted"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
72
79
|
attr_reader :add_ons
|
73
80
|
attr_reader :additional_processor_response # The raw response from the processor.
|
74
81
|
attr_reader :amex_express_checkout_details
|
@@ -102,6 +109,7 @@ module Braintree
|
|
102
109
|
attr_reader :ideal_payment_details
|
103
110
|
attr_reader :masterpass_card_details
|
104
111
|
attr_reader :merchant_account_id
|
112
|
+
attr_reader :network_transaction_id
|
105
113
|
attr_reader :order_id
|
106
114
|
attr_reader :partial_settlement_transaction_ids
|
107
115
|
attr_reader :payment_instrument_type
|
@@ -226,6 +226,10 @@ module Braintree
|
|
226
226
|
{:venmo => [:profile_id]}
|
227
227
|
]
|
228
228
|
},
|
229
|
+
{:external_vault => [
|
230
|
+
:status,
|
231
|
+
:previous_network_transaction_id,
|
232
|
+
]},
|
229
233
|
{:custom_fields => :_any_key_},
|
230
234
|
{:descriptor => [:name, :phone, :url]},
|
231
235
|
{:paypal_account => [:email, :token, :paypal_data, :payee_id, :payee_email]},
|
data/lib/braintree/util.rb
CHANGED
@@ -66,6 +66,37 @@ module Braintree
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
def self.raise_exception_for_graphql_error(response)
|
70
|
+
return if !response[:errors]
|
71
|
+
|
72
|
+
for error in response[:errors]
|
73
|
+
if error[:extensions] && error[:extensions][:errorClass]
|
74
|
+
case error[:extensions][:errorClass]
|
75
|
+
when "VALIDATION"
|
76
|
+
next # skip raising an error if it is a validation error
|
77
|
+
when "AUTHENTICATION"
|
78
|
+
raise AuthenticationError
|
79
|
+
when "AUTHORIZATION"
|
80
|
+
raise AuthorizationError, error[:message]
|
81
|
+
when "NOT_FOUND"
|
82
|
+
raise NotFoundError
|
83
|
+
when "UNSUPPORTED_CLIENT"
|
84
|
+
raise UpgradeRequiredError, "Please upgrade your client library."
|
85
|
+
when "RESOURCE_LIMIT"
|
86
|
+
raise TooManyRequestsError
|
87
|
+
when "INTERNAL"
|
88
|
+
raise ServerError
|
89
|
+
when "SERVICE_AVAILABILITY"
|
90
|
+
raise DownForMaintenanceError
|
91
|
+
else
|
92
|
+
raise UnexpectedError, "Unexpected Response: #{error[:message]}"
|
93
|
+
end
|
94
|
+
else
|
95
|
+
raise UnexpectedError, "Unexpected Response: #{error[:message]}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
69
100
|
def self.to_big_decimal(decimal)
|
70
101
|
case decimal
|
71
102
|
when BigDecimal, NilClass
|
@@ -82,15 +113,19 @@ module Braintree
|
|
82
113
|
end
|
83
114
|
|
84
115
|
def self.verify_keys(valid_keys, hash)
|
85
|
-
|
86
|
-
invalid_keys = _flatten_hash_keys(hash) - flattened_valid_keys
|
87
|
-
invalid_keys = _remove_wildcard_keys(flattened_valid_keys, invalid_keys)
|
116
|
+
invalid_keys = _get_invalid_keys(valid_keys, hash)
|
88
117
|
if invalid_keys.any?
|
89
118
|
sorted = invalid_keys.sort_by { |k| k.to_s }.join(", ")
|
90
119
|
raise ArgumentError, "invalid keys: #{sorted}"
|
91
120
|
end
|
92
121
|
end
|
93
122
|
|
123
|
+
def self.keys_valid?(valid_keys, hash)
|
124
|
+
invalid_keys = _get_invalid_keys(valid_keys, hash)
|
125
|
+
|
126
|
+
!invalid_keys.any?
|
127
|
+
end
|
128
|
+
|
94
129
|
def self._flatten_valid_keys(valid_keys, namespace = nil)
|
95
130
|
valid_keys.inject([]) do |result, key|
|
96
131
|
if key.is_a?(Hash)
|
@@ -138,6 +173,12 @@ module Braintree
|
|
138
173
|
end
|
139
174
|
end
|
140
175
|
|
176
|
+
def self._get_invalid_keys(valid_keys, hash)
|
177
|
+
flattened_valid_keys = _flatten_valid_keys(valid_keys)
|
178
|
+
keys = _flatten_hash_keys(hash) - flattened_valid_keys
|
179
|
+
keys = _remove_wildcard_keys(flattened_valid_keys, keys)
|
180
|
+
end
|
181
|
+
|
141
182
|
module IdEquality
|
142
183
|
def ==(other) # :nodoc:
|
143
184
|
return false unless other.is_a?(self.class)
|
@@ -6,8 +6,16 @@ module Braintree
|
|
6
6
|
attr_reader :code
|
7
7
|
attr_reader :message
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
|
9
|
+
def initialize(error_hash)
|
10
|
+
# parse GraphQL response objects
|
11
|
+
if (error_hash[:extensions] &&
|
12
|
+
error_hash[:extensions][:errorClass] &&
|
13
|
+
error_hash[:extensions][:errorClass] == "VALIDATION")
|
14
|
+
error_hash[:code] = error_hash[:extensions][:legacyCode].to_i
|
15
|
+
error_hash[:attribute] = error_hash[:path].last
|
16
|
+
end
|
17
|
+
|
18
|
+
set_instance_variables_from_hash error_hash
|
11
19
|
end
|
12
20
|
|
13
21
|
def inspect # :nodoc:
|
@@ -3,7 +3,8 @@ module Braintree
|
|
3
3
|
include Enumerable
|
4
4
|
|
5
5
|
def initialize(data) # :nodoc:
|
6
|
-
|
6
|
+
return if !data.is_a? Hash
|
7
|
+
@errors = (data[:errors] || {}).map { |hash| Braintree::ValidationError.new(hash) }
|
7
8
|
@nested = {}
|
8
9
|
data.keys.each do |key|
|
9
10
|
next if key == :errors
|
data/lib/braintree/version.rb
CHANGED
@@ -41,6 +41,8 @@ module Braintree
|
|
41
41
|
ConnectedMerchantPayPalStatusChanged = "connected_merchant_paypal_status_changed"
|
42
42
|
|
43
43
|
GrantedPaymentInstrumentUpdate = "granted_payment_instrument_update"
|
44
|
+
|
45
|
+
LocalPaymentCompleted = "local_payment_completed"
|
44
46
|
end
|
45
47
|
|
46
48
|
attr_reader :account_updater_daily_report
|
@@ -51,8 +53,9 @@ module Braintree
|
|
51
53
|
attr_reader :granted_payment_instrument_update
|
52
54
|
attr_reader :ideal_payment
|
53
55
|
attr_reader :kind
|
54
|
-
attr_reader :
|
56
|
+
attr_reader :local_payment_completed
|
55
57
|
attr_reader :oauth_access_revocation
|
58
|
+
attr_reader :partner_merchant
|
56
59
|
attr_reader :source_merchant_id
|
57
60
|
attr_reader :subscription
|
58
61
|
attr_reader :timestamp
|
@@ -82,6 +85,7 @@ module Braintree
|
|
82
85
|
@connected_merchant_status_transitioned = ConnectedMerchantStatusTransitioned._new(@subject[:connected_merchant_status_transitioned]) if @subject.has_key?(:connected_merchant_status_transitioned)
|
83
86
|
@connected_merchant_paypal_status_changed = ConnectedMerchantPayPalStatusChanged._new(@subject[:connected_merchant_paypal_status_changed]) if @subject.has_key?(:connected_merchant_paypal_status_changed)
|
84
87
|
@granted_payment_instrument_update = GrantedPaymentInstrumentUpdate._new(@subject[:granted_payment_instrument_update]) if @subject.has_key?(:granted_payment_instrument_update)
|
88
|
+
@local_payment_completed = LocalPaymentCompleted._new(@subject[:local_payment]) if @subject.has_key?(:local_payment)
|
85
89
|
end
|
86
90
|
|
87
91
|
def merchant_account
|
@@ -64,6 +64,8 @@ module Braintree
|
|
64
64
|
_disbursement_sample_xml(id)
|
65
65
|
when Braintree::WebhookNotification::Kind::SubscriptionChargedSuccessfully
|
66
66
|
_subscription_charged_successfully(id)
|
67
|
+
when Braintree::WebhookNotification::Kind::SubscriptionChargedUnsuccessfully
|
68
|
+
_subscription_charged_unsuccessfully(id)
|
67
69
|
when Braintree::WebhookNotification::Kind::AccountUpdaterDailyReport
|
68
70
|
_account_updater_daily_report_sample_xml(id)
|
69
71
|
when Braintree::WebhookNotification::Kind::ConnectedMerchantStatusTransitioned
|
@@ -76,6 +78,8 @@ module Braintree
|
|
76
78
|
_ideal_payment_failed_sample_xml(id)
|
77
79
|
when Braintree::WebhookNotification::Kind::GrantedPaymentInstrumentUpdate
|
78
80
|
_granted_payment_instrument_update_sample_xml(id)
|
81
|
+
when Braintree::WebhookNotification::Kind::LocalPaymentCompleted
|
82
|
+
_local_payment_completed_sample_xml(id)
|
79
83
|
else
|
80
84
|
_subscription_sample_xml(id)
|
81
85
|
end
|
@@ -95,6 +99,7 @@ module Braintree
|
|
95
99
|
<id>#{id}</id>
|
96
100
|
<transactions type="array">
|
97
101
|
<transaction>
|
102
|
+
<id>#{id}</id>
|
98
103
|
<status>submitted_for_settlement</status>
|
99
104
|
<amount>49.99</amount>
|
100
105
|
</transaction>
|
@@ -107,6 +112,26 @@ module Braintree
|
|
107
112
|
XML
|
108
113
|
end
|
109
114
|
|
115
|
+
def _subscription_charged_unsuccessfully(id)
|
116
|
+
|
117
|
+
<<-XML
|
118
|
+
<subscription>
|
119
|
+
<id>#{id}</id>
|
120
|
+
<transactions type="array">
|
121
|
+
<transaction>
|
122
|
+
<id>#{id}</id>
|
123
|
+
<status>failed</status>
|
124
|
+
<amount>49.99</amount>
|
125
|
+
</transaction>
|
126
|
+
</transactions>
|
127
|
+
<add_ons type="array">
|
128
|
+
</add_ons>
|
129
|
+
<discounts type="array">
|
130
|
+
</discounts>
|
131
|
+
</subscription>
|
132
|
+
XML
|
133
|
+
end
|
134
|
+
|
110
135
|
def _subscription_sample_xml(id)
|
111
136
|
|
112
137
|
<<-XML
|
@@ -589,7 +614,6 @@ module Braintree
|
|
589
614
|
end
|
590
615
|
|
591
616
|
def _ideal_payment_complete_sample_xml(id)
|
592
|
-
|
593
617
|
<<-XML
|
594
618
|
<ideal-payment>
|
595
619
|
<id>#{id}</id>
|
@@ -606,7 +630,6 @@ module Braintree
|
|
606
630
|
end
|
607
631
|
|
608
632
|
def _ideal_payment_failed_sample_xml(id)
|
609
|
-
|
610
633
|
<<-XML
|
611
634
|
<ideal-payment>
|
612
635
|
<id>#{id}</id>
|
@@ -623,7 +646,6 @@ module Braintree
|
|
623
646
|
end
|
624
647
|
|
625
648
|
def _granted_payment_instrument_update_sample_xml(id)
|
626
|
-
|
627
649
|
<<-XML
|
628
650
|
<granted-payment-instrument-update>
|
629
651
|
<grant-owner-merchant-id>vczo7jqrpwrsi2px</grant-owner-merchant-id>
|
@@ -641,5 +663,14 @@ module Braintree
|
|
641
663
|
</granted-payment-instrument-update>
|
642
664
|
XML
|
643
665
|
end
|
666
|
+
|
667
|
+
def _local_payment_completed_sample_xml(id)
|
668
|
+
<<-XML
|
669
|
+
<local-payment>
|
670
|
+
<payment-id>PAY-XYZ123</payment-id>
|
671
|
+
<payer-id>ABCPAYER</payer-id>
|
672
|
+
</local-payment>
|
673
|
+
XML
|
674
|
+
end
|
644
675
|
end
|
645
676
|
end
|
data/lib/braintree.rb
CHANGED
@@ -21,6 +21,7 @@ require "braintree/base_module"
|
|
21
21
|
require "braintree/modification"
|
22
22
|
|
23
23
|
require "braintree/util"
|
24
|
+
require "braintree/http"
|
24
25
|
|
25
26
|
require "braintree/account_updater_daily_report"
|
26
27
|
require "braintree/ach_mandate"
|
@@ -70,10 +71,11 @@ require "braintree/error_codes"
|
|
70
71
|
require "braintree/error_result"
|
71
72
|
require "braintree/errors"
|
72
73
|
require "braintree/gateway"
|
73
|
-
require "braintree/
|
74
|
+
require "braintree/graphql_client"
|
74
75
|
require "braintree/ideal_payment"
|
75
76
|
require "braintree/ideal_payment_gateway"
|
76
77
|
require "braintree/transaction/ideal_payment_details"
|
78
|
+
require "braintree/local_payment_completed"
|
77
79
|
require "braintree/merchant"
|
78
80
|
require "braintree/merchant_gateway"
|
79
81
|
require "braintree/merchant_account"
|
@@ -535,6 +535,20 @@ describe Braintree::CreditCard do
|
|
535
535
|
credit_card.expiration_date.should == "11/2099"
|
536
536
|
end
|
537
537
|
end
|
538
|
+
|
539
|
+
context "card_type" do
|
540
|
+
it "is set to Elo" do
|
541
|
+
customer = Braintree::Customer.create!
|
542
|
+
result = Braintree::CreditCard.create(
|
543
|
+
:customer_id => customer.id,
|
544
|
+
:number => Braintree::Test::CreditCardNumbers::Elo,
|
545
|
+
:expiration_date => "10/2020",
|
546
|
+
)
|
547
|
+
result.success?.should == true
|
548
|
+
credit_card = result.credit_card
|
549
|
+
credit_card.card_type.should == Braintree::CreditCard::CardType::Elo
|
550
|
+
end
|
551
|
+
end
|
538
552
|
end
|
539
553
|
|
540
554
|
describe "self.create!" do
|
@@ -34,6 +34,9 @@ describe Braintree::Dispute do
|
|
34
34
|
|
35
35
|
refreshed_dispute = Braintree::Dispute.find(dispute.id)
|
36
36
|
refreshed_dispute.status.should == Braintree::Dispute::Status::Accepted
|
37
|
+
|
38
|
+
dispute_from_transaction = Braintree::Transaction.find(dispute.transaction.id).disputes[0]
|
39
|
+
dispute_from_transaction.status.should == Braintree::Dispute::Status::Accepted
|
37
40
|
end
|
38
41
|
|
39
42
|
it "returns an error response if the dispute is not in open status" do
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
|
+
|
3
|
+
describe Braintree::GraphQLClient do
|
4
|
+
before :each do
|
5
|
+
@config = Braintree::Configuration.instantiate
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "initialize" do
|
9
|
+
it "assigns overriding graphql headers" do
|
10
|
+
expect(@config.graphql_client.instance_variable_get("@graphql_headers")).to be_kind_of(Hash)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "query" do
|
15
|
+
it "makes valid GraphQL queries when given a definition" do
|
16
|
+
definition = <<-GRAPHQL
|
17
|
+
query {
|
18
|
+
ping
|
19
|
+
}
|
20
|
+
GRAPHQL
|
21
|
+
|
22
|
+
response = Braintree::GraphQLClient.new(@config).query(definition)
|
23
|
+
|
24
|
+
expect(response[:data]).to eq({:ping=>"pong"})
|
25
|
+
end
|
26
|
+
|
27
|
+
it "makes valid GraphQL requests when given a definitiona and variable" do
|
28
|
+
definition = <<-GRAPHQL
|
29
|
+
mutation CreateClientToken($input: CreateClientTokenInput!) {
|
30
|
+
createClientToken(input: $input) {
|
31
|
+
clientMutationId
|
32
|
+
clientToken
|
33
|
+
}
|
34
|
+
}
|
35
|
+
GRAPHQL
|
36
|
+
|
37
|
+
variables = {
|
38
|
+
input: {
|
39
|
+
clientMutationId: "abc123",
|
40
|
+
clientToken: {
|
41
|
+
merchantAccountId: "ABC123"
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
response = Braintree::GraphQLClient.new(@config).query(definition, variables)
|
47
|
+
|
48
|
+
expect(response[:data][:createClientToken][:clientToken]).to be_a(String)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "returns results parsable into validation errors" do
|
52
|
+
definition = <<-GRAPHQL
|
53
|
+
query TransactionLevelFeeReport($date: Date!, $merchantAccountId: ID) {
|
54
|
+
report {
|
55
|
+
transactionLevelFees(date: $date, merchantAccountId: $merchantAccountId) {
|
56
|
+
url
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
GRAPHQL
|
61
|
+
|
62
|
+
variables = {
|
63
|
+
date: "2018-01-01",
|
64
|
+
merchantAccountId: "some_merchant"
|
65
|
+
}
|
66
|
+
|
67
|
+
response = Braintree::GraphQLClient.new(@config).query(definition, variables)
|
68
|
+
errors = Braintree::ValidationErrorCollection.new(response)
|
69
|
+
|
70
|
+
expect(errors.size).to eq(1)
|
71
|
+
expect(errors.first.message).to eq("Invalid merchant account id: some_merchant")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|