braintree 2.31.0 → 2.32.1

Sign up to get free protection for your applications and to get access to all the features.
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