braintree 2.31.0 → 2.32.1

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 (51) hide show
  1. data/README.rdoc +2 -2
  2. data/lib/braintree.rb +12 -0
  3. data/lib/braintree/client_token.rb +5 -0
  4. data/lib/braintree/client_token_gateway.rb +2 -1
  5. data/lib/braintree/configuration.rb +1 -1
  6. data/lib/braintree/credit_card.rb +1 -1
  7. data/lib/braintree/credit_card_gateway.rb +3 -3
  8. data/lib/braintree/customer.rb +18 -4
  9. data/lib/braintree/customer_gateway.rb +2 -2
  10. data/lib/braintree/customer_search.rb +1 -0
  11. data/lib/braintree/error_codes.rb +81 -14
  12. data/lib/braintree/exceptions.rb +2 -0
  13. data/lib/braintree/gateway.rb +16 -0
  14. data/lib/braintree/payment_instrument_type.rb +7 -0
  15. data/lib/braintree/payment_method.rb +17 -0
  16. data/lib/braintree/payment_method_gateway.rb +58 -0
  17. data/lib/braintree/paypal_account.rb +47 -0
  18. data/lib/braintree/paypal_account_gateway.rb +41 -0
  19. data/lib/braintree/sepa_bank_account.rb +34 -0
  20. data/lib/braintree/sepa_bank_account_gateway.rb +16 -0
  21. data/lib/braintree/successful_result.rb +1 -1
  22. data/lib/braintree/test/nonce.rb +10 -0
  23. data/lib/braintree/test_transaction.rb +15 -0
  24. data/lib/braintree/testing_gateway.rb +35 -0
  25. data/lib/braintree/transaction.rb +6 -0
  26. data/lib/braintree/transaction/paypal_details.rb +14 -0
  27. data/lib/braintree/transaction_gateway.rb +3 -1
  28. data/lib/braintree/transaction_search.rb +4 -0
  29. data/lib/braintree/unknown_payment_method.rb +20 -0
  30. data/lib/braintree/version.rb +2 -2
  31. data/lib/braintree/webhook_testing_gateway.rb +1 -1
  32. data/spec/integration/braintree/client_api/client_token_spec.rb +80 -17
  33. data/spec/integration/braintree/client_api/spec_helper.rb +93 -10
  34. data/spec/integration/braintree/credit_card_spec.rb +28 -27
  35. data/spec/integration/braintree/customer_search_spec.rb +23 -0
  36. data/spec/integration/braintree/customer_spec.rb +83 -1
  37. data/spec/integration/braintree/payment_method_spec.rb +315 -0
  38. data/spec/integration/braintree/paypal_account_spec.rb +188 -0
  39. data/spec/integration/braintree/subscription_spec.rb +50 -20
  40. data/spec/integration/braintree/test_transaction_spec.rb +104 -0
  41. data/spec/integration/braintree/transaction_search_spec.rb +60 -0
  42. data/spec/integration/braintree/transaction_spec.rb +583 -8
  43. data/spec/integration/spec_helper.rb +22 -0
  44. data/spec/spec_helper.rb +8 -2
  45. data/spec/unit/braintree/customer_spec.rb +24 -4
  46. data/spec/unit/braintree/payment_method_spec.rb +25 -0
  47. data/spec/unit/braintree/paypal_account_spec.rb +31 -0
  48. data/spec/unit/braintree/unknown_payment_method_spec.rb +29 -0
  49. metadata +141 -120
  50. checksums.yaml +0 -7
  51. data/spec/httpsd.pid +0 -1
@@ -1,22 +1,58 @@
1
1
  require 'json'
2
2
 
3
- def nonce_for_new_credit_card(options)
3
+ def decode_client_token(raw_client_token)
4
+ decoded_client_token_string = Base64.decode64(raw_client_token)
5
+ JSON.parse(decoded_client_token_string)
6
+ end
7
+
8
+ def nonce_for_new_payment_method(options)
9
+ client = _initialize_client(options)
10
+ response = client.add_payment_method(options)
11
+
12
+ _nonce_from_response(response)
13
+ end
14
+
15
+ def _initialize_client(options)
4
16
  client_token_options = options.delete(:client_token_options) || {}
5
- client_token = Braintree::ClientToken.generate(client_token_options)
6
- client = ClientApiHttp.new(Braintree::Configuration.instantiate,
7
- :authorization_fingerprint => JSON.parse(client_token)["authorizationFingerprint"],
17
+ raw_client_token = Braintree::ClientToken.generate(client_token_options)
18
+ client_token = decode_client_token(raw_client_token)
19
+
20
+ ClientApiHttp.new(Braintree::Configuration.instantiate,
21
+ :authorization_fingerprint => client_token["authorizationFingerprint"],
8
22
  :shared_customer_identifier => "fake_identifier",
9
23
  :shared_customer_identifier_type => "testing"
10
24
  )
25
+ end
11
26
 
12
- response = client.add_card(options)
27
+ def _nonce_from_response(response)
13
28
  body = JSON.parse(response.body)
14
29
 
15
30
  if body["errors"] != nil
16
31
  raise body["errors"].inspect
17
32
  end
18
33
 
19
- body["nonce"]
34
+ if body.has_key?("paypalAccounts")
35
+ body["paypalAccounts"][0]["nonce"]
36
+ else
37
+ body["creditCards"][0]["nonce"]
38
+ end
39
+ end
40
+
41
+ def nonce_for_paypal_account(paypal_account_details)
42
+ raw_client_token = Braintree::ClientToken.generate
43
+ client_token = decode_client_token(raw_client_token)
44
+ client = ClientApiHttp.new(Braintree::Configuration.instantiate,
45
+ :authorization_fingerprint => client_token["authorizationFingerprint"]
46
+ )
47
+
48
+ response = client.create_paypal_account(paypal_account_details)
49
+ body = JSON.parse(response.body)
50
+
51
+ if body["errors"] != nil
52
+ raise body["errors"].inspect
53
+ end
54
+
55
+ body["paypalAccounts"][0]["nonce"]
20
56
  end
21
57
 
22
58
  class ClientApiHttp
@@ -35,6 +71,10 @@ class ClientApiHttp
35
71
  _http_do(Net::HTTP::Post, path, params.to_json)
36
72
  end
37
73
 
74
+ def put(path, params)
75
+ _http_do(Net::HTTP::Put, path, params.to_json)
76
+ end
77
+
38
78
  def fingerprint=(fingerprint)
39
79
  @options[:authorization_fingerprint] = fingerprint
40
80
  end
@@ -59,9 +99,9 @@ class ClientApiHttp
59
99
  raise Braintree::SSLCertificateError
60
100
  end
61
101
 
62
- def get_cards
102
+ def get_payment_methods
63
103
  encoded_fingerprint = Braintree::Util.url_encode(@options[:authorization_fingerprint])
64
- url = "/merchants/#{@config.merchant_id}/client_api/nonces.json?"
104
+ url = "/merchants/#{@config.merchant_id}/client_api/v1/payment_methods?"
65
105
  url += "authorizationFingerprint=#{encoded_fingerprint}"
66
106
  url += "&sharedCustomerIdentifier=#{@options[:shared_customer_identifier]}"
67
107
  url += "&sharedCustomerIdentifierType=#{@options[:shared_customer_identifier_type]}"
@@ -69,12 +109,55 @@ class ClientApiHttp
69
109
  get(url)
70
110
  end
71
111
 
72
- def add_card(params)
112
+ def add_payment_method(params)
73
113
  fingerprint = @options[:authorization_fingerprint]
74
114
  params[:authorizationFingerprint] = fingerprint
75
115
  params[:sharedCustomerIdentifier] = @options[:shared_customer_identifier]
76
116
  params[:sharedCustomerIdentifierType] = @options[:shared_customer_identifier_type]
77
117
 
78
- post("/merchants/#{@config.merchant_id}/client_api/nonces.json", params)
118
+ payment_method_type = nil
119
+ if params.has_key?(:paypal_account)
120
+ payment_method_type = "paypal_accounts"
121
+ else
122
+ payment_method_type = "credit_cards"
123
+ end
124
+
125
+ post("/merchants/#{@config.merchant_id}/client_api/v1/payment_methods/#{payment_method_type}", params)
126
+ end
127
+
128
+ def create_credit_card(params)
129
+ params = {:credit_card => params}
130
+ params.merge!(
131
+ :authorization_fingerprint => @options[:authorization_fingerprint],
132
+ :shared_customer_identifier => "fake_identifier",
133
+ :shared_customer_identifier_type => "testing"
134
+ )
135
+
136
+ post("/merchants/#{config.merchant_id}/client_api/v1/payment_methods/credit_cards", params)
137
+ end
138
+
139
+ def create_paypal_account(params)
140
+ params = {:paypal_account => params}
141
+ params.merge!(
142
+ :authorization_fingerprint => @options[:authorization_fingerprint]
143
+ )
144
+
145
+ post("/merchants/#{config.merchant_id}/client_api/v1/payment_methods/paypal_accounts", params)
146
+ end
147
+
148
+ def create_sepa_bank_account_nonce(params)
149
+ foo = {
150
+ :authorization_fingerprint => @options[:authorization_fingerprint],
151
+ :shared_customer_identifier => "fake_identifier",
152
+ :shared_customer_identifier_type => "testing",
153
+
154
+ :sepa_mandate => params
155
+ }
156
+
157
+ response = post("/merchants/#{config.merchant_id}/client_api/v1/sepa_mandates", foo)
158
+
159
+ mrn = JSON.parse(response.body)['sepaMandates'][0]['mandateReferenceNumber']
160
+ accept_response = put("/merchants/#{config.merchant_id}/client_api/v1/sepa_mandates/#{mrn}/accept.json",foo)
161
+ JSON.parse(accept_response.body)['sepaBankAccounts'][0]['nonce']
79
162
  end
80
163
  end
@@ -456,7 +456,7 @@ describe Braintree::CreditCard do
456
456
 
457
457
  context "client API" do
458
458
  it "adds credit card to an existing customer using a payment method nonce" do
459
- nonce = nonce_for_new_credit_card(
459
+ nonce = nonce_for_new_payment_method(
460
460
  :credit_card => {
461
461
  :number => "4111111111111111",
462
462
  :expiration_month => "11",
@@ -1050,24 +1050,6 @@ describe Braintree::CreditCard do
1050
1050
  end
1051
1051
  end
1052
1052
 
1053
- describe "delete" do
1054
- it "deletes the credit card" do
1055
- customer = Braintree::Customer.create.customer
1056
- result = Braintree::CreditCard.create(
1057
- :customer_id => customer.id,
1058
- :number => Braintree::Test::CreditCardNumbers::Visa,
1059
- :expiration_date => "05/2012"
1060
- )
1061
-
1062
- result.success?.should == true
1063
- credit_card = result.credit_card
1064
- credit_card.delete.should == true
1065
- expect do
1066
- Braintree::CreditCard.find(credit_card.token)
1067
- end.to raise_error(Braintree::NotFoundError)
1068
- end
1069
- end
1070
-
1071
1053
  describe "self.expired" do
1072
1054
  it "can iterate over all items, and make sure they are all expired" do
1073
1055
  customer = Braintree::Customer.all.first
@@ -1161,12 +1143,30 @@ describe Braintree::CreditCard do
1161
1143
  Braintree::CreditCard.find("invalid-token")
1162
1144
  end.to raise_error(Braintree::NotFoundError, 'payment method with token "invalid-token" not found')
1163
1145
  end
1146
+
1147
+ it "raises a NotFoundError exception if searching for a PayPalAccount token" do
1148
+ customer = Braintree::Customer.create!
1149
+ paypal_account_token = "PAYPAL_ACCOUNT_TOKEN_#{rand(36**3).to_s(36)}"
1150
+ paypal_nonce = nonce_for_paypal_account({
1151
+ :consent_code => "PAYPAL_CONSENT_CODE",
1152
+ :token => paypal_account_token
1153
+ })
1154
+
1155
+ Braintree::PaymentMethod.create({
1156
+ :payment_method_nonce => paypal_nonce,
1157
+ :customer_id => customer.id
1158
+ })
1159
+
1160
+ expect do
1161
+ Braintree::CreditCard.find(paypal_account_token)
1162
+ end.to raise_error(Braintree::NotFoundError, "payment method with token \"#{paypal_account_token}\" not found")
1163
+ end
1164
1164
  end
1165
1165
 
1166
1166
  describe "self.from_nonce" do
1167
1167
  it "finds the payment method with the given nonce" do
1168
1168
  customer = Braintree::Customer.create!
1169
- nonce = nonce_for_new_credit_card(
1169
+ nonce = nonce_for_new_payment_method(
1170
1170
  :credit_card => {
1171
1171
  :number => "4111111111111111",
1172
1172
  :expiration_month => "11",
@@ -1181,7 +1181,7 @@ describe Braintree::CreditCard do
1181
1181
  end
1182
1182
 
1183
1183
  it "does not find a payment method for an unlocked nonce that points to a shared credit card" do
1184
- nonce = nonce_for_new_credit_card(
1184
+ nonce = nonce_for_new_payment_method(
1185
1185
  :credit_card => {
1186
1186
  :number => "4111111111111111",
1187
1187
  :expiration_month => "11",
@@ -1194,14 +1194,15 @@ describe Braintree::CreditCard do
1194
1194
  end
1195
1195
 
1196
1196
  it "does not find the payment method for a locked nonce" do
1197
- client_token = Braintree::ClientToken.generate
1197
+ raw_client_token = Braintree::ClientToken.generate
1198
+ client_token = decode_client_token(raw_client_token)
1198
1199
  client = ClientApiHttp.new(Braintree::Configuration.instantiate,
1199
- :authorization_fingerprint => JSON.parse(client_token)["authorizationFingerprint"],
1200
+ :authorization_fingerprint => client_token["authorizationFingerprint"],
1200
1201
  :shared_customer_identifier => "fake_identifier",
1201
1202
  :shared_customer_identifier_type => "testing"
1202
1203
  )
1203
1204
 
1204
- client.add_card(
1205
+ client.add_payment_method(
1205
1206
  :credit_card => {
1206
1207
  :number => "4111111111111111",
1207
1208
  :expiration_month => "11",
@@ -1210,9 +1211,9 @@ describe Braintree::CreditCard do
1210
1211
  :share => true
1211
1212
  )
1212
1213
 
1213
- response = client.get_cards
1214
+ response = client.get_payment_methods
1214
1215
  body = JSON.parse(response.body)
1215
- nonce = body["creditCards"].first["nonce"]
1216
+ nonce = body["paymentMethods"].first["nonce"]
1216
1217
 
1217
1218
  expect do
1218
1219
  Braintree::CreditCard.from_nonce(nonce)
@@ -1221,7 +1222,7 @@ describe Braintree::CreditCard do
1221
1222
 
1222
1223
  it "does not find the payment method for a consumednonce" do
1223
1224
  customer = Braintree::Customer.create!
1224
- nonce = nonce_for_new_credit_card(
1225
+ nonce = nonce_for_new_payment_method(
1225
1226
  :credit_card => {
1226
1227
  :number => "4111111111111111",
1227
1228
  :expiration_month => "11",
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+ require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
2
3
 
3
4
  describe Braintree::Transaction, "search" do
4
5
  context "advanced" do
@@ -169,4 +170,26 @@ describe Braintree::Transaction, "search" do
169
170
  collection.first.company.should == customer.company
170
171
  end
171
172
  end
173
+
174
+ it "can search by paypal_account_email" do
175
+ paypal_token = rand(36**3).to_s(36)
176
+ nonce = nonce_for_paypal_account(
177
+ :consent_code => "PAYPAL_CONSENT_CODE",
178
+ :token => paypal_token
179
+ )
180
+
181
+ customer_id = "UNIQUE_CUSTOMER_ID_" + rand(36**3).to_s(36)
182
+ customer = Braintree::Customer.create!(
183
+ :payment_method_nonce => nonce,
184
+ :id => customer_id
185
+ )
186
+
187
+ collection = Braintree::Customer.search do |search|
188
+ search.paypal_account_email.is "jane.doe@example.com"
189
+ search.id.is customer_id
190
+ end
191
+
192
+ collection.maximum_size.should == 1
193
+ collection.first.should == customer
194
+ end
172
195
  end
@@ -383,7 +383,7 @@ describe Braintree::Customer do
383
383
 
384
384
  context "client API" do
385
385
  it "can create a customer with a payment method nonce" do
386
- nonce = nonce_for_new_credit_card(
386
+ nonce = nonce_for_new_payment_method(
387
387
  :credit_card => {
388
388
  :number => "4111111111111111",
389
389
  :expiration_month => "11",
@@ -1135,4 +1135,86 @@ describe Braintree::Customer do
1135
1135
  customer.default_credit_card.should == default_credit_card
1136
1136
  end
1137
1137
  end
1138
+
1139
+ describe "paypal" do
1140
+ context "future" do
1141
+ it "creates a customer with a future paypal account" do
1142
+ result = Braintree::Customer.create(
1143
+ :payment_method_nonce => Braintree::Test::Nonce::PayPalFuturePayment
1144
+ )
1145
+
1146
+ result.should be_success
1147
+ end
1148
+
1149
+ it "updates a customer with a future paypal account" do
1150
+ customer = Braintree::Customer.create!(
1151
+ :credit_card => {
1152
+ :number => Braintree::Test::CreditCardNumbers::Visa,
1153
+ :expiration_date => "12/2015",
1154
+ :options => {
1155
+ :make_default => true
1156
+ }
1157
+ }
1158
+ )
1159
+
1160
+ paypal_account_token = "PAYPAL_ACCOUNT_TOKEN_#{rand(36**3).to_s(36)}"
1161
+ nonce = nonce_for_paypal_account(
1162
+ :consent_code => "PAYPAL_CONSENT_CODE",
1163
+ :token => paypal_account_token,
1164
+ :options => {
1165
+ :make_default => true
1166
+ }
1167
+ )
1168
+
1169
+ result = Braintree::Customer.update(
1170
+ customer.id,
1171
+ :payment_method_nonce => nonce
1172
+ )
1173
+
1174
+ result.should be_success
1175
+ result.customer.default_payment_method.token.should == paypal_account_token
1176
+ end
1177
+ end
1178
+
1179
+ context "onetime" do
1180
+ it "does not create a customer with a onetime paypal account" do
1181
+ result = Braintree::Customer.create(
1182
+ :payment_method_nonce => Braintree::Test::Nonce::PayPalOneTimePayment
1183
+ )
1184
+
1185
+ result.should_not be_success
1186
+ end
1187
+
1188
+ it "does not update a customer with a onetime paypal account" do
1189
+ credit_card_token = rand(36**3).to_s(36)
1190
+ customer = Braintree::Customer.create!(
1191
+ :credit_card => {
1192
+ :token => credit_card_token,
1193
+ :number => Braintree::Test::CreditCardNumbers::Visa,
1194
+ :expiration_date => "12/2015",
1195
+ :options => {
1196
+ :make_default => true
1197
+ }
1198
+ }
1199
+ )
1200
+
1201
+ paypal_account_token = "PAYPAL_ACCOUNT_TOKEN_#{rand(36**3).to_s(36)}"
1202
+ nonce = nonce_for_paypal_account(
1203
+ :access_token => "PAYPAL_ACCESS_TOKEN",
1204
+ :token => paypal_account_token,
1205
+ :options => {
1206
+ :make_default => true
1207
+ }
1208
+ )
1209
+
1210
+ result = Braintree::Customer.update(
1211
+ customer.id,
1212
+ :payment_method_nonce => nonce
1213
+ )
1214
+
1215
+ result.should_not be_success
1216
+ customer.default_payment_method.token.should == credit_card_token
1217
+ end
1218
+ end
1219
+ end
1138
1220
  end
@@ -0,0 +1,315 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+ require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
3
+
4
+ describe Braintree::PaymentMethod do
5
+ describe "self.create" do
6
+ it "creates a payment method from a vaulted credit card nonce" do
7
+ config = Braintree::Configuration.instantiate
8
+ customer = Braintree::Customer.create.customer
9
+ raw_client_token = Braintree::ClientToken.generate(:customer_id => customer.id)
10
+ client_token = decode_client_token(raw_client_token)
11
+ authorization_fingerprint = client_token["authorizationFingerprint"]
12
+ http = ClientApiHttp.new(
13
+ config,
14
+ :authorization_fingerprint => authorization_fingerprint,
15
+ :shared_customer_identifier => "fake_identifier",
16
+ :shared_customer_identifier_type => "testing"
17
+ )
18
+
19
+ response = http.create_credit_card(
20
+ :number => 4111111111111111,
21
+ :expirationMonth => 12,
22
+ :expirationYear => 2020
23
+ )
24
+ response.code.should == "201"
25
+
26
+ nonce = JSON.parse(response.body)["creditCards"].first["nonce"]
27
+ result = Braintree::PaymentMethod.create(
28
+ :payment_method_nonce => nonce,
29
+ :customer_id => customer.id
30
+ )
31
+
32
+ result.should be_success
33
+ result.payment_method.should be_a(Braintree::CreditCard)
34
+ token = result.payment_method.token
35
+
36
+ found_credit_card = Braintree::CreditCard.find(token)
37
+ found_credit_card.should_not be_nil
38
+ end
39
+
40
+ it "creates a payment method from an unvalidated credit card nonce" do
41
+ config = Braintree::Configuration.instantiate
42
+ customer = Braintree::Customer.create.customer
43
+ raw_client_token = Braintree::ClientToken.generate(:customer_id => customer.id)
44
+ client_token = decode_client_token(raw_client_token)
45
+ authorization_fingerprint = client_token["authorizationFingerprint"]
46
+ http = ClientApiHttp.new(
47
+ config,
48
+ :authorization_fingerprint => authorization_fingerprint,
49
+ :shared_customer_identifier => "fake_identifier",
50
+ :shared_customer_identifier_type => "testing"
51
+ )
52
+
53
+ response = http.create_credit_card(
54
+ :number => "4111111111111111",
55
+ :expirationMonth => "12",
56
+ :expirationYear => "2020",
57
+ :options => {:validate => false}
58
+ )
59
+ response.code.should == "202"
60
+
61
+ nonce = JSON.parse(response.body)["creditCards"].first["nonce"]
62
+ result = Braintree::PaymentMethod.create(
63
+ :payment_method_nonce => nonce,
64
+ :customer_id => customer.id
65
+ )
66
+
67
+ result.should be_success
68
+ result.payment_method.should be_a(Braintree::CreditCard)
69
+ token = result.payment_method.token
70
+
71
+ found_credit_card = Braintree::CreditCard.find(token)
72
+ found_credit_card.should_not be_nil
73
+ end
74
+
75
+ it "allows passing the make_default option alongside the nonce" do
76
+ customer = Braintree::Customer.create!
77
+ result = Braintree::CreditCard.create(
78
+ :customer_id => customer.id,
79
+ :number => Braintree::Test::CreditCardNumbers::Visa,
80
+ :expiration_date => "05/2009",
81
+ :cvv => "100"
82
+ )
83
+ result.success?.should == true
84
+ original_payment_method = result.credit_card
85
+ original_payment_method.should be_default
86
+
87
+ nonce = nonce_for_paypal_account(:consent_code => "PAYPAL_CONSENT_CODE")
88
+ result = Braintree::PaymentMethod.create(
89
+ :payment_method_nonce => nonce,
90
+ :customer_id => customer.id,
91
+ :options => {:make_default => true}
92
+ )
93
+
94
+ result.should be_success
95
+ new_payment_method = result.payment_method
96
+ new_payment_method.should be_default
97
+ end
98
+
99
+ it "overrides the token in the nonce" do
100
+ customer = Braintree::Customer.create!
101
+
102
+ first_token = "FIRST_TOKEN_#{rand(36**3).to_s(36)}"
103
+ second_token = "SECOND_TOKEN_#{rand(36**3).to_s(36)}"
104
+ nonce = nonce_for_paypal_account(
105
+ :consent_code => "PAYPAL_CONSENT_CODE",
106
+ :token => first_token
107
+ )
108
+ result = Braintree::PaymentMethod.create(
109
+ :payment_method_nonce => nonce,
110
+ :customer_id => customer.id,
111
+ :token => second_token
112
+ )
113
+
114
+ result.should be_success
115
+ payment_method = result.payment_method
116
+ payment_method.token.should == second_token
117
+ end
118
+
119
+ context "paypal" do
120
+ it "creates a payment method from an unvalidated future paypal account nonce" do
121
+ nonce = nonce_for_paypal_account(:consent_code => "PAYPAL_CONSENT_CODE")
122
+ customer = Braintree::Customer.create.customer
123
+ result = Braintree::PaymentMethod.create(
124
+ :payment_method_nonce => nonce,
125
+ :customer_id => customer.id
126
+ )
127
+
128
+ result.should be_success
129
+ result.payment_method.should be_a(Braintree::PayPalAccount)
130
+ result.payment_method.image_url.should_not be_nil
131
+ token = result.payment_method.token
132
+
133
+ found_paypal_account = Braintree::PayPalAccount.find(token)
134
+ found_paypal_account.should_not be_nil
135
+ end
136
+
137
+ it "does not create a payment method from an unvalidated onetime paypal account nonce" do
138
+ customer = Braintree::Customer.create.customer
139
+ nonce = nonce_for_paypal_account(:access_token => "PAYPAL_ACCESS_TOKEN")
140
+ result = Braintree::PaymentMethod.create(
141
+ :payment_method_nonce => nonce,
142
+ :customer_id => customer.id
143
+ )
144
+
145
+ result.should_not be_success
146
+ result.errors.first.code.should == "82902"
147
+ end
148
+
149
+ it "returns appropriate validation errors" do
150
+ customer = Braintree::Customer.create.customer
151
+ nonce = nonce_for_paypal_account(:token => "PAYPAL_TOKEN")
152
+ result = Braintree::PaymentMethod.create(
153
+ :payment_method_nonce => nonce,
154
+ :customer_id => customer.id
155
+ )
156
+
157
+ result.should_not be_success
158
+ errors = result.errors.map(&:code)
159
+ errors.should include("82901")
160
+ errors.should include("82902")
161
+ end
162
+ end
163
+
164
+ context "SEPA" do
165
+ it "returns the SEPA bank account behind the nonce" do
166
+ config = Braintree::Configuration.instantiate
167
+ customer = Braintree::Customer.create.customer
168
+ raw_client_token = Braintree::ClientToken.generate(:customer_id => customer.id, :sepa_mandate_type => Braintree::SEPABankAccount::MandateType::Business)
169
+ client_token = decode_client_token(raw_client_token)
170
+ authorization_fingerprint = client_token["authorizationFingerprint"]
171
+ http = ClientApiHttp.new(
172
+ config,
173
+ :authorization_fingerprint => authorization_fingerprint
174
+ )
175
+
176
+ nonce = http.create_sepa_bank_account_nonce(
177
+ :accountHolderName => "Bob Holder",
178
+ :iban => "DE89370400440532013000",
179
+ :bic => "DEUTDEFF",
180
+ :locale => "en-US",
181
+ :billingAddress => {
182
+ :region => "Hesse",
183
+ :country_name => "Germany"
184
+ }
185
+ )
186
+ nonce.should_not == nil
187
+ result = Braintree::PaymentMethod.create(
188
+ :payment_method_nonce => nonce,
189
+ :customer_id => customer.id
190
+ )
191
+
192
+ result.should be_success
193
+ result.payment_method.token.should_not == nil
194
+ result.payment_method.image_url.should_not be_nil
195
+ end
196
+ end
197
+ end
198
+
199
+ describe "self.find" do
200
+ context "credit cards" do
201
+ it "finds the payment method with the given token" do
202
+ customer = Braintree::Customer.create.customer
203
+ result = Braintree::CreditCard.create(
204
+ :customer_id => customer.id,
205
+ :number => Braintree::Test::CreditCardNumbers::Visa,
206
+ :expiration_date => "05/2012"
207
+ )
208
+ result.success?.should == true
209
+
210
+ credit_card = Braintree::PaymentMethod.find(result.credit_card.token)
211
+ credit_card.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
212
+ credit_card.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
213
+ credit_card.token.should == result.credit_card.token
214
+ credit_card.expiration_date.should == "05/2012"
215
+ end
216
+
217
+ it "returns associated subscriptions with the credit card" do
218
+ customer = Braintree::Customer.create.customer
219
+ credit_card = Braintree::CreditCard.create(
220
+ :customer_id => customer.id,
221
+ :number => Braintree::Test::CreditCardNumbers::Visa,
222
+ :expiration_date => "05/2012"
223
+ ).credit_card
224
+
225
+ subscription = Braintree::Subscription.create(
226
+ :payment_method_token => credit_card.token,
227
+ :plan_id => "integration_trialless_plan",
228
+ :price => "1.00"
229
+ ).subscription
230
+
231
+ found_card = Braintree::PaymentMethod.find(credit_card.token)
232
+ found_card.subscriptions.first.id.should == subscription.id
233
+ found_card.subscriptions.first.plan_id.should == "integration_trialless_plan"
234
+ found_card.subscriptions.first.payment_method_token.should == credit_card.token
235
+ found_card.subscriptions.first.price.should == BigDecimal.new("1.00")
236
+ end
237
+ end
238
+
239
+ context "paypal accounts" do
240
+ it "finds the payment method with the given token" do
241
+ customer = Braintree::Customer.create!
242
+ payment_method_token = "PAYMENT_METHOD_TOKEN_#{rand(36**3).to_s(36)}"
243
+ nonce = nonce_for_paypal_account(
244
+ :consent_code => "consent-code",
245
+ :token => payment_method_token
246
+ )
247
+ result = Braintree::PaymentMethod.create(
248
+ :payment_method_nonce => nonce,
249
+ :customer_id => customer.id
250
+ )
251
+ result.should be_success
252
+
253
+ paypal_account = Braintree::PaymentMethod.find(payment_method_token)
254
+ paypal_account.should be_a(Braintree::PayPalAccount)
255
+ paypal_account.token.should == payment_method_token
256
+ paypal_account.email.should == "jane.doe@example.com"
257
+ end
258
+ end
259
+
260
+ it "raises a NotFoundError exception if payment method cannot be found" do
261
+ expect do
262
+ Braintree::PaymentMethod.find("invalid-token")
263
+ end.to raise_error(Braintree::NotFoundError, 'payment method with token "invalid-token" not found')
264
+ end
265
+ end
266
+
267
+ describe "self.delete" do
268
+ it "deletes a paypal account" do
269
+ customer = Braintree::Customer.create!
270
+ paypal_account_token = "PAYPAL_ACCOUNT_TOKEN_#{rand(36**3).to_s(36)}"
271
+ nonce = nonce_for_paypal_account(
272
+ :consent_code => "PAYPAL_CONSENT_CODE",
273
+ :token => paypal_account_token
274
+ )
275
+ Braintree::PaymentMethod.create(
276
+ :payment_method_nonce => nonce,
277
+ :customer_id => customer.id
278
+ )
279
+
280
+ paypal_account = Braintree::PaymentMethod.find(paypal_account_token)
281
+ paypal_account.should be_a(Braintree::PayPalAccount)
282
+
283
+ result = Braintree::PaymentMethod.delete(paypal_account_token)
284
+
285
+ expect do
286
+ Braintree::PaymentMethod.find(paypal_account_token)
287
+ end.to raise_error(Braintree::NotFoundError, "payment method with token \"#{paypal_account_token}\" not found")
288
+ end
289
+
290
+ it "deletes a credit card" do
291
+ token = "CREDIT_CARD_#{rand(36**3).to_s(36)}"
292
+ customer = Braintree::Customer.create!
293
+ nonce = nonce_for_new_payment_method({
294
+ :credit_card => {
295
+ :number => "4111111111111111",
296
+ :expiration_month => "11",
297
+ :expiration_year => "2099",
298
+ :token => token
299
+ },
300
+ :client_token_options => {:customer_id => customer.id}
301
+ })
302
+
303
+ Braintree::PaymentMethod.create(
304
+ :payment_method_nonce => nonce,
305
+ :customer_id => customer.id
306
+ )
307
+
308
+ Braintree::PaymentMethod.delete(token)
309
+
310
+ expect do
311
+ Braintree::PaymentMethod.find(token)
312
+ end.to raise_error(Braintree::NotFoundError, "payment method with token \"#{token}\" not found")
313
+ end
314
+ end
315
+ end