braintree 4.40.0 → 4.42.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/lib/braintree/client_token_gateway.rb +10 -1
  3. data/lib/braintree/credit_card_gateway.rb +9 -3
  4. data/lib/braintree/credit_card_verification_gateway.rb +3 -0
  5. data/lib/braintree/customer_gateway.rb +11 -3
  6. data/lib/braintree/error_codes.rb +12 -0
  7. data/lib/braintree/http.rb +4 -2
  8. data/lib/braintree/merchant_account_gateway.rb +2 -0
  9. data/lib/braintree/payment_method_gateway.rb +6 -1
  10. data/lib/braintree/payment_method_nonce_gateway.rb +4 -0
  11. data/lib/braintree/paypal_account_gateway.rb +6 -1
  12. data/lib/braintree/plan_gateway.rb +4 -0
  13. data/lib/braintree/sepa_direct_debit_account_gateway.rb +4 -0
  14. data/lib/braintree/subscription_gateway.rb +6 -0
  15. data/lib/braintree/testing_gateway.rb +4 -0
  16. data/lib/braintree/transaction.rb +14 -0
  17. data/lib/braintree/transaction_gateway.rb +39 -7
  18. data/lib/braintree/transaction_line_item_gateway.rb +3 -1
  19. data/lib/braintree/transaction_search.rb +1 -0
  20. data/lib/braintree/us_bank_account_gateway.rb +2 -0
  21. data/lib/braintree/us_bank_account_verification_gateway.rb +4 -0
  22. data/lib/braintree/version.rb +1 -1
  23. data/spec/integration/braintree/apple_pay_spec.rb +3 -1
  24. data/spec/integration/braintree/client_api/client_token_spec.rb +14 -0
  25. data/spec/integration/braintree/credit_card_spec.rb +31 -0
  26. data/spec/integration/braintree/credit_card_verification_spec.rb +54 -0
  27. data/spec/integration/braintree/customer_spec.rb +58 -0
  28. data/spec/integration/braintree/transaction_idempotency_spec.rb +30 -0
  29. data/spec/integration/braintree/transaction_search_spec.rb +95 -0
  30. data/spec/integration/braintree/transaction_spec.rb +211 -1
  31. data/spec/unit/braintree/client_token_spec.rb +72 -0
  32. data/spec/unit/braintree/credit_card_spec.rb +28 -2
  33. data/spec/unit/braintree/credit_card_verification_gateway_spec.rb +1 -0
  34. data/spec/unit/braintree/credit_card_verification_spec.rb +8 -0
  35. data/spec/unit/braintree/customer_spec.rb +28 -2
  36. data/spec/unit/braintree/http_spec.rb +44 -0
  37. data/spec/unit/braintree/merchant_account_spec.rb +11 -0
  38. data/spec/unit/braintree/package_tracking_spec.rb +2 -2
  39. data/spec/unit/braintree/payment_method_nonce_spec.rb +14 -0
  40. data/spec/unit/braintree/payment_method_spec.rb +20 -0
  41. data/spec/unit/braintree/paypal_account_spec.rb +20 -0
  42. data/spec/unit/braintree/plan_gateway_spec.rb +30 -0
  43. data/spec/unit/braintree/sepa_debit_account_spec.rb +14 -0
  44. data/spec/unit/braintree/subscription_spec.rb +20 -0
  45. data/spec/unit/braintree/test_transaction_spec.rb +18 -0
  46. data/spec/unit/braintree/transaction_gateway_spec.rb +24 -0
  47. data/spec/unit/braintree/transaction_line_item_spec.rb +11 -0
  48. data/spec/unit/braintree/transaction_search_spec.rb +25 -0
  49. data/spec/unit/braintree/transaction_spec.rb +68 -6
  50. data/spec/unit/braintree/us_bank_account_spec.rb +8 -0
  51. data/spec/unit/braintree/us_bank_account_verification_spec.rb +14 -0
  52. data/spec/unit/braintree/util_spec.rb +37 -0
  53. metadata +7 -3
@@ -529,6 +529,37 @@ describe Braintree::CreditCard do
529
529
  expect(result.success?).to eq(true)
530
530
  end
531
531
 
532
+ it "can set the mastercard transaction link identifier when creating a credit card" do
533
+ customer = Braintree::Customer.create!
534
+
535
+ result = Braintree::CreditCard.create(
536
+ :customer_id => customer.id,
537
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
538
+ :expiration_date => "05/2009",
539
+ :external_vault => {
540
+ :mastercard_transaction_link_id => "1234567890123456789012",
541
+ },
542
+ )
543
+
544
+ expect(result.success?).to eq(true)
545
+ end
546
+
547
+ it "rejects a mastercard transaction link identifier that is not 22 characters" do
548
+ customer = Braintree::Customer.create!
549
+
550
+ result = Braintree::CreditCard.create(
551
+ :customer_id => customer.id,
552
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
553
+ :expiration_date => "05/2009",
554
+ :external_vault => {
555
+ :mastercard_transaction_link_id => "1234567890123456789012123",
556
+ },
557
+ )
558
+
559
+ expect(result.success?).to eq(false)
560
+ expect(result.errors.for(:credit_card).for(:external_vault).on(:mastercard_transaction_link_id)[0].code).to eq(Braintree::ErrorCodes::CreditCard::ExternalVault::MastercardTransactionLinkIdIsInvalid)
561
+ end
562
+
532
563
  context "card type indicators" do
533
564
  it "sets the prepaid field if the card is prepaid" do
534
565
  customer = Braintree::Customer.create!
@@ -147,6 +147,60 @@ describe Braintree::CreditCardVerification, "search" do
147
147
  expect(result.credit_card_verification.network_transaction_id).not_to be_nil
148
148
  end
149
149
 
150
+ it "creates a new verification with previous_mastercard_transaction_link_id" do
151
+ verification_params = {
152
+ :credit_card => {
153
+ :expiration_date => "05/2029",
154
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
155
+ },
156
+ :external_vault => {
157
+ :status => "vaulted",
158
+ :previous_mastercard_transaction_link_id => "1234567890123456789012",
159
+ }
160
+ }
161
+
162
+ result = Braintree::CreditCardVerification.create(verification_params)
163
+
164
+ expect(result).to be_success
165
+ expect(result.credit_card_verification.id).to match(/^\w{6,}$/)
166
+ end
167
+
168
+ it "rejects non-vaulted status with previous_mastercard_transaction_link_id" do
169
+ verification_params = {
170
+ :credit_card => {
171
+ :expiration_date => "05/2029",
172
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
173
+ },
174
+ :external_vault => {
175
+ :status => "will_vault",
176
+ :previous_mastercard_transaction_link_id => "1234567890123456789012",
177
+ }
178
+ }
179
+
180
+ result = Braintree::CreditCardVerification.create(verification_params)
181
+
182
+ expect(result.success?).to eq(false)
183
+ expect(result.errors.for(:verification).for(:external_vault).on(:status)[0].code).to eq(Braintree::ErrorCodes::Verification::ExternalVault::StatusWithPreviousMastercardTransactionLinkIdIsInvalid)
184
+ end
185
+
186
+ it "rejects previous_mastercard_transaction_link_id that is not 22 characters" do
187
+ verification_params = {
188
+ :credit_card => {
189
+ :expiration_date => "05/2029",
190
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
191
+ },
192
+ :external_vault => {
193
+ :status => "vaulted",
194
+ :previous_mastercard_transaction_link_id => "1234567890123456789012123",
195
+ }
196
+ }
197
+
198
+ result = Braintree::CreditCardVerification.create(verification_params)
199
+
200
+ expect(result.success?).to eq(false)
201
+ expect(result.errors.for(:verification).for(:external_vault).on(:previous_mastercard_transaction_link_id)[0].code).to eq(Braintree::ErrorCodes::Verification::ExternalVault::PreviousMastercardTransactionLinkIdIsInvalid)
202
+ end
203
+
150
204
  it "creates a new verification from risk data param" do
151
205
  verification_params = {
152
206
  :credit_card => {
@@ -102,6 +102,21 @@ describe Braintree::Customer do
102
102
  expect(result).to be_success
103
103
  end
104
104
 
105
+ it "supports creation with a mastercard_transaction_link_id external_vault param" do
106
+ result = Braintree::Customer.create(
107
+ :credit_card => {
108
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
109
+ :expiration_date => "05/2010",
110
+ :cvv => "100",
111
+ :external_vault => {
112
+ :mastercard_transaction_link_id => "1234567890123456789012",
113
+ },
114
+ },
115
+ )
116
+
117
+ expect(result).to be_success
118
+ end
119
+
105
120
  it "supports creation including risk data with customer_browser and customer_ip" do
106
121
  result = Braintree::Customer.create(
107
122
  :credit_card => {
@@ -2677,4 +2692,47 @@ describe Braintree::Customer do
2677
2692
  end
2678
2693
  end
2679
2694
 
2695
+ describe "path traversal" do
2696
+ it "self.update rejects a traversal customer_id and does not void the victim transaction" do
2697
+ transaction = Braintree::Transaction.sale!(
2698
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
2699
+ :credit_card => {
2700
+ :number => Braintree::Test::CreditCardNumbers::Visa,
2701
+ :expiration_date => "05/2009"
2702
+ },
2703
+ :options => {:submit_for_settlement => false},
2704
+ )
2705
+ traversal_id = "../transactions/#{transaction.id}/void"
2706
+
2707
+ expect do
2708
+ Braintree::Customer.update(traversal_id, :first_name => "HackerOne")
2709
+ end.to raise_error(ArgumentError, "customer_id contains invalid characters")
2710
+
2711
+ unaffected_transaction = Braintree::Transaction.find(transaction.id)
2712
+ expect(unaffected_transaction.status).to eq(Braintree::Transaction::Status::Authorized)
2713
+ end
2714
+
2715
+ it "self.delete rejects a traversal customer_id and does not delete the victim payment method" do
2716
+ create_result = Braintree::Customer.create(:first_name => "Victim")
2717
+ expect(create_result.success?).to eq(true)
2718
+ customer = create_result.customer
2719
+
2720
+ credit_card_result = Braintree::CreditCard.create(
2721
+ :customer_id => customer.id,
2722
+ :number => Braintree::Test::CreditCardNumbers::Visa,
2723
+ :expiration_date => "05/2009",
2724
+ )
2725
+ expect(credit_card_result.success?).to eq(true)
2726
+ token = credit_card_result.credit_card.token
2727
+ traversal_id = "../payment_methods/any/#{token}"
2728
+
2729
+ expect do
2730
+ Braintree::Customer.delete(traversal_id)
2731
+ end.to raise_error(ArgumentError, "customer_id contains invalid characters")
2732
+
2733
+ unaffected_credit_card = Braintree::CreditCard.find(token)
2734
+ expect(unaffected_credit_card.token).to eq(token)
2735
+ end
2736
+ end
2737
+
2680
2738
  end
@@ -277,6 +277,36 @@ describe Braintree::Transaction, "idempotency" do
277
277
  end
278
278
  end
279
279
 
280
+ describe "reverse" do
281
+ it "returns original reverse on duplicate request with same api_request_key" do
282
+ api_request_key = "reverse-idempotency-key-#{rand(1000000)}"
283
+
284
+ sale_request = {
285
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
286
+ :credit_card => {
287
+ :number => "4111111111111111",
288
+ :expiration_date => "05/2035"
289
+ }
290
+ }
291
+
292
+ sale_result = Braintree::Transaction.sale(sale_request)
293
+ expect(sale_result).to be_success
294
+ transaction_id = sale_result.transaction.id
295
+
296
+ reverse_options = {
297
+ :api_request_key => api_request_key
298
+ }
299
+
300
+ reverse_result1 = Braintree::Transaction.reverse(transaction_id, reverse_options)
301
+ expect(reverse_result1).to be_success
302
+
303
+ reverse_result2 = Braintree::Transaction.reverse(transaction_id, reverse_options)
304
+ expect(reverse_result2).to be_success
305
+ expect(reverse_result1.transaction.id).to eq(reverse_result2.transaction.id)
306
+ expect(reverse_result2.transaction.status).to eq(Braintree::Transaction::Status::Voided)
307
+ end
308
+ end
309
+
280
310
  describe "refund" do
281
311
  it "returns original refund on duplicate request with same api_request_key" do
282
312
  api_request_key = "refund-idempotency-key-#{rand(1000000)}"
@@ -257,6 +257,93 @@ describe Braintree::Transaction, "search" do
257
257
  expect(collection.maximum_size).to eq(0)
258
258
  end
259
259
 
260
+ it "searches on ach_type" do
261
+ same_day_transaction = Braintree::Transaction.find("sameday_ach_sameday_requested")
262
+ standard_transaction = Braintree::Transaction.find("standard_ach_standard_requested")
263
+
264
+ collection = Braintree::Transaction.search do |search|
265
+ search.id.is same_day_transaction.id
266
+ search.ach_type.is Braintree::Transaction::AchType::SameDay
267
+ end
268
+
269
+ expect(collection.maximum_size).to eq(1)
270
+ expect(collection.first.id).to eq(same_day_transaction.id)
271
+
272
+ collection = Braintree::Transaction.search do |search|
273
+ search.id.is same_day_transaction.id
274
+ search.ach_type.is Braintree::Transaction::AchType::Standard
275
+ end
276
+
277
+ expect(collection.maximum_size).to eq(0)
278
+
279
+ collection = Braintree::Transaction.search do |search|
280
+ search.id.is standard_transaction.id
281
+ search.ach_type.is Braintree::Transaction::AchType::Standard
282
+ end
283
+
284
+ expect(collection.maximum_size).to eq(1)
285
+ expect(collection.first.id).to eq(standard_transaction.id)
286
+
287
+ collection = Braintree::Transaction.search do |search|
288
+ search.id.is standard_transaction.id
289
+ search.ach_type.is Braintree::Transaction::AchType::SameDay
290
+ end
291
+
292
+ expect(collection.maximum_size).to eq(0)
293
+
294
+ collection = Braintree::Transaction.search do |search|
295
+ search.id.is same_day_transaction.id
296
+ search.ach_type.in [
297
+ Braintree::Transaction::AchType::SameDay,
298
+ Braintree::Transaction::AchType::Standard
299
+ ]
300
+ end
301
+
302
+ expect(collection.maximum_size).to eq(1)
303
+ expect(collection.first.id).to eq(same_day_transaction.id)
304
+
305
+ collection = Braintree::Transaction.search do |search|
306
+ search.id.is standard_transaction.id
307
+ search.ach_type.in [
308
+ Braintree::Transaction::AchType::SameDay,
309
+ Braintree::Transaction::AchType::Standard
310
+ ]
311
+ end
312
+
313
+ expect(collection.maximum_size).to eq(1)
314
+ expect(collection.first.id).to eq(standard_transaction.id)
315
+
316
+ divergent_transaction = Braintree::Transaction.find("standard_ach_sameday_requested")
317
+ expect(divergent_transaction.ach_type).to eq(Braintree::Transaction::AchType::Standard)
318
+ expect(divergent_transaction.requested_ach_type).to eq(Braintree::Transaction::AchType::SameDay)
319
+
320
+ collection = Braintree::Transaction.search do |search|
321
+ search.id.is divergent_transaction.id
322
+ search.ach_type.is Braintree::Transaction::AchType::Standard
323
+ end
324
+
325
+ expect(collection.maximum_size).to eq(1)
326
+ expect(collection.first.id).to eq(divergent_transaction.id)
327
+
328
+ collection = Braintree::Transaction.search do |search|
329
+ search.id.is divergent_transaction.id
330
+ search.ach_type.is Braintree::Transaction::AchType::SameDay
331
+ end
332
+
333
+ expect(collection.maximum_size).to eq(0)
334
+
335
+ collection = Braintree::Transaction.search do |search|
336
+ search.id.is divergent_transaction.id
337
+ search.ach_type.in [
338
+ Braintree::Transaction::AchType::SameDay,
339
+ Braintree::Transaction::AchType::Standard
340
+ ]
341
+ end
342
+
343
+ expect(collection.maximum_size).to eq(1)
344
+ expect(collection.first.id).to eq(divergent_transaction.id)
345
+ end
346
+
260
347
  it "searches on credit_card_customer_location" do
261
348
  transaction = Braintree::Transaction.sale!(
262
349
  :amount => Braintree::Test::TransactionAmounts::Authorize,
@@ -661,6 +748,14 @@ describe Braintree::Transaction, "search" do
661
748
  end
662
749
  end.to raise_error(ArgumentError)
663
750
  end
751
+
752
+ it "raises an exception on invalid ach_type" do
753
+ expect do
754
+ Braintree::Transaction.search do |search|
755
+ search.ach_type.is "invalid_ach_type"
756
+ end
757
+ end.to raise_error(ArgumentError)
758
+ end
664
759
  end
665
760
 
666
761
  context "range fields" do
@@ -5013,6 +5013,23 @@ describe Braintree::Transaction do
5013
5013
  expect(result.transaction.network_transaction_id).not_to be_nil
5014
5014
  end
5015
5015
 
5016
+ it "accepts previous_mastercard_transaction_link_id" do
5017
+ result = Braintree::Transaction.create(
5018
+ :type => "sale",
5019
+ :credit_card => {
5020
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
5021
+ :expiration_date => "05/2009"
5022
+ },
5023
+ :external_vault => {
5024
+ :status => Braintree::Transaction::ExternalVault::Status::Vaulted,
5025
+ :previous_mastercard_transaction_link_id => "1234567890123456789012",
5026
+ },
5027
+ :amount => "10.00",
5028
+ )
5029
+ expect(result.success?).to eq(true)
5030
+ expect(result.transaction.network_transaction_id).not_to be_nil
5031
+ end
5032
+
5016
5033
  it "rejects non-vaulted status with previous_network_transaction_id" do
5017
5034
  result = Braintree::Transaction.create(
5018
5035
  :type => "sale",
@@ -5029,6 +5046,40 @@ describe Braintree::Transaction do
5029
5046
  expect(result.success?).to eq(false)
5030
5047
  expect(result.errors.for(:transaction).for(:external_vault).on(:status)[0].code).to eq(Braintree::ErrorCodes::Transaction::ExternalVault::StatusWithPreviousNetworkTransactionIdIsInvalid)
5031
5048
  end
5049
+
5050
+ it "rejects non-vaulted status with previous_mastercard_transaction_link_id" do
5051
+ result = Braintree::Transaction.create(
5052
+ :type => "sale",
5053
+ :credit_card => {
5054
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
5055
+ :expiration_date => "05/2009"
5056
+ },
5057
+ :external_vault => {
5058
+ :status => Braintree::Transaction::ExternalVault::Status::WillVault,
5059
+ :previous_mastercard_transaction_link_id => "1234567890123456789012",
5060
+ },
5061
+ :amount => "10.00",
5062
+ )
5063
+ expect(result.success?).to eq(false)
5064
+ expect(result.errors.for(:transaction).for(:external_vault).on(:status)[0].code).to eq(Braintree::ErrorCodes::Transaction::ExternalVault::StatusWithPreviousMastercardTransactionLinkIdIsInvalid)
5065
+ end
5066
+
5067
+ it "rejects previous_mastercard_transaction_link_id that is not 22 characters" do
5068
+ result = Braintree::Transaction.create(
5069
+ :type => "sale",
5070
+ :credit_card => {
5071
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
5072
+ :expiration_date => "05/2009"
5073
+ },
5074
+ :external_vault => {
5075
+ :status => Braintree::Transaction::ExternalVault::Status::Vaulted,
5076
+ :previous_mastercard_transaction_link_id => "1234567890123456789012123",
5077
+ },
5078
+ :amount => "10.00",
5079
+ )
5080
+ expect(result.success?).to eq(false)
5081
+ expect(result.errors.for(:transaction).for(:external_vault).on(:previous_mastercard_transaction_link_id)[0].code).to eq(Braintree::ErrorCodes::Transaction::ExternalVault::PreviousMastercardTransactionLinkIdIsInvalid)
5082
+ end
5032
5083
  end
5033
5084
 
5034
5085
  context "Non-(Visa/Mastercard/Discover/AmEx) card types" do
@@ -5233,6 +5284,28 @@ describe Braintree::Transaction do
5233
5284
  transaction = Braintree::Transaction.find(transaction.id)
5234
5285
  expect(transaction.refund_ids.sort).to eq([transaction_1.id, transaction_2.id].sort)
5235
5286
  end
5287
+
5288
+ it "allows partial refund with surcharge_amount" do
5289
+ transaction = Braintree::Transaction.sale!(
5290
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
5291
+ :surcharge_amount => "1.00",
5292
+ :credit_card => {
5293
+ :number => Braintree::Test::CreditCardNumbers::Visa,
5294
+ :expiration_date => "05/2009"
5295
+ },
5296
+ :options => {
5297
+ :submit_for_settlement => true
5298
+ },
5299
+ )
5300
+ config = Braintree::Configuration.instantiate
5301
+ config.http.put("#{config.base_merchant_path}/transactions/#{transaction.id}/settle")
5302
+ transaction = Braintree::Transaction.find(transaction.id)
5303
+
5304
+ result = Braintree::Transaction.refund(transaction.id, :amount => transaction.amount / 2, :surcharge_amount => "0.50")
5305
+ expect(result.success?).to eq(true)
5306
+ expect(result.transaction.type).to eq("credit")
5307
+ expect(result.transaction.surcharge_amount).to eq(BigDecimal("0.50"))
5308
+ end
5236
5309
  end
5237
5310
 
5238
5311
  it "returns a successful result if successful" do
@@ -5272,6 +5345,28 @@ describe Braintree::Transaction do
5272
5345
  expect(result.success?).to eq(false)
5273
5346
  expect(result.errors.for(:transaction).on(:base)[0].code).to eq(Braintree::ErrorCodes::Transaction::CannotRefundUnlessSettled)
5274
5347
  end
5348
+
5349
+ it "accepts surcharge_amount field in refund" do
5350
+ transaction = Braintree::Transaction.sale!(
5351
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
5352
+ :surcharge_amount => "1.00",
5353
+ :credit_card => {
5354
+ :number => Braintree::Test::CreditCardNumbers::Visa,
5355
+ :expiration_date => "05/2009"
5356
+ },
5357
+ :options => {
5358
+ :submit_for_settlement => true
5359
+ },
5360
+ )
5361
+ config = Braintree::Configuration.instantiate
5362
+ config.http.put("#{config.base_merchant_path}/transactions/#{transaction.id}/settle")
5363
+ transaction = Braintree::Transaction.find(transaction.id)
5364
+
5365
+ result = Braintree::Transaction.refund(transaction.id, :surcharge_amount => "1.00")
5366
+ expect(result.success?).to eq(true)
5367
+ expect(result.transaction.type).to eq("credit")
5368
+ expect(result.transaction.surcharge_amount).to eq(BigDecimal("1.00"))
5369
+ end
5275
5370
  end
5276
5371
 
5277
5372
  describe "self.refund!" do
@@ -7295,6 +7390,85 @@ describe Braintree::Transaction do
7295
7390
  end
7296
7391
  end
7297
7392
 
7393
+ describe "self.reverse" do
7394
+ it "voids a voidable transaction" do
7395
+ transaction = Braintree::Transaction.sale!(
7396
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
7397
+ :credit_card => {
7398
+ :number => Braintree::Test::CreditCardNumbers::Visa,
7399
+ :expiration_date => "05/2009"
7400
+ },
7401
+ )
7402
+
7403
+ result = Braintree::Transaction.reverse(transaction.id)
7404
+
7405
+ expect(result.success?).to eq(true)
7406
+ expect(result.transaction.id).to eq(transaction.id)
7407
+ expect(result.transaction.status).to eq(Braintree::Transaction::Status::Voided)
7408
+ expect(result.transaction.refunded_transaction_id).to be_nil
7409
+ end
7410
+
7411
+ it "returns an error when reversing twice without an api request key" do
7412
+ transaction = Braintree::Transaction.sale!(
7413
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
7414
+ :credit_card => {
7415
+ :number => Braintree::Test::CreditCardNumbers::Visa,
7416
+ :expiration_date => "05/2009"
7417
+ },
7418
+ )
7419
+
7420
+ expect(Braintree::Transaction.reverse(transaction.id)).to be_success
7421
+ result = Braintree::Transaction.reverse(transaction.id)
7422
+
7423
+ expect(result.success?).to eq(false)
7424
+ expect(result.errors.for(:transaction).on(:base).first.code).to eq(
7425
+ Braintree::ErrorCodes::Transaction::CannotRefundUnlessSettled,
7426
+ )
7427
+ end
7428
+
7429
+ it "voids an explicitly created voidable refund" do
7430
+ transaction = Braintree::Transaction.sale!(
7431
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
7432
+ :credit_card => {
7433
+ :number => Braintree::Test::CreditCardNumbers::Visa,
7434
+ :expiration_date => "05/2009"
7435
+ },
7436
+ :options => {
7437
+ :submit_for_settlement => true
7438
+ },
7439
+ )
7440
+ Braintree::TestTransaction.settle(transaction.id)
7441
+ refund = Braintree::Transaction.refund!(transaction.id)
7442
+
7443
+ result = Braintree::Transaction.reverse(refund.id)
7444
+
7445
+ expect(result.success?).to eq(true)
7446
+ expect(result.transaction.id).to eq(refund.id)
7447
+ expect(result.transaction.status).to eq(Braintree::Transaction::Status::Voided)
7448
+ expect(result.transaction.refunded_transaction_id).to eq(transaction.id)
7449
+ end
7450
+
7451
+ it "refunds a settled transaction" do
7452
+ transaction = Braintree::Transaction.sale!(
7453
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
7454
+ :credit_card => {
7455
+ :number => Braintree::Test::CreditCardNumbers::Visa,
7456
+ :expiration_date => "05/2009"
7457
+ },
7458
+ :options => {
7459
+ :submit_for_settlement => true
7460
+ },
7461
+ )
7462
+ Braintree::TestTransaction.settle(transaction.id)
7463
+
7464
+ result = Braintree::Transaction.reverse(transaction.id)
7465
+
7466
+ expect(result.success?).to eq(true)
7467
+ expect(result.transaction.type).to eq(Braintree::Transaction::Type::Credit)
7468
+ expect(result.transaction.refunded_transaction_id).to eq(transaction.id)
7469
+ end
7470
+ end
7471
+
7298
7472
  describe "self.void" do
7299
7473
  it "returns a successful result if successful" do
7300
7474
  transaction = Braintree::Transaction.sale!(
@@ -8179,7 +8353,7 @@ describe Braintree::Transaction do
8179
8353
  end
8180
8354
 
8181
8355
  context "Surcharge Amount" do
8182
- it "accepts surcharge_amount field" do
8356
+ it "accepts surcharge_amount field for sale transactions" do
8183
8357
  result = Braintree::Transaction.create(
8184
8358
  :type => "sale",
8185
8359
  :amount => "10.00",
@@ -8193,5 +8367,41 @@ describe Braintree::Transaction do
8193
8367
  expect(result.success?).to eq(true)
8194
8368
  expect(result.transaction.surcharge_amount).to eq(BigDecimal("1.00"))
8195
8369
  end
8370
+
8371
+ it "accepts surcharge_amount field for blind credit" do
8372
+ result = Braintree::Transaction.create(
8373
+ :type => "credit",
8374
+ :amount => "10.00",
8375
+ :surcharge_amount => "1.00",
8376
+ :credit_card => {
8377
+ :number => Braintree::Test::CreditCardNumbers::Visa,
8378
+ :expiration_date => "05/2029"
8379
+ },
8380
+ )
8381
+
8382
+ expect(result.success?).to eq(true)
8383
+ expect(result.transaction.surcharge_amount).to eq(BigDecimal("1.00"))
8384
+ end
8385
+ end
8386
+
8387
+ describe "path traversal" do
8388
+ it "self.void rejects a traversal transaction_id and does not void the victim transaction" do
8389
+ victim_transaction = Braintree::Transaction.sale!(
8390
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
8391
+ :credit_card => {
8392
+ :number => Braintree::Test::CreditCardNumbers::Visa,
8393
+ :expiration_date => "05/2009"
8394
+ },
8395
+ :options => {:submit_for_settlement => false},
8396
+ )
8397
+ traversal_id = "../transactions/#{victim_transaction.id}"
8398
+
8399
+ expect do
8400
+ Braintree::Transaction.void(traversal_id)
8401
+ end.to raise_error(ArgumentError, "transaction_id contains invalid characters")
8402
+
8403
+ unaffected_transaction = Braintree::Transaction.find(victim_transaction.id)
8404
+ expect(unaffected_transaction.status).to eq(Braintree::Transaction::Status::Authorized)
8405
+ end
8196
8406
  end
8197
8407
  end
@@ -20,6 +20,78 @@ module Braintree
20
20
  )
21
21
  }.to raise_error(ArgumentError, /created_at, public_key/)
22
22
  end
23
+
24
+ context "with preferred_payment_method_token" do
25
+ let(:config) { SpecHelper::TestMerchantConfig }
26
+ let(:gateway) { Gateway.new(config) }
27
+ let(:http) { double(:http) }
28
+
29
+ before do
30
+ allow(config).to receive(:http).and_return(http)
31
+ allow(Configuration).to receive(:gateway).and_return(gateway)
32
+ end
33
+
34
+ def expect_client_token_post(options)
35
+ expect(http).to receive(:post).with(
36
+ "#{config.base_merchant_path}/client_token",
37
+ :client_token => options,
38
+ ).and_return(:client_token => {:value => "client-token"})
39
+ end
40
+
41
+ it "renames preferred_payment_method_token to payment_method_id" do
42
+ expect_client_token_post(
43
+ :payment_method_id => "a-pmt",
44
+ :version => ClientToken::DEFAULT_VERSION,
45
+ )
46
+
47
+ client_token = Braintree::ClientToken.generate(
48
+ :preferred_payment_method_token => "a-pmt",
49
+ )
50
+
51
+ expect(client_token).to eq("client-token")
52
+ end
53
+
54
+ it "renames string preferred_payment_method_token to payment_method_id" do
55
+ expect_client_token_post(
56
+ :payment_method_id => "a-pmt",
57
+ :version => ClientToken::DEFAULT_VERSION,
58
+ )
59
+
60
+ client_token = Braintree::ClientToken.generate(
61
+ "preferred_payment_method_token" => "a-pmt",
62
+ )
63
+
64
+ expect(client_token).to eq("client-token")
65
+ end
66
+
67
+ it "renames preferred_payment_method_token when the value is nil" do
68
+ expect_client_token_post(
69
+ :payment_method_id => nil,
70
+ :version => ClientToken::DEFAULT_VERSION,
71
+ )
72
+
73
+ client_token = Braintree::ClientToken.generate(
74
+ :preferred_payment_method_token => nil,
75
+ )
76
+
77
+ expect(client_token).to eq("client-token")
78
+ end
79
+
80
+ it "does not mutate the caller's options hash" do
81
+ options = {:preferred_payment_method_token => "a-pmt"}
82
+ expect(http).to receive(:post).twice.with(
83
+ "#{config.base_merchant_path}/client_token",
84
+ :client_token => {
85
+ :payment_method_id => "a-pmt",
86
+ :version => ClientToken::DEFAULT_VERSION,
87
+ },
88
+ ).and_return(:client_token => {:value => "client-token"})
89
+
90
+ expect(Braintree::ClientToken.generate(options)).to eq("client-token")
91
+ expect(Braintree::ClientToken.generate(options)).to eq("client-token")
92
+ expect(options).to eq(:preferred_payment_method_token => "a-pmt")
93
+ end
94
+ end
23
95
  end
24
96
 
25
97
  context "adding credit_card options with no customer ID" do