braintree 2.76.0 → 2.77.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/braintree.rb +12 -0
  3. data/lib/braintree/apple_pay.rb +29 -0
  4. data/lib/braintree/apple_pay_card.rb +1 -1
  5. data/lib/braintree/apple_pay_gateway.rb +37 -0
  6. data/lib/braintree/apple_pay_options.rb +19 -0
  7. data/lib/braintree/authorization_adjustment.rb +20 -0
  8. data/lib/braintree/dispute.rb +78 -9
  9. data/lib/braintree/dispute/evidence.rb +18 -0
  10. data/lib/braintree/dispute/history_event.rb +14 -0
  11. data/lib/braintree/dispute/transaction.rb +18 -0
  12. data/lib/braintree/dispute_gateway.rb +118 -0
  13. data/lib/braintree/dispute_search.rb +30 -0
  14. data/lib/braintree/document_upload.rb +34 -0
  15. data/lib/braintree/document_upload_gateway.rb +32 -0
  16. data/lib/braintree/error_codes.rb +17 -0
  17. data/lib/braintree/facilitated_details.rb +19 -0
  18. data/lib/braintree/gateway.rb +12 -0
  19. data/lib/braintree/http.rb +60 -12
  20. data/lib/braintree/successful_result.rb +1 -1
  21. data/lib/braintree/test/credit_card.rb +6 -0
  22. data/lib/braintree/transaction.rb +4 -0
  23. data/lib/braintree/version.rb +1 -1
  24. data/lib/braintree/webhook_testing_gateway.rb +196 -19
  25. data/spec/fixtures/files/bt_logo.png +0 -0
  26. data/spec/fixtures/files/gif_extension_bt_logo.gif +0 -0
  27. data/spec/fixtures/files/malformed_pdf.pdf +1 -0
  28. data/spec/httpsd.pid +1 -1
  29. data/spec/integration/braintree/apple_pay_spec.rb +92 -0
  30. data/spec/integration/braintree/coinbase_spec.rb +15 -12
  31. data/spec/integration/braintree/dispute_search_spec.rb +49 -0
  32. data/spec/integration/braintree/dispute_spec.rb +216 -0
  33. data/spec/integration/braintree/document_upload_spec.rb +55 -0
  34. data/spec/integration/braintree/http_spec.rb +8 -0
  35. data/spec/integration/braintree/payment_method_spec.rb +5 -16
  36. data/spec/integration/braintree/transaction_spec.rb +21 -4
  37. data/spec/spec_helper.rb +3 -2
  38. data/spec/unit/braintree/apple_pay_card_spec.rb +6 -0
  39. data/spec/unit/braintree/dispute_search_spec.rb +59 -0
  40. data/spec/unit/braintree/dispute_spec.rb +331 -8
  41. data/spec/unit/braintree/document_upload_spec.rb +35 -0
  42. data/spec/unit/braintree/http_spec.rb +21 -0
  43. data/spec/unit/braintree/transaction_spec.rb +17 -0
  44. data/spec/unit/braintree/webhook_notification_spec.rb +74 -51
  45. metadata +24 -3
@@ -0,0 +1,30 @@
1
+ module Braintree
2
+ class DisputeSearch < AdvancedSearch # :nodoc:
3
+ text_fields(
4
+ :case_number,
5
+ :id,
6
+ :reference_number,
7
+ :transaction_id
8
+ )
9
+
10
+ multiple_value_field :kind, :allows => Dispute::Kind::All
11
+ multiple_value_field :merchant_account_id
12
+ multiple_value_field :reason, :allows => Dispute::Reason::All
13
+ multiple_value_field :reason_code
14
+ multiple_value_field :status, :allows => Dispute::Status::All
15
+
16
+ multiple_value_field :transaction_source, :allows => [
17
+ Transaction::Source::Api,
18
+ Transaction::Source::ControlPanel,
19
+ Transaction::Source::Recurring,
20
+ Transaction::Source::Unrecognized,
21
+ ]
22
+
23
+ range_fields(
24
+ :amount_disputed,
25
+ :amount_won,
26
+ :received_date,
27
+ :reply_by_date
28
+ )
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ module Braintree
2
+ class DocumentUpload
3
+ include BaseModule
4
+
5
+ module Kind
6
+ IdentityDocument = "identity_document"
7
+ EvidenceDocument = "evidence_document"
8
+ PayoutInvoiceDocument = "payout_invoice_document"
9
+ end
10
+
11
+ attr_reader :id, :kind, :content_type, :name, :size
12
+
13
+ def self.create(attributes)
14
+ Configuration.gateway.document_upload.create(attributes)
15
+ end
16
+
17
+ def initialize(attributes) # :nodoc:
18
+ set_instance_variables_from_hash(attributes)
19
+ end
20
+
21
+ # True if <tt>other</tt> has the same id.
22
+ def ==(other)
23
+ return false unless other.is_a?(DocumentUpload)
24
+ id == other.id
25
+ end
26
+
27
+ class << self
28
+ protected :new
29
+ def _new(*args) # :nodoc:
30
+ self.new *args
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ module Braintree
2
+ class DocumentUploadGateway # :nodoc:
3
+ def initialize(gateway)
4
+ @gateway = gateway
5
+ @config = gateway.config
6
+ @config.assert_has_access_token_or_keys
7
+ end
8
+
9
+ def create(attributes)
10
+ Util.verify_keys(DocumentUploadGateway._create_signature, attributes)
11
+ _do_create "/document_uploads", {"document_upload[kind]" => attributes[:kind]}, attributes[:file]
12
+ end
13
+
14
+ def self._create_signature # :nodoc:
15
+ [
16
+ :kind,
17
+ :file
18
+ ]
19
+ end
20
+
21
+ def _do_create(path, params, file) # :nodoc:
22
+ response = @config.http.post("#{@config.base_merchant_path}#{path}", params, file)
23
+ if response[:document_upload]
24
+ SuccessfulResult.new(:document_upload => DocumentUpload._new(response[:document_upload]))
25
+ elsif response[:api_error_response]
26
+ ErrorResult.new(@gateway, response[:api_error_response])
27
+ else
28
+ raise UnexpectedError, "expected :document_upload or :api_error_response"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -146,6 +146,21 @@ module Braintree
146
146
  UrlFormatIsInvalid = "92206"
147
147
  end
148
148
 
149
+ module Dispute
150
+ CanOnlyAddEvidenceToOpenDispute = "95701"
151
+ CanOnlyRemoveEvidenceFromOpenDispute = "95702"
152
+ CanOnlyAddEvidenceDocumentToDispute = "95703"
153
+ CanOnlyAcceptOpenDispute = "95704"
154
+ CanOnlyFinalizeOpenDispute = "95705"
155
+ end
156
+
157
+ module DocumentUpload
158
+ KindIsInvalid = "84901"
159
+ FileIsTooLarge = "84902"
160
+ FileTypeIsInvalid = "84903"
161
+ FileIsMalformedOrEncrypted = "84904"
162
+ end
163
+
149
164
  module PayPalAccount
150
165
  AuthExpired = "92911"
151
166
  CannotHaveBothAccessTokenAndConsentCode = "82903"
@@ -292,6 +307,7 @@ module Braintree
292
307
  CustomerIdIsInvalid = "91510"
293
308
  HasAlreadyBeenRefunded = "91512"
294
309
  IdealPaymentNotComplete = "815141"
310
+ IdealPaymentsCannotBeVaulted = "915150"
295
311
  MerchantAccountDoesNotMatch3DSecureMerchantAccount = "91584"
296
312
  MerchantAccountDoesNotMatchIdealPaymentMerchantAccount = "915143"
297
313
  MerchantAccountDoesNotSupportMOTO = "91558"
@@ -548,6 +564,7 @@ module Braintree
548
564
  PaymentMethodNonceUnknown = "93108"
549
565
  PaymentMethodNonceLocked = "93109"
550
566
  CannotForwardPaymentMethodType = "93107"
567
+ PaymentMethodNoLongerSupported = "93117"
551
568
  end
552
569
 
553
570
  module AuthorizationFingerprint
@@ -0,0 +1,19 @@
1
+ module Braintree
2
+ class FacilitatedDetails # :nodoc:
3
+ include BaseModule
4
+
5
+ attr_reader :merchant_id, :merchant_name, :payment_method_nonce
6
+
7
+ def initialize(attributes)
8
+ set_instance_variables_from_hash attributes unless attributes.nil?
9
+ end
10
+
11
+ def inspect
12
+ attr_order = [:merchant_id, :merchant_name, :payment_method_nonce]
13
+ formatted_attrs = attr_order.map do |attr|
14
+ "#{attr}: #{send(attr).inspect}"
15
+ end
16
+ "#<FacilitatorDetails #{formatted_attrs.join(", ")}>"
17
+ end
18
+ end
19
+ end
@@ -20,6 +20,10 @@ module Braintree
20
20
  AddressGateway.new(self)
21
21
  end
22
22
 
23
+ def apple_pay
24
+ ApplePayGateway.new(self)
25
+ end
26
+
23
27
  def client_token
24
28
  ClientTokenGateway.new(self)
25
29
  end
@@ -36,6 +40,14 @@ module Braintree
36
40
  DiscountGateway.new(self)
37
41
  end
38
42
 
43
+ def dispute
44
+ DisputeGateway.new(self)
45
+ end
46
+
47
+ def document_upload
48
+ DocumentUploadGateway.new(self)
49
+ end
50
+
39
51
  def oauth
40
52
  OAuthGateway.new(self)
41
53
  end
@@ -1,20 +1,25 @@
1
1
  module Braintree
2
2
  class Http # :nodoc:
3
3
 
4
+ LINE_FEED = "\r\n"
5
+
4
6
  def initialize(config)
5
7
  @config = config
6
8
  end
7
9
 
8
- def delete(path)
10
+ def delete(_path, query_params = {})
11
+ path = _path + _build_query_string(query_params)
9
12
  response = _http_do Net::HTTP::Delete, path
10
- if response.code.to_i == 200
13
+ if response.code.to_i == 200 || response.code.to_i == 204
11
14
  true
15
+ elsif response.code.to_i == 422
16
+ Xml.hash_from_xml(_body(response))
12
17
  else
13
18
  Util.raise_exception_for_status_code(response.code)
14
19
  end
15
20
  end
16
21
 
17
- def get(_path, query_params={})
22
+ def get(_path, query_params = {})
18
23
  path = _path + _build_query_string(query_params)
19
24
  response = _http_do Net::HTTP::Get, path
20
25
  if response.code.to_i == 200 || response.code.to_i == 422
@@ -24,8 +29,12 @@ module Braintree
24
29
  end
25
30
  end
26
31
 
27
- def post(path, params = nil)
28
- response = _http_do Net::HTTP::Post, path, _build_xml(params)
32
+ def post(path, params = nil, file = nil)
33
+ body = params
34
+ if !file
35
+ body = _build_xml(params)
36
+ end
37
+ response = _http_do Net::HTTP::Post, path, body, file
29
38
  if response.code.to_i == 200 || response.code.to_i == 201 || response.code.to_i == 422
30
39
  Xml.hash_from_xml(_body(response))
31
40
  else
@@ -58,7 +67,7 @@ module Braintree
58
67
  end
59
68
  end
60
69
 
61
- def _http_do(http_verb, path, body = nil)
70
+ def _http_do(http_verb, path, body = nil, file = nil)
62
71
  if @config.proxy_address
63
72
  connection = Net::HTTP.new(
64
73
  @config.server,
@@ -96,9 +105,22 @@ module Braintree
96
105
  end
97
106
  @config.logger.debug "[Braintree] [#{_current_time}] #{request.method} #{path}"
98
107
  if body
99
- request["Content-Type"] = "application/xml"
100
- request.body = body
101
- @config.logger.debug _format_and_sanitize_body_for_log(body)
108
+ if file
109
+ boundary = DateTime.now.strftime("%Q")
110
+ request["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
111
+
112
+ form_params = []
113
+ body.each do |k, v|
114
+ form_params.push(_add_form_field(k, v))
115
+ end
116
+ form_params.push(_add_file_part("file", file))
117
+ request.body = form_params.collect {|p| "--" + boundary + "#{LINE_FEED}" + p}.join("") + "--" + boundary + "--"
118
+ @config.logger.debug _format_and_sanitize_body_for_log(_build_xml(body))
119
+ else
120
+ request["Content-Type"] = "application/xml"
121
+ request.body = body
122
+ @config.logger.debug _format_and_sanitize_body_for_log(body)
123
+ end
102
124
  end
103
125
  response = http.request(request)
104
126
  @config.logger.info "[Braintree] [#{_current_time}] #{request.method} #{path} #{response.code}"
@@ -112,9 +134,35 @@ module Braintree
112
134
  raise Braintree::SSLCertificateError
113
135
  end
114
136
 
137
+ def _add_form_field(key, value)
138
+ return "Content-Disposition: form-data; name=\"#{key}\"#{LINE_FEED}#{LINE_FEED}#{value}#{LINE_FEED}"
139
+ end
140
+
141
+ def _add_file_part(key, file)
142
+ mime_type = _mime_type_for_file_name(file.path)
143
+ return "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{file.path}\"#{LINE_FEED}" +
144
+ "Content-Type: #{mime_type}#{LINE_FEED}#{LINE_FEED}#{file.read}#{LINE_FEED}"
145
+ end
146
+
147
+ def _mime_type_for_file_name(filename)
148
+ file_extension = File.extname(filename).strip.downcase[1..-1]
149
+ if file_extension == "jpeg" || file_extension == "jpg"
150
+ return "image/jpeg"
151
+ elsif file_extension == "png"
152
+ return "image/png"
153
+ elsif file_extension == "pdf"
154
+ return "application/pdf"
155
+ else
156
+ return "application/octet-stream"
157
+ end
158
+ end
159
+
115
160
  def _body(response)
116
- if response.header["Content-Encoding"] == "gzip"
161
+ content_encoding = response.header["Content-Encoding"]
162
+ if content_encoding == "gzip"
117
163
  Zlib::GzipReader.new(StringIO.new(response.body)).read
164
+ elsif content_encoding.nil?
165
+ ""
118
166
  else
119
167
  raise UnexpectedError, "expected a gzipped response"
120
168
  end
@@ -126,8 +174,8 @@ module Braintree
126
174
 
127
175
  def _format_and_sanitize_body_for_log(input_xml)
128
176
  formatted_xml = input_xml.gsub(/^/, "[Braintree] ")
129
- formatted_xml = formatted_xml.gsub(/<number>(.{6}).+?(.{4})<\/number>/, '<number>\1******\2</number>')
130
- formatted_xml = formatted_xml.gsub(/<cvv>.+?<\/cvv>/, '<cvv>***</cvv>')
177
+ formatted_xml = formatted_xml.gsub(/<number>(.{6}).+?(.{4})<\/number>/m, '<number>\1******\2</number>')
178
+ formatted_xml = formatted_xml.gsub(/<cvv>.+?<\/cvv>/m, '<cvv>***</cvv>')
131
179
  formatted_xml
132
180
  end
133
181
 
@@ -2,7 +2,7 @@ module Braintree
2
2
  class SuccessfulResult
3
3
  include BaseModule
4
4
 
5
- attr_reader :address, :credit_card, :customer, :merchant_account, :payment_method, :settlement_batch_summary, :subscription, :new_transaction, :transaction, :payment_method_nonce, :credentials, :merchant, :supported_networks, :paypal_account, :merchant_accounts
5
+ attr_reader :address, :credit_card, :customer, :document_upload, :merchant_account, :payment_method, :settlement_batch_summary, :subscription, :new_transaction, :transaction, :payment_method_nonce, :credentials, :merchant, :supported_networks, :paypal_account, :merchant_accounts, :disputes, :evidence, :apple_pay_options
6
6
 
7
7
  def initialize(attributes = {}) # :nodoc:
8
8
  @attrs = attributes.keys
@@ -54,6 +54,12 @@ module Braintree
54
54
  All = [Success, IneligibleCard, InsufficientPoints]
55
55
  end
56
56
 
57
+ module Disputes
58
+ Chargeback = "4023898493988028"
59
+
60
+ Numbers = [Chargeback]
61
+ end
62
+
57
63
  All = AmExes + Discovers + MasterCards + Visas + AmexPayWithPoints::All
58
64
  end
59
65
 
@@ -120,12 +120,14 @@ module Braintree
120
120
  attr_reader :add_ons, :discounts
121
121
  attr_reader :payment_instrument_type
122
122
  attr_reader :risk_data
123
+ attr_reader :facilitated_details
123
124
  attr_reader :facilitator_details
124
125
  attr_reader :three_d_secure_info
125
126
  attr_reader :us_bank_account_details
126
127
  attr_reader :ideal_payment_details
127
128
  attr_reader :visa_checkout_card_details
128
129
  attr_reader :masterpass_card_details
130
+ attr_reader :authorization_adjustments
129
131
 
130
132
  def self.create(attributes)
131
133
  Configuration.gateway.transaction.create(attributes)
@@ -269,12 +271,14 @@ module Braintree
269
271
  discounts.map! { |attrs| Discount._new(attrs) } if discounts
270
272
  @payment_instrument_type = attributes[:payment_instrument_type]
271
273
  @risk_data = RiskData.new(attributes[:risk_data]) if attributes[:risk_data]
274
+ @facilitated_details = FacilitatedDetails.new(attributes[:facilitated_details]) if attributes[:facilitated_details]
272
275
  @facilitator_details = FacilitatorDetails.new(attributes[:facilitator_details]) if attributes[:facilitator_details]
273
276
  @three_d_secure_info = ThreeDSecureInfo.new(attributes[:three_d_secure_info]) if attributes[:three_d_secure_info]
274
277
  @us_bank_account_details = UsBankAccountDetails.new(attributes[:us_bank_account]) if attributes[:us_bank_account]
275
278
  @ideal_payment_details = IdealPaymentDetails.new(attributes[:ideal_payment]) if attributes[:ideal_payment]
276
279
  @visa_checkout_card_details = VisaCheckoutCardDetails.new(attributes[:visa_checkout_card])
277
280
  @masterpass_card_details = MasterpassCardDetails.new(attributes[:masterpass_card])
281
+ authorization_adjustments.map! { |attrs| AuthorizationAdjustment._new(attrs) } if authorization_adjustments
278
282
  end
279
283
 
280
284
  # True if <tt>other</tt> is a Braintree::Transaction with the same id.
@@ -1,7 +1,7 @@
1
1
  module Braintree
2
2
  module Version
3
3
  Major = 2
4
- Minor = 76
4
+ Minor = 77
5
5
  Tiny = 0
6
6
 
7
7
  String = "#{Major}.#{Minor}.#{Tiny}"
@@ -241,10 +241,33 @@ module Braintree
241
241
  end
242
242
 
243
243
  def _dispute_opened_sample_xml(id)
244
+ if id == "legacy_dispute_id"
245
+ _old_dispute_opened_sample_xml(id)
246
+ else
247
+ _new_dispute_opened_sample_xml(id)
248
+ end
249
+ end
250
+
251
+ def _dispute_lost_sample_xml(id)
252
+ if id == "legacy_dispute_id"
253
+ _old_dispute_lost_sample_xml(id)
254
+ else
255
+ _new_dispute_lost_sample_xml(id)
256
+ end
257
+ end
258
+
259
+ def _dispute_won_sample_xml(id)
260
+ if id == "legacy_dispute_id"
261
+ _old_dispute_won_sample_xml(id)
262
+ else
263
+ _new_dispute_won_sample_xml(id)
264
+ end
265
+ end
244
266
 
267
+ def _old_dispute_opened_sample_xml(id)
245
268
  <<-XML
246
269
  <dispute>
247
- <amount>250.00</amount>
270
+ <amount>100.00</amount>
248
271
  <currency-iso-code>USD</currency-iso-code>
249
272
  <received-date type="date">2014-03-01</received-date>
250
273
  <reply-by-date type="date">2014-03-21</reply-by-date>
@@ -254,18 +277,17 @@ module Braintree
254
277
  <id>#{id}</id>
255
278
  <transaction>
256
279
  <id>#{id}</id>
257
- <amount>250.00</amount>
280
+ <amount>100.00</amount>
258
281
  </transaction>
259
282
  <date-opened type=\"date\">2014-03-21</date-opened>
260
283
  </dispute>
261
284
  XML
262
285
  end
263
286
 
264
- def _dispute_lost_sample_xml(id)
265
-
287
+ def _old_dispute_lost_sample_xml(id)
266
288
  <<-XML
267
289
  <dispute>
268
- <amount>250.00</amount>
290
+ <amount>100.00</amount>
269
291
  <currency-iso-code>USD</currency-iso-code>
270
292
  <received-date type="date">2014-03-01</received-date>
271
293
  <reply-by-date type="date">2014-03-21</reply-by-date>
@@ -275,18 +297,17 @@ module Braintree
275
297
  <id>#{id}</id>
276
298
  <transaction>
277
299
  <id>#{id}</id>
278
- <amount>250.00</amount>
300
+ <amount>100.00</amount>
279
301
  </transaction>
280
302
  <date-opened type=\"date\">2014-03-21</date-opened>
281
303
  </dispute>
282
304
  XML
283
305
  end
284
306
 
285
- def _dispute_won_sample_xml(id)
286
-
307
+ def _old_dispute_won_sample_xml(id)
287
308
  <<-XML
288
309
  <dispute>
289
- <amount>250.00</amount>
310
+ <amount>100.00</amount>
290
311
  <currency-iso-code>USD</currency-iso-code>
291
312
  <received-date type="date">2014-03-01</received-date>
292
313
  <reply-by-date type="date">2014-03-21</reply-by-date>
@@ -296,7 +317,172 @@ module Braintree
296
317
  <id>#{id}</id>
297
318
  <transaction>
298
319
  <id>#{id}</id>
299
- <amount>250.00</amount>
320
+ <amount>100.00</amount>
321
+ </transaction>
322
+ <date-opened type=\"date\">2014-03-21</date-opened>
323
+ <date-won type=\"date\">2014-03-22</date-won>
324
+ </dispute>
325
+ XML
326
+ end
327
+
328
+ def _new_dispute_opened_sample_xml(id)
329
+ <<-XML
330
+ <dispute>
331
+ <id>#{id}</id>
332
+ <amount>100.00</amount>
333
+ <amount-disputed>100.00</amount-disputed>
334
+ <amount-won>95.00</amount-won>
335
+ <case-number>CASE-12345</case-number>
336
+ <created-at type="datetime">2017-06-16T20:44:41Z</created-at>
337
+ <currency-iso-code>USD</currency-iso-code>
338
+ <forwarded-comments nil="true"/>
339
+ <kind>chargeback</kind>
340
+ <merchant-account-id>ytnlulaloidoqwvzxjrdqputg</merchant-account-id>
341
+ <reason>fraud</reason>
342
+ <reason-code nil="true"/>
343
+ <reason-description nil="true"/>
344
+ <received-date type="date">2016-02-15</received-date>
345
+ <reference-number>REF-9876</reference-number>
346
+ <reply-by-date type="date">2016-02-22</reply-by-date>
347
+ <status>open</status>
348
+ <updated-at type="datetime">2017-06-16T20:44:41Z</updated-at>
349
+ <original-dispute-id>9qde5qgp</original-dispute-id>
350
+ <status-history type="array">
351
+ <status-history>
352
+ <status>open</status>
353
+ <timestamp type="datetime">2017-06-16T20:44:41Z</timestamp>
354
+ </status-history>
355
+ </status-history>
356
+ <evidence type="array"/>
357
+ <transaction>
358
+ <id>#{id}</id>
359
+ <amount>100.00</amount>
360
+ <created-at>2017-06-21T20:44:41Z</created-at>
361
+ <order-id nil="true"/>
362
+ <purchase-order-number nil="true"/>
363
+ <payment-instrument-subtype>Visa</payment-instrument-subtype>
364
+ </transaction>
365
+ <date-opened type=\"date\">2014-03-21</date-opened>
366
+ </dispute>
367
+ XML
368
+ end
369
+
370
+ def _new_dispute_lost_sample_xml(id)
371
+ <<-XML
372
+ <dispute>
373
+ <id>#{id}</id>
374
+ <amount>100.00</amount>
375
+ <amount-disputed>100.00</amount-disputed>
376
+ <amount-won>95.00</amount-won>
377
+ <case-number>CASE-12345</case-number>
378
+ <created-at type="datetime">2017-06-16T20:44:41Z</created-at>
379
+ <currency-iso-code>USD</currency-iso-code>
380
+ <forwarded-comments nil="true"/>
381
+ <kind>chargeback</kind>
382
+ <merchant-account-id>ytnlulaloidoqwvzxjrdqputg</merchant-account-id>
383
+ <reason>fraud</reason>
384
+ <reason-code nil="true"/>
385
+ <reason-description nil="true"/>
386
+ <received-date type="date">2016-02-15</received-date>
387
+ <reference-number>REF-9876</reference-number>
388
+ <reply-by-date type="date">2016-02-22</reply-by-date>
389
+ <status>lost</status>
390
+ <updated-at type="datetime">2017-06-21T20:44:41Z</updated-at>
391
+ <original-dispute-id>9qde5qgp</original-dispute-id>
392
+ <status-history type="array">
393
+ <status-history>
394
+ <status>open</status>
395
+ <timestamp type="datetime">2017-06-16T20:44:41Z</timestamp>
396
+ </status-history>
397
+ <status-history>
398
+ <status>lost</status>
399
+ <timestamp type="datetime">2017-06-25T20:50:55Z</timestamp>
400
+ </status-history>
401
+ </status-history>
402
+ <evidence type="array">
403
+ <evidence>
404
+ <id>rxtngk9j5j93tsrq</id>
405
+ <comments nil="true"/>
406
+ <created-at type="datetime">2017-06-21T20:44:42Z</created-at>
407
+ <sent-to-processor-at nil="true"/>
408
+ <url>s3.amazonaws.com/foo.jpg</url>
409
+ </evidence>
410
+ <evidence>
411
+ <id>88cfb8dd</id>
412
+ <comments>text evidence</comments>
413
+ <created-at type="datetime">2017-06-21T20:44:42Z</created-at>
414
+ <sent-to-processor-at nil="true"/>
415
+ <url nil="true"/>
416
+ </evidence>
417
+ </evidence>
418
+ <transaction>
419
+ <id>#{id}</id>
420
+ <amount>100.00</amount>
421
+ <created-at>2017-06-21T20:44:41Z</created-at>
422
+ <order-id nil="true"/>
423
+ <purchase-order-number nil="true"/>
424
+ <payment-instrument-subtype>Visa</payment-instrument-subtype>
425
+ </transaction>
426
+ <date-opened type=\"date\">2014-03-21</date-opened>
427
+ </dispute>
428
+ XML
429
+ end
430
+
431
+ def _new_dispute_won_sample_xml(id)
432
+ <<-XML
433
+ <dispute>
434
+ <id>#{id}</id>
435
+ <amount>100.00</amount>
436
+ <amount-disputed>100.00</amount-disputed>
437
+ <amount-won>95.00</amount-won>
438
+ <case-number>CASE-12345</case-number>
439
+ <created-at type="datetime">2017-06-16T20:44:41Z</created-at>
440
+ <currency-iso-code>USD</currency-iso-code>
441
+ <forwarded-comments nil="true"/>
442
+ <kind>chargeback</kind>
443
+ <merchant-account-id>ytnlulaloidoqwvzxjrdqputg</merchant-account-id>
444
+ <reason>fraud</reason>
445
+ <reason-code nil="true"/>
446
+ <reason-description nil="true"/>
447
+ <received-date type="date">2016-02-15</received-date>
448
+ <reference-number>REF-9876</reference-number>
449
+ <reply-by-date type="date">2016-02-22</reply-by-date>
450
+ <status>won</status>
451
+ <updated-at type="datetime">2017-06-21T20:44:41Z</updated-at>
452
+ <original-dispute-id>9qde5qgp</original-dispute-id>
453
+ <status-history type="array">
454
+ <status-history>
455
+ <status>open</status>
456
+ <timestamp type="datetime">2017-06-16T20:44:41Z</timestamp>
457
+ </status-history>
458
+ <status-history>
459
+ <status>won</status>
460
+ <timestamp type="datetime">2017-06-25T20:50:55Z</timestamp>
461
+ </status-history>
462
+ </status-history>
463
+ <evidence type="array">
464
+ <evidence>
465
+ <id>rxtngk9j5j93tsrq</id>
466
+ <comments nil="true"/>
467
+ <created-at type="datetime">2017-06-21T20:44:42Z</created-at>
468
+ <sent-to-processor-at nil="true"/>
469
+ <url>s3.amazonaws.com/foo.jpg</url>
470
+ </evidence>
471
+ <evidence>
472
+ <id>88cfb8dd</id>
473
+ <comments>text evidence</comments>
474
+ <created-at type="datetime">2017-06-21T20:44:42Z</created-at>
475
+ <sent-to-processor-at nil="true"/>
476
+ <url nil="true"/>
477
+ </evidence>
478
+ </evidence>
479
+ <transaction>
480
+ <id>#{id}</id>
481
+ <amount>100.00</amount>
482
+ <created-at>2017-06-21T20:44:41Z</created-at>
483
+ <order-id nil="true"/>
484
+ <purchase-order-number nil="true"/>
485
+ <payment-instrument-subtype>Visa</payment-instrument-subtype>
300
486
  </transaction>
301
487
  <date-opened type=\"date\">2014-03-21</date-opened>
302
488
  <date-won type=\"date\">2014-03-22</date-won>
@@ -395,15 +581,6 @@ module Braintree
395
581
  <currency>EUR</currency>
396
582
  <amount>10.00</amount>
397
583
  <created-at>2016-11-29T23:27:34.547Z</created-at>
398
- <iban-bank-account>
399
- <created-at>2016-11-29T23:27:36.386Z</created-at>
400
- <description>DESCRIPTION ABC</description>
401
- <bic>XXXXNLXX</bic>
402
- <iban-country>11</iban-country>
403
- <iban-account-number-last-4>0000</iban-account-number-last-4>
404
- <masked-iban>NL************0000</masked-iban>
405
- <account-holder-name>Account Holder</account-holder-name>
406
- </iban-bank-account>
407
584
  <approval-url>https://example.com</approval-url>
408
585
  <ideal-transaction-id>1234567890</ideal-transaction-id>
409
586
  </ideal-payment>