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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f42a6a1794be0f659dc3cea9f5e84bff6e1d4e75
4
- data.tar.gz: efdb9c09c2b5961fc4358af6f7d397ac4a304c53
3
+ metadata.gz: f91adc9f9c4c198e0a23a83d154ed5dec5c1a90e
4
+ data.tar.gz: fe219448f54a560983e11cd15062abe6c89da036
5
5
  SHA512:
6
- metadata.gz: aaea5122d23bf61d943af46e50bd768b70efcfb2aede98c857e2ae36c84851b9871dffccafbfadeafca384101ec0b9dee2a5d69bd7ec3c664228836a5ef2da0d
7
- data.tar.gz: e10e87bb06504b7119ff25ae558422a12d6ff88f614580a30af194eb8985b9b6655fb94b3c5fe8d65d5be8d96ccb3fead07214a73e2c3ec289fc09946c4cf7df
6
+ metadata.gz: d337708211ff819d6db66faa86e5b60a06bf8e539de8df21b5f38cff8dfbd941908c628155dbbb69b63b13ad25d778dfae72f876e4fcbe97afd8c665c5901bff
7
+ data.tar.gz: fcdeb5b27036b32e6c3f0380e4885ef38640ed94d0e8486b624cf7908dd33a8c12dbcc0082a1c3456fc03ab2df90b4ee2d6b117fbb81e74bdd61fc4bcabebbcf
@@ -30,7 +30,11 @@ require "braintree/address_gateway"
30
30
  require "braintree/advanced_search"
31
31
  require "braintree/android_pay_card"
32
32
  require "braintree/amex_express_checkout_card"
33
+ require "braintree/apple_pay"
33
34
  require "braintree/apple_pay_card"
35
+ require "braintree/apple_pay_gateway"
36
+ require "braintree/apple_pay_options"
37
+ require "braintree/authorization_adjustment"
34
38
  require "braintree/client_token"
35
39
  require "braintree/client_token_gateway"
36
40
  require "braintree/coinbase_account"
@@ -51,7 +55,13 @@ require "braintree/digest"
51
55
  require "braintree/discount"
52
56
  require "braintree/discount_gateway"
53
57
  require "braintree/dispute"
58
+ require "braintree/dispute_gateway"
59
+ require "braintree/dispute/evidence"
60
+ require "braintree/dispute/history_event"
61
+ require "braintree/dispute/transaction"
54
62
  require "braintree/dispute/transaction_details"
63
+ require "braintree/document_upload"
64
+ require "braintree/document_upload_gateway"
55
65
  require "braintree/error_codes"
56
66
  require "braintree/error_result"
57
67
  require "braintree/errors"
@@ -80,6 +90,7 @@ require "braintree/paypal_account_gateway"
80
90
  require "braintree/plan"
81
91
  require "braintree/plan_gateway"
82
92
  require "braintree/risk_data"
93
+ require "braintree/facilitated_details"
83
94
  require "braintree/facilitator_details"
84
95
  require "braintree/three_d_secure_info"
85
96
  require "braintree/settlement_batch_summary"
@@ -125,6 +136,7 @@ require "braintree/transaction/visa_checkout_card_details"
125
136
  require "braintree/transaction/masterpass_card_details"
126
137
  require "braintree/unknown_payment_method"
127
138
  require "braintree/disbursement"
139
+ require "braintree/dispute_search"
128
140
  require "braintree/transparent_redirect"
129
141
  require "braintree/transparent_redirect_gateway"
130
142
  require "braintree/util"
@@ -0,0 +1,29 @@
1
+ module Braintree
2
+ class ApplePay
3
+ include BaseModule # :nodoc:
4
+
5
+ def initialize(gateway, attributes) # :nodoc:
6
+ set_instance_variables_from_hash(attributes)
7
+ end
8
+
9
+ class << self
10
+ protected :new
11
+ end
12
+
13
+ def self._new(*args) # :nodoc:
14
+ self.new *args
15
+ end
16
+
17
+ def self.register_domain(domain)
18
+ Configuration.gateway.apple_pay.register_domain(domain)
19
+ end
20
+
21
+ def self.unregister_domain(domain)
22
+ Configuration.gateway.apple_pay.unregister_domain(domain)
23
+ end
24
+
25
+ def self.registered_domains
26
+ Configuration.gateway.apple_pay.registered_domains
27
+ end
28
+ end
29
+ end
@@ -10,7 +10,7 @@ module Braintree
10
10
  All = constants.map { |c| const_get(c) }
11
11
  end
12
12
 
13
- attr_reader :card_type, :created_at, :customer_id, :default, :expiration_month,
13
+ attr_reader :bin, :card_type, :created_at, :customer_id, :default, :expiration_month,
14
14
  :expiration_year, :expired, :image_url, :last_4, :payment_instrument_name,
15
15
  :source_description, :subscriptions, :token, :updated_at
16
16
 
@@ -0,0 +1,37 @@
1
+ module Braintree
2
+ class ApplePayGateway
3
+ def initialize(gateway)
4
+ @gateway = gateway
5
+ @config = gateway.config
6
+ end
7
+
8
+ def register_domain(domain)
9
+ response = @config.http.post("#{@config.base_merchant_path}/processing/apple_pay/validate_domains", :url => domain)
10
+
11
+ if response.has_key?(:response) && response[:response][:success]
12
+ Braintree::SuccessfulResult.new
13
+ elsif response[:api_error_response]
14
+ ErrorResult.new(@gateway, response[:api_error_response])
15
+ else
16
+ raise "expected :response or :api_error_response"
17
+ end
18
+ end
19
+
20
+ def unregister_domain(domain)
21
+ @config.http.delete("#{@config.base_merchant_path}/processing/apple_pay/unregister_domain", :url => CGI.escape(domain))
22
+ SuccessfulResult.new
23
+ end
24
+
25
+ def registered_domains
26
+ response = @config.http.get("#{@config.base_merchant_path}/processing/apple_pay/registered_domains")
27
+
28
+ if response.has_key?(:response)
29
+ Braintree::SuccessfulResult.new(:apple_pay_options => ApplePayOptions._new(response[:response]))
30
+ elsif response[:api_error_response]
31
+ ErrorResult.new(@gateway, response[:api_error_response])
32
+ else
33
+ raise "expected :response or :api_error_response"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,19 @@
1
+ module Braintree
2
+ class ApplePayOptions
3
+ include BaseModule # :nodoc:
4
+
5
+ attr_reader :domains
6
+
7
+ def initialize(attributes) # :nodoc:
8
+ set_instance_variables_from_hash(attributes)
9
+ end
10
+
11
+ class << self
12
+ protected :new
13
+ end
14
+
15
+ def self._new(*args) # :nodoc:
16
+ self.new *args
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module Braintree
2
+ class AuthorizationAdjustment # :nodoc:
3
+ include BaseModule
4
+
5
+ attr_reader :amount
6
+ attr_reader :success
7
+ attr_reader :timestamp
8
+
9
+ class << self
10
+ protected :new
11
+ def _new(*args) # :nodoc:
12
+ self.new *args
13
+ end
14
+ end
15
+
16
+ def initialize(attributes) # :nodoc:
17
+ set_instance_variables_from_hash(attributes)
18
+ end
19
+ end
20
+ end
@@ -3,21 +3,40 @@ module Braintree
3
3
  include BaseModule
4
4
 
5
5
  attr_reader :amount
6
+ attr_reader :amount_disputed
7
+ attr_reader :amount_won
8
+ attr_reader :case_number
9
+ attr_reader :created_at
10
+ attr_reader :currency_iso_code
11
+ attr_reader :date_opened
12
+ attr_reader :date_won
13
+ attr_reader :evidence
14
+ attr_reader :forwarded_comments
15
+ attr_reader :id
16
+ attr_reader :kind
17
+ attr_reader :merchant_account_id
18
+ attr_reader :original_dispute_id
19
+ attr_reader :reason
20
+ attr_reader :reason_code
21
+ attr_reader :reason_description
6
22
  attr_reader :received_date
23
+ attr_reader :reference_number
7
24
  attr_reader :reply_by_date
8
25
  attr_reader :status
9
- attr_reader :reason
10
- attr_reader :currency_iso_code
11
- attr_reader :id
26
+ attr_reader :status_history
27
+ attr_reader :transaction
12
28
  attr_reader :transaction_details
13
- attr_reader :kind
14
- attr_reader :date_opened
15
- attr_reader :date_won
29
+ attr_reader :updated_at
16
30
 
17
31
  module Status
32
+ Accepted = "accepted"
33
+ Disputed = "disputed"
34
+ Expired = "expired"
18
35
  Open = "open"
19
36
  Lost = "lost"
20
37
  Won = "won"
38
+
39
+ All = constants.map { |c| const_get(c) }
21
40
  end
22
41
 
23
42
  module Reason
@@ -32,12 +51,16 @@ module Braintree
32
51
  ProductUnsatisfactory = "product_unsatisfactory"
33
52
  TransactionAmountDiffers = "transaction_amount_differs"
34
53
  Retrieval = "retrieval"
54
+
55
+ All = constants.map { |c| const_get(c) }
35
56
  end
36
57
 
37
58
  module Kind
38
59
  Chargeback = "chargeback"
39
60
  PreArbitration = "pre_arbitration"
40
61
  Retrieval = "retrieval"
62
+
63
+ All = constants.map { |c| const_get(c) }
41
64
  end
42
65
 
43
66
  class << self
@@ -47,14 +70,60 @@ module Braintree
47
70
  end
48
71
  end
49
72
 
73
+ def self.accept(dispute_id)
74
+ Configuration.gateway.dispute.accept(dispute_id)
75
+ end
76
+
77
+ def self.add_file_evidence(dispute_id, document_upload_id)
78
+ Configuration.gateway.dispute.add_file_evidence(dispute_id, document_upload_id)
79
+ end
80
+
81
+ def self.add_text_evidence(dispute_id, content)
82
+ Configuration.gateway.dispute.add_text_evidence(dispute_id, content)
83
+ end
84
+
85
+ def self.finalize(dispute_id)
86
+ Configuration.gateway.dispute.finalize(dispute_id)
87
+ end
88
+
89
+ def self.find(dispute_id)
90
+ Configuration.gateway.dispute.find(dispute_id)
91
+ end
92
+
93
+ def self.remove_evidence(dispute_id, evidence_id)
94
+ Configuration.gateway.dispute.remove_evidence(dispute_id, evidence_id)
95
+ end
96
+
97
+ def self.search(&block)
98
+ Configuration.gateway.dispute.search(&block)
99
+ end
100
+
50
101
  def initialize(attributes) # :nodoc:
51
102
  set_instance_variables_from_hash(attributes)
103
+ @date_opened = Date.parse(date_opened) unless date_opened.nil?
104
+ @date_won = Date.parse(date_won) unless date_won.nil?
52
105
  @received_date = Date.parse(received_date)
53
106
  @reply_by_date = Date.parse(reply_by_date) unless reply_by_date.nil?
54
107
  @amount = Util.to_big_decimal(amount)
55
- @transaction_details = TransactionDetails.new(@transaction)
56
- @date_opened = Date.parse(date_opened) unless date_opened.nil?
57
- @date_won = Date.parse(date_won) unless date_won.nil?
108
+ @amount_disputed = Util.to_big_decimal(amount_disputed)
109
+ @amount_won = Util.to_big_decimal(amount_won)
110
+
111
+ @evidence = evidence.map do |record|
112
+ Braintree::Dispute::Evidence.new(record)
113
+ end unless evidence.nil?
114
+
115
+ @transaction_details = TransactionDetails.new(transaction)
116
+ @transaction = Transaction.new(transaction)
117
+
118
+ @status_history = status_history.map do |event|
119
+ Braintree::Dispute::HistoryEvent.new(event)
120
+ end unless status_history.nil?
121
+ end
122
+
123
+ # Returns true if +other+ is a Dispute with the same id
124
+ def ==(other)
125
+ return false unless other.is_a?(Dispute)
126
+ id == other.id
58
127
  end
59
128
  end
60
129
  end
@@ -0,0 +1,18 @@
1
+ module Braintree
2
+ class Dispute
3
+ class Evidence # :nodoc:
4
+ include BaseModule
5
+
6
+ attr_reader :comment
7
+ attr_reader :created_at
8
+ attr_reader :id
9
+ attr_reader :sent_to_processor_at
10
+ attr_reader :url
11
+
12
+ def initialize(attributes)
13
+ set_instance_variables_from_hash attributes unless attributes.nil?
14
+ @sent_to_processor_at = Date.parse(sent_to_processor_at) unless sent_to_processor_at.nil?
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module Braintree
2
+ class Dispute
3
+ class HistoryEvent # :nodoc:
4
+ include BaseModule
5
+
6
+ attr_reader :status
7
+ attr_reader :timestamp
8
+
9
+ def initialize(attributes)
10
+ set_instance_variables_from_hash attributes unless attributes.nil?
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ module Braintree
2
+ class Dispute
3
+ class Transaction # :nodoc:
4
+ include BaseModule
5
+
6
+ attr_reader :amount
7
+ attr_reader :id
8
+ attr_reader :order_id
9
+ attr_reader :purchase_order_number
10
+ attr_reader :payment_instrument_subtype
11
+
12
+ def initialize(attributes)
13
+ set_instance_variables_from_hash attributes unless attributes.nil?
14
+ @amount = Util.to_big_decimal(amount)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,118 @@
1
+ module Braintree
2
+ class DisputeGateway # :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 accept(dispute_id)
10
+ raise ArgumentError, "dispute_id contains invalid characters" unless dispute_id.to_s =~ /\A[\w-]+\z/
11
+ raise ArgumentError, "dispute_id cannot be blank" if dispute_id.nil? || dispute_id.to_s.strip == ""
12
+
13
+ response = @config.http.put("#{@config.base_merchant_path}/disputes/#{dispute_id}/accept")
14
+ if response[:api_error_response]
15
+ ErrorResult.new(@gateway, response[:api_error_response])
16
+ else
17
+ SuccessfulResult.new
18
+ end
19
+ rescue NotFoundError
20
+ raise NotFoundError, "dispute with id #{dispute_id} not found"
21
+ end
22
+
23
+ def add_file_evidence(dispute_id, document_upload_id)
24
+ raise ArgumentError, "dispute_id contains invalid characters" unless dispute_id.to_s =~ /\A[\w-]+\z/
25
+ raise ArgumentError, "dispute_id cannot be blank" if dispute_id.nil? || dispute_id.to_s.strip == ""
26
+ raise ArgumentError, "document_upload_id contains invalid characters" unless document_upload_id.to_s =~ /\A[\w-]+\z/
27
+ raise ArgumentError, "document_upload_id cannot be blank" if document_upload_id.nil? || dispute_id.to_s.strip == ""
28
+
29
+ params = {document_upload_id: document_upload_id}
30
+ response = @config.http.post("#{@config.base_merchant_path}/disputes/#{dispute_id}/evidence", params)
31
+
32
+ if response[:evidence]
33
+ SuccessfulResult.new(:evidence => Dispute::Evidence.new(response[:evidence]))
34
+ elsif response[:api_error_response]
35
+ ErrorResult.new(@gateway, response[:api_error_response])
36
+ else
37
+ raise "expected :evidence or :api_error_response"
38
+ end
39
+ rescue NotFoundError
40
+ raise NotFoundError, "dispute with id #{dispute_id} not found"
41
+ end
42
+
43
+ def add_text_evidence(dispute_id, content)
44
+ raise ArgumentError, "dispute_id contains invalid characters" unless dispute_id.to_s =~ /\A[\w-]+\z/
45
+ raise ArgumentError, "dispute_id cannot be blank" if dispute_id.nil? || dispute_id.to_s.strip == ""
46
+ raise ArgumentError, "content cannot be blank" if content.nil? || content.to_s.strip == ""
47
+
48
+ params = {comments: content}
49
+ response = @config.http.post("#{@config.base_merchant_path}/disputes/#{dispute_id}/evidence", params)
50
+
51
+ if response[:evidence]
52
+ SuccessfulResult.new(:evidence => Dispute::Evidence.new(response[:evidence]))
53
+ elsif response[:api_error_response]
54
+ ErrorResult.new(@gateway, response[:api_error_response])
55
+ else
56
+ raise "expected :evidence or :api_error_response"
57
+ end
58
+ rescue NotFoundError
59
+ raise NotFoundError, "dispute with id #{dispute_id} not found"
60
+ end
61
+
62
+ def finalize(dispute_id)
63
+ raise ArgumentError, "dispute_id contains invalid characters" unless dispute_id.to_s =~ /\A[\w-]+\z/
64
+ raise ArgumentError, "dispute_id cannot be blank" if dispute_id.nil? || dispute_id.to_s.strip == ""
65
+
66
+ response = @config.http.put("#{@config.base_merchant_path}/disputes/#{dispute_id}/finalize")
67
+ if response[:api_error_response]
68
+ ErrorResult.new(@gateway, response[:api_error_response])
69
+ else
70
+ SuccessfulResult.new
71
+ end
72
+ rescue NotFoundError
73
+ raise NotFoundError, "dispute with id #{dispute_id} not found"
74
+ end
75
+
76
+ def find(dispute_id)
77
+ raise ArgumentError, "dispute_id contains invalid characters" unless dispute_id.to_s =~ /\A[\w-]+\z/
78
+ raise ArgumentError, "dispute_id cannot be blank" if dispute_id.nil? || dispute_id.to_s.strip == ""
79
+ response = @config.http.get("#{@config.base_merchant_path}/disputes/#{dispute_id}")
80
+ Dispute._new(response[:dispute])
81
+ rescue NotFoundError
82
+ raise NotFoundError, "dispute with id #{dispute_id} not found"
83
+ end
84
+
85
+ def remove_evidence(dispute_id, evidence_id)
86
+ raise ArgumentError, "dispute_id contains invalid characters" unless dispute_id.to_s =~ /\A[\w-]+\z/
87
+ raise ArgumentError, "dispute_id cannot be blank" if dispute_id.nil? || dispute_id.to_s.strip == ""
88
+ raise ArgumentError, "evidence_id contains invalid characters" unless evidence_id.to_s =~ /\A[\w-]+\z/
89
+ raise ArgumentError, "evidence_id cannot be blank" if evidence_id.nil? || evidence_id.to_s.strip == ""
90
+
91
+ response = @config.http.delete("#{@config.base_merchant_path}/disputes/#{dispute_id}/evidence/#{evidence_id}")
92
+
93
+ if response.respond_to?(:to_hash) && response[:api_error_response]
94
+ ErrorResult.new(@gateway, response[:api_error_response])
95
+ else
96
+ SuccessfulResult.new
97
+ end
98
+ rescue NotFoundError
99
+ raise NotFoundError, "evidence with id #{evidence_id} for dispute with id #{dispute_id} not found"
100
+ end
101
+
102
+ def search(&block)
103
+ search = DisputeSearch.new
104
+ block.call(search) if block
105
+
106
+ paginated_results = PaginatedCollection.new { |page| _fetch_disputes(search, page) }
107
+ SuccessfulResult.new(:disputes => paginated_results)
108
+ end
109
+
110
+ def _fetch_disputes(search, page)
111
+ response = @config.http.post("#{@config.base_merchant_path}/disputes/advanced_search?page=#{page}", {:search => search.to_hash, :page => page})
112
+ body = response[:disputes]
113
+ disputes = Util.extract_attribute_as_array(body, :dispute).map { |d| Dispute._new(d) }
114
+
115
+ PaginatedResult.new(body[:total_items], body[:page_size], disputes)
116
+ end
117
+ end
118
+ end