require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper") def make_token SecureRandom.uuid end describe Braintree::PaymentMethod do describe "self.create" do it "creates a payment method from a vaulted credit card nonce" do config = Braintree::Configuration.instantiate customer = Braintree::Customer.create.customer raw_client_token = Braintree::ClientToken.generate(:customer_id => customer.id) client_token = decode_client_token(raw_client_token) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp.new( config, :authorization_fingerprint => authorization_fingerprint, :shared_customer_identifier => "fake_identifier", :shared_customer_identifier_type => "testing", ) response = http.create_credit_card( :number => 4111111111111111, :expirationMonth => 12, :expirationYear => 2020, ) expect(response.code).to eq("201") nonce = JSON.parse(response.body)["creditCards"].first["nonce"] result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::CreditCard) token = result.payment_method.token found_credit_card = Braintree::CreditCard.find(token) expect(found_credit_card).not_to be_nil end it "creates a payment method from an unvalidated credit card nonce" do config = Braintree::Configuration.instantiate customer = Braintree::Customer.create.customer raw_client_token = Braintree::ClientToken.generate(:customer_id => customer.id) client_token = decode_client_token(raw_client_token) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp.new( config, :authorization_fingerprint => authorization_fingerprint, :shared_customer_identifier => "fake_identifier", :shared_customer_identifier_type => "testing", ) response = http.create_credit_card( :number => "4111111111111111", :expirationMonth => "12", :expirationYear => "2020", :options => {:validate => false}, ) expect(response.code).to eq("202") nonce = JSON.parse(response.body)["creditCards"].first["nonce"] result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::CreditCard) token = result.payment_method.token found_credit_card = Braintree::CreditCard.find(token) expect(found_credit_card).not_to be_nil end it "creates a payment method from a fake apple pay nonce" do customer = Braintree::Customer.create.customer token = SecureRandom.hex(16) result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::ApplePayAmEx, :customer_id => customer.id, :token => token, ) expect(result).to be_success apple_pay_card = result.payment_method expect(apple_pay_card).to be_a(Braintree::ApplePayCard) expect(apple_pay_card).not_to be_nil expect(apple_pay_card.bin).not_to be_nil expect(apple_pay_card.token).to eq(token) expect(apple_pay_card.card_type).to eq(Braintree::ApplePayCard::CardType::AmEx) expect(apple_pay_card.payment_instrument_name).to eq("AmEx 41002") expect(apple_pay_card.source_description).to eq("AmEx 41002") expect(apple_pay_card.default).to eq(true) expect(apple_pay_card.image_url).to match(/apple_pay/) expect(apple_pay_card.expiration_month.to_i).to be > 0 expect(apple_pay_card.expiration_year.to_i).to be > 0 expect(apple_pay_card.customer_id).to eq(customer.id) expect(apple_pay_card.commercial).not_to be_nil expect(apple_pay_card.country_of_issuance).not_to be_nil expect(apple_pay_card.debit).not_to be_nil expect(apple_pay_card.durbin_regulated).not_to be_nil expect(apple_pay_card.healthcare).not_to be_nil expect(apple_pay_card.issuing_bank).not_to be_nil expect(apple_pay_card.payroll).not_to be_nil expect(apple_pay_card.prepaid).not_to be_nil expect(apple_pay_card.product_id).not_to be_nil end it "creates a payment method from a fake apple pay mpan nonce" do customer = Braintree::Customer.create.customer token = SecureRandom.hex(16) result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::ApplePayMpan, :customer_id => customer.id, :token => token, ) expect(result).to be_success apple_pay_card = result.payment_method expect(apple_pay_card).to be_a(Braintree::ApplePayCard) expect(apple_pay_card).not_to be_nil expect(apple_pay_card.bin).not_to be_nil expect(apple_pay_card.token).to eq(token) expect(apple_pay_card.card_type).to eq(Braintree::ApplePayCard::CardType::Visa) expect(apple_pay_card.payment_instrument_name).to eq("Visa 8886") expect(apple_pay_card.source_description).to eq("Visa 8886") expect(apple_pay_card.default).to eq(true) expect(apple_pay_card.image_url).to match(/apple_pay/) expect(apple_pay_card.expiration_month.to_i).to be > 0 expect(apple_pay_card.expiration_year.to_i).to be > 0 expect(apple_pay_card.customer_id).to eq(customer.id) expect(apple_pay_card.commercial).not_to be_nil expect(apple_pay_card.country_of_issuance).not_to be_nil expect(apple_pay_card.debit).not_to be_nil expect(apple_pay_card.durbin_regulated).not_to be_nil expect(apple_pay_card.healthcare).not_to be_nil expect(apple_pay_card.issuing_bank).not_to be_nil expect(apple_pay_card.payroll).not_to be_nil expect(apple_pay_card.prepaid).not_to be_nil expect(apple_pay_card.product_id).not_to be_nil expect(apple_pay_card.merchant_token_identifier).not_to be_nil expect(apple_pay_card.source_card_last4).not_to be_nil end it "creates a payment method from a fake google pay proxy card nonce" do customer = Braintree::Customer.create.customer token = SecureRandom.hex(16) result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::GooglePayDiscover, :customer_id => customer.id, :token => token, ) expect(result).to be_success google_pay_card = result.payment_method expect(google_pay_card).to be_a(Braintree::GooglePayCard) expect(google_pay_card).not_to be_nil expect(google_pay_card.token).to eq(token) expect(google_pay_card.card_type).to eq(Braintree::CreditCard::CardType::Discover) expect(google_pay_card.virtual_card_type).to eq(Braintree::CreditCard::CardType::Discover) expect(google_pay_card.expiration_month.to_i).to be > 0 expect(google_pay_card.expiration_year.to_i).to be > 0 expect(google_pay_card.default).to eq(true) expect(google_pay_card.image_url).to match(/android_pay/) expect(google_pay_card.is_network_tokenized?).to eq(false) expect(google_pay_card.source_card_type).to eq(Braintree::CreditCard::CardType::Discover) expect(google_pay_card.source_card_last_4).to eq("1111") expect(google_pay_card.google_transaction_id).to eq("google_transaction_id") expect(google_pay_card.source_description).to eq("Discover 1111") expect(google_pay_card.customer_id).to eq(customer.id) expect(google_pay_card.commercial).not_to be_nil expect(google_pay_card.country_of_issuance).not_to be_nil expect(google_pay_card.debit).not_to be_nil expect(google_pay_card.durbin_regulated).not_to be_nil expect(google_pay_card.healthcare).not_to be_nil expect(google_pay_card.issuing_bank).not_to be_nil expect(google_pay_card.payroll).not_to be_nil expect(google_pay_card.prepaid).not_to be_nil expect(google_pay_card.product_id).not_to be_nil end it "creates a payment method from a google pay network token nonce" do customer = Braintree::Customer.create.customer token = SecureRandom.hex(16) result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::GooglePayMasterCard, :customer_id => customer.id, :token => token, ) expect(result).to be_success google_pay_card = result.payment_method expect(google_pay_card).to be_a(Braintree::GooglePayCard) expect(google_pay_card).not_to be_nil expect(google_pay_card.token).to eq(token) expect(google_pay_card.card_type).to eq(Braintree::CreditCard::CardType::MasterCard) expect(google_pay_card.virtual_card_type).to eq(Braintree::CreditCard::CardType::MasterCard) expect(google_pay_card.expiration_month.to_i).to be > 0 expect(google_pay_card.expiration_year.to_i).to be > 0 expect(google_pay_card.default).to eq(true) expect(google_pay_card.image_url).to match(/android_pay/) expect(google_pay_card.is_network_tokenized?).to eq(true) expect(google_pay_card.source_card_type).to eq(Braintree::CreditCard::CardType::MasterCard) expect(google_pay_card.source_card_last_4).to eq("4444") expect(google_pay_card.google_transaction_id).to eq("google_transaction_id") expect(google_pay_card.source_description).to eq("MasterCard 4444") expect(google_pay_card.customer_id).to eq(customer.id) expect(google_pay_card.commercial).not_to be_nil expect(google_pay_card.country_of_issuance).not_to be_nil expect(google_pay_card.debit).not_to be_nil expect(google_pay_card.durbin_regulated).not_to be_nil expect(google_pay_card.healthcare).not_to be_nil expect(google_pay_card.issuing_bank).not_to be_nil expect(google_pay_card.payroll).not_to be_nil expect(google_pay_card.prepaid).not_to be_nil expect(google_pay_card.product_id).not_to be_nil end it "creates a payment method from venmo account nonce" do customer = Braintree::Customer.create.customer token = SecureRandom.hex(16) result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::VenmoAccount, :customer_id => customer.id, :token => token, ) expect(result).to be_success venmo_account = result.payment_method expect(venmo_account).to be_a(Braintree::VenmoAccount) expect(venmo_account.default).to eq(true) expect(venmo_account.token).to eq(token) expect(venmo_account.username).to eq("venmojoe") expect(venmo_account.venmo_user_id).to eq("1234567891234567891") expect(venmo_account.image_url).to include(".png") expect(venmo_account.source_description).to eq("Venmo Account: venmojoe") expect(venmo_account.customer_id).to eq(customer.id) end it "allows passing the make_default option alongside the nonce" do customer = Braintree::Customer.create! result = Braintree::CreditCard.create( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2009", :cvv => "100", ) expect(result.success?).to eq(true) original_payment_method = result.credit_card expect(original_payment_method).to be_default nonce = nonce_for_paypal_account(:consent_code => "PAYPAL_CONSENT_CODE") result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => {:make_default => true}, ) expect(result).to be_success new_payment_method = result.payment_method expect(new_payment_method).to be_default end it "overrides the token in the nonce" do customer = Braintree::Customer.create! first_token = make_token second_token = make_token nonce = nonce_for_paypal_account( :consent_code => "PAYPAL_CONSENT_CODE", :token => first_token, ) result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :token => second_token, ) expect(result).to be_success payment_method = result.payment_method expect(payment_method.token).to eq(second_token) end it "respects verify_card and verification_merchant_account_id when included outside of the nonce" do nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa, :expiration_month => "11", :expiration_year => "2099", }, ) customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :verification_merchant_account_id => SpecHelper::NonDefaultMerchantAccountId }, ) expect(result).not_to be_success expect(result.credit_card_verification.status).to eq(Braintree::Transaction::Status::ProcessorDeclined) expect(result.credit_card_verification.processor_response_code).to eq("2000") expect(result.credit_card_verification.processor_response_text).to eq("Do Not Honor") expect(result.credit_card_verification.merchant_account_id).to eq(SpecHelper::NonDefaultMerchantAccountId) end it "respects verification amount when included outside of the nonce" do nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa, :expiration_month => "11", :expiration_year => "2099", }, ) customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :verification_amount => "100.00" }, ) expect(result).not_to be_success expect(result.credit_card_verification.status).to eq(Braintree::Transaction::Status::ProcessorDeclined) expect(result.credit_card_verification.processor_response_code).to eq("2000") expect(result.credit_card_verification.processor_response_text).to eq("Do Not Honor") expect(result.credit_card_verification.amount).to eq(BigDecimal("100.00")) end it "validates presence of three_d_secure_version in 3ds pass thru params" do customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :customer_id => customer.id, :payment_method_nonce => Braintree::Test::Nonce::Transactable, :three_d_secure_pass_thru => { :eci_flag => "05", :cavv => "some_cavv", :xid => "some_xid", :three_d_secure_version => "xx", :authentication_response => "Y", :directory_response => "Y", :cavv_algorithm => "2", :ds_transaction_id => "some_ds_transaction_id", }, :options => {:verify_card => true}, ) expect(result).not_to be_success error = result.errors.for(:verification).first expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::ThreeDSecureVersionIsInvalid) expect(error.message).to eq("The version of 3D Secure authentication must be composed only of digits and separated by periods (e.g. `1.0.2`).") end it "accepts three_d_secure pass thru params in the request" do customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :customer_id => customer.id, :payment_method_nonce => Braintree::Test::Nonce::Transactable, :three_d_secure_pass_thru => { :eci_flag => "05", :cavv => "some_cavv", :xid => "some_xid", :three_d_secure_version => "1.0.2", :authentication_response => "Y", :directory_response => "Y", :cavv_algorithm => "2", :ds_transaction_id => "some_ds_transaction_id", }, :options => {:verify_card => true}, ) expect(result).to be_success end it "returns 3DS info on cc verification" do customer = Braintree::Customer.create.customer result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::ThreeDSecureVisaFullAuthentication, :options => {:verify_card => true}, :customer_id => customer.id, ) expect(result.success?).to eq(true) three_d_secure_info = result.payment_method.verification.three_d_secure_info expect(three_d_secure_info.status).to eq("authenticate_successful") expect(three_d_secure_info).to be_liability_shifted expect(three_d_secure_info).to be_liability_shift_possible expect(three_d_secure_info.enrolled).to be_a(String) expect(three_d_secure_info.cavv).to be_a(String) expect(three_d_secure_info.xid).to be_a(String) expect(three_d_secure_info.eci_flag).to be_a(String) expect(three_d_secure_info.three_d_secure_version).to be_a(String) end it "respects fail_on_duplicate_payment_method when included outside of the nonce" do customer = Braintree::Customer.create! result = Braintree::CreditCard.create( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) expect(result).to be_success nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012" }, ) result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :fail_on_duplicate_payment_method => true }, ) expect(result).not_to be_success expect(result.errors.first.code).to eq("81724") end it "allows passing the billing address outside of the nonce" do config = Braintree::Configuration.instantiate customer = Braintree::Customer.create.customer raw_client_token = Braintree::ClientToken.generate(:customer_id => customer.id) client_token = decode_client_token(raw_client_token) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp.new( config, :authorization_fingerprint => authorization_fingerprint, :shared_customer_identifier => "fake_identifier", :shared_customer_identifier_type => "testing", ) response = http.create_credit_card( :number => "4111111111111111", :expirationMonth => "12", :expirationYear => "2020", :options => {:validate => false}, ) expect(response.code).to eq("202") nonce = JSON.parse(response.body)["creditCards"].first["nonce"] result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :billing_address => { :street_address => "123 Abc Way", :international_phone => {:country_code => "1", :national_number => "3121234567"}, }, ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::CreditCard) token = result.payment_method.token found_credit_card = Braintree::CreditCard.find(token) expect(found_credit_card).not_to be_nil expect(found_credit_card.billing_address.street_address).to eq("123 Abc Way") expect(found_credit_card.billing_address.international_phone[:country_code]).to eq("1") expect(found_credit_card.billing_address.international_phone[:national_number]).to eq("3121234567") end it "allows passing a billing address id outside of the nonce" do config = Braintree::Configuration.instantiate customer = Braintree::Customer.create.customer raw_client_token = Braintree::ClientToken.generate(:customer_id => customer.id) client_token = decode_client_token(raw_client_token) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp.new( config, :authorization_fingerprint => authorization_fingerprint, :shared_customer_identifier => "fake_identifier", :shared_customer_identifier_type => "testing", ) response = http.create_credit_card( :number => "4111111111111111", :expirationMonth => "12", :expirationYear => "2020", :options => {:validate => false}, ) expect(response.code).to eq("202") nonce = JSON.parse(response.body)["creditCards"].first["nonce"] address = Braintree::Address.create!(:customer_id => customer.id, :first_name => "Bobby", :last_name => "Tables") result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :billing_address_id => address.id, ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::CreditCard) token = result.payment_method.token found_credit_card = Braintree::CreditCard.find(token) expect(found_credit_card).not_to be_nil expect(found_credit_card.billing_address.first_name).to eq("Bobby") expect(found_credit_card.billing_address.last_name).to eq("Tables") end it "overrides the billing address in the nonce" do config = Braintree::Configuration.instantiate customer = Braintree::Customer.create.customer raw_client_token = Braintree::ClientToken.generate(:customer_id => customer.id) client_token = decode_client_token(raw_client_token) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp.new( config, :authorization_fingerprint => authorization_fingerprint, :shared_customer_identifier => "fake_identifier", :shared_customer_identifier_type => "testing", ) response = http.create_credit_card( :number => "4111111111111111", :expirationMonth => "12", :expirationYear => "2020", :options => {:validate => false}, :billing_address => { :street_address => "456 Xyz Way" }, ) expect(response.code).to eq("202") nonce = JSON.parse(response.body)["creditCards"].first["nonce"] result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :billing_address => { :street_address => "123 Abc Way" }, ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::CreditCard) token = result.payment_method.token found_credit_card = Braintree::CreditCard.find(token) expect(found_credit_card).not_to be_nil expect(found_credit_card.billing_address.street_address).to eq("123 Abc Way") end it "does not override the billing address for a vaulted credit card" do config = Braintree::Configuration.instantiate customer = Braintree::Customer.create.customer raw_client_token = Braintree::ClientToken.generate(:customer_id => customer.id) client_token = decode_client_token(raw_client_token) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp.new( config, :authorization_fingerprint => authorization_fingerprint, :shared_customer_identifier => "fake_identifier", :shared_customer_identifier_type => "testing", ) response = http.create_credit_card( :number => 4111111111111111, :expirationMonth => 12, :expirationYear => 2020, :billing_address => { :street_address => "456 Xyz Way" }, ) expect(response.code).to eq("201") nonce = JSON.parse(response.body)["creditCards"].first["nonce"] result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :billing_address => { :street_address => "123 Abc Way" }, ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::CreditCard) token = result.payment_method.token found_credit_card = Braintree::CreditCard.find(token) expect(found_credit_card).not_to be_nil expect(found_credit_card.billing_address.street_address).to eq("456 Xyz Way") end it "includes risk data when skip_advanced_fraud_checking is false" do with_fraud_protection_enterprise_merchant do customer = Braintree::Customer.create! nonce = nonce_for_new_payment_method( :credit_card => { :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2009", }, ) result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :skip_advanced_fraud_checking => false, }, ) expect(result).to be_success verification = result.payment_method.verification expect(verification.risk_data).not_to be_nil end end it "does not include risk data when skip_advanced_fraud_checking is true" do with_fraud_protection_enterprise_merchant do customer = Braintree::Customer.create! nonce = nonce_for_new_payment_method( :credit_card => { :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2009", }, ) result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :skip_advanced_fraud_checking => true, }, ) expect(result).to be_success verification = result.payment_method.verification expect(verification.risk_data).to be_nil end end context "account_type" do it "verifies card with account_type debit" do nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::Hiper, :expiration_month => "11", :expiration_year => "2099", }, ) customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :verification_merchant_account_id => SpecHelper::HiperBRLMerchantAccountId, :verification_account_type => "debit", }, ) expect(result).to be_success expect(result.payment_method.verification.credit_card[:account_type]).to eq("debit") end it "verifies card with account_type credit" do nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::Hiper, :expiration_month => "11", :expiration_year => "2099", }, ) customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :verification_merchant_account_id => SpecHelper::HiperBRLMerchantAccountId, :verification_account_type => "credit", }, ) expect(result).to be_success expect(result.payment_method.verification.credit_card[:account_type]).to eq("credit") end it "errors with invalid account_type" do nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::Hiper, :expiration_month => "11", :expiration_year => "2099", }, ) customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :verification_merchant_account_id => SpecHelper::HiperBRLMerchantAccountId, :verification_account_type => "ach", }, ) expect(result).not_to be_success expect(result.errors.for(:credit_card).for(:options).on(:verification_account_type)[0].code).to eq(Braintree::ErrorCodes::CreditCard::VerificationAccountTypeIsInvalid) end it "errors when account_type not supported by merchant" do nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_month => "11", :expiration_year => "2099", }, ) customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :verification_account_type => "credit", }, ) expect(result).not_to be_success expect(result.errors.for(:credit_card).for(:options).on(:verification_account_type)[0].code).to eq(Braintree::ErrorCodes::CreditCard::VerificationAccountTypeNotSupported) end it "updates the credit card with account_type credit" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::Hiper, :expiration_date => "06/2013", :options => { :verify_card => true, :verification_merchant_account_id => SpecHelper::HiperBRLMerchantAccountId, :verification_account_type => "credit", }, ) expect(update_result.success?).to eq(true) expect(update_result.payment_method.verification.credit_card[:account_type]).to eq("credit") end it "updates the credit card with account_type debit" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::Hiper, :expiration_date => "06/2013", :options => { :verify_card => true, :verification_merchant_account_id => SpecHelper::HiperBRLMerchantAccountId, :verification_account_type => "debit", }, ) expect(update_result.success?).to eq(true) expect(update_result.payment_method.verification.credit_card[:account_type]).to eq("debit") end end context "paypal" do it "creates a payment method from an unvalidated future paypal account nonce" do nonce = nonce_for_paypal_account(:consent_code => "PAYPAL_CONSENT_CODE") customer = Braintree::Customer.create.customer result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::PayPalAccount) expect(result.payment_method.image_url).not_to be_nil token = result.payment_method.token found_paypal_account = Braintree::PayPalAccount.find(token) expect(found_paypal_account).not_to be_nil end it "creates a limited use payment method from a paypal account nonce for a paypal intent==order payment" do nonce = nonce_for_paypal_account( :intent => "order", :payment_token => "fake-payment-token", :payer_id => "fake-payer-id", ) customer = Braintree::Customer.create.customer result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :paypal => { :payee_email => "payee@example.com", :order_id => "merchant-order-id", :custom_field => "custom merchant field", :description => "merchant description", :amount => "1.23", :shipping => { :first_name => "first", :last_name => "last", :locality => "Austin", :postal_code => "78729", :street_address => "7700 W Parmer Ln", :country_name => "US", :region => "TX", }, }, }, ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::PayPalAccount) expect(result.payment_method.image_url).not_to be_nil expect(result.payment_method.payer_id).not_to be_nil token = result.payment_method.token found_paypal_account = Braintree::PayPalAccount.find(token) expect(found_paypal_account).not_to be_nil expect(found_paypal_account.payer_id).not_to be_nil end it "creates a billing agreement payment method from a refresh token" do customer = Braintree::Customer.create.customer result = Braintree::PaymentMethod.create( :customer_id => customer.id, :paypal_refresh_token => "some_future_payment_token", ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::PayPalAccount) expect(result.payment_method.billing_agreement_id).to eq("B_FAKE_ID") expect(result.payment_method.payer_id).not_to be_nil token = result.payment_method.token found_paypal_account = Braintree::PayPalAccount.find(token) expect(found_paypal_account).not_to be_nil expect(found_paypal_account.billing_agreement_id).to eq("B_FAKE_ID") expect(found_paypal_account.payer_id).not_to be_nil end it "does not create a payment method from an unvalidated onetime paypal account nonce" do customer = Braintree::Customer.create.customer nonce = nonce_for_paypal_account(:access_token => "PAYPAL_ACCESS_TOKEN") result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, ) expect(result).not_to be_success expect(result.errors.first.code).to eq("82902") end it "ignores passed billing address params" do nonce = nonce_for_paypal_account(:consent_code => "PAYPAL_CONSENT_CODE") customer = Braintree::Customer.create.customer result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :billing_address => { :street_address => "123 Abc Way" }, ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::PayPalAccount) expect(result.payment_method.image_url).not_to be_nil token = result.payment_method.token found_paypal_account = Braintree::PayPalAccount.find(token) expect(found_paypal_account).not_to be_nil end it "ignores passed billing address id" do nonce = nonce_for_paypal_account(:consent_code => "PAYPAL_CONSENT_CODE") customer = Braintree::Customer.create.customer result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :billing_address_id => "address_id", ) expect(result).to be_success expect(result.payment_method).to be_a(Braintree::PayPalAccount) expect(result.payment_method.image_url).not_to be_nil token = result.payment_method.token found_paypal_account = Braintree::PayPalAccount.find(token) expect(found_paypal_account).not_to be_nil end it "returns appropriate validation errors" do customer = Braintree::Customer.create.customer nonce = nonce_for_paypal_account(:token => "PAYPAL_TOKEN") result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, ) expect(result).not_to be_success errors = result.errors.map(&:code) expect(errors).to include("82901") expect(errors).to include("82902") end it "doesn't return an error if credit card options are present for a paypal nonce" do customer = Braintree::Customer.create! original_token = random_payment_method_token nonce = nonce_for_paypal_account( :consent_code => "consent-code", :token => original_token, ) result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :fail_on_duplicate_payment_method => true, :verification_merchant_account_id => "not_a_real_merchant_account_id" }, ) expect(result).to be_success end end context "Unknown payment methods" do it "creates an unknown payment method from a nonce" do customer = Braintree::Customer.create.customer token = SecureRandom.hex(16) result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::AbstractTransactable, :customer_id => customer.id, :token => token, ) expect(result).to be_success payment_method = result.payment_method expect(payment_method).not_to be_nil expect(payment_method.token).to eq(token) expect(payment_method).to be_a Braintree::UnknownPaymentMethod end end context "verification_currency_iso_code" do it "validates verification_currency_iso_code against currency configured in default merchant account" do nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_month => "11", :expiration_year => "2099", }, ) customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :verification_currency_iso_code => "USD" }, ) expect(result).to be_success result.payment_method.verification.currency_iso_code == "USD" end it "validates verification_currency_iso_code against currency configured in verification_merchant_account_id" do nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_month => "11", :expiration_year => "2099", }, ) customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :verification_merchant_account_id => SpecHelper::NonDefaultMerchantAccountId, :verification_currency_iso_code => "USD" }, ) expect(result).to be_success result.payment_method.verification.currency_iso_code == "USD" result.payment_method.verification.merchant_account_id == SpecHelper::NonDefaultMerchantAccountId end it "errors with invalid presentment currency due to verification_currency_iso_code not matching with currency configured in default merchant account" do nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_month => "11", :expiration_year => "2099", }, ) customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :verification_currency_iso_code => "GBP" }, ) expect(result).not_to be_success expect(result.errors.for(:credit_card).for(:options).on(:verification_currency_iso_code)[0].code).to eq(Braintree::ErrorCodes::CreditCard::CurrencyCodeNotSupportedByMerchantAccount) end it "errors with invalid presentment currency due to verification_currency_iso_code not matching with currency configured in verification_merchant_account_id" do nonce = nonce_for_new_payment_method( :credit_card => { :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_month => "11", :expiration_year => "2099", }, ) customer = Braintree::Customer.create! result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, :options => { :verify_card => true, :verification_merchant_account_id => SpecHelper::NonDefaultMerchantAccountId, :verification_currency_iso_code => "GBP" }, ) expect(result).not_to be_success expect(result.errors.for(:credit_card).for(:options).on(:verification_currency_iso_code)[0].code).to eq(Braintree::ErrorCodes::CreditCard::CurrencyCodeNotSupportedByMerchantAccount) end end end describe "self.create!" do it "creates a payment method from a vaulted credit card nonce" do config = Braintree::Configuration.instantiate customer = Braintree::Customer.create.customer raw_client_token = Braintree::ClientToken.generate(:customer_id => customer.id) client_token = decode_client_token(raw_client_token) authorization_fingerprint = client_token["authorizationFingerprint"] http = ClientApiHttp.new( config, :authorization_fingerprint => authorization_fingerprint, :shared_customer_identifier => "fake_identifier", :shared_customer_identifier_type => "testing", ) response = http.create_credit_card( :number => 4111111111111111, :expirationMonth => 12, :expirationYear => 2020, ) expect(response.code).to eq("201") nonce = JSON.parse(response.body)["creditCards"].first["nonce"] payment_method = Braintree::PaymentMethod.create!( :payment_method_nonce => nonce, :customer_id => customer.id, ) expect(payment_method).to be_a(Braintree::CreditCard) token = payment_method.token found_credit_card = Braintree::CreditCard.find(token) expect(found_credit_card).not_to be_nil end end describe "self.find" do context "credit cards" do it "finds the payment method with the given token" do customer = Braintree::Customer.create.customer result = Braintree::CreditCard.create( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) expect(result.success?).to eq(true) credit_card = Braintree::PaymentMethod.find(result.credit_card.token) expect(credit_card.bin).to eq(Braintree::Test::CreditCardNumbers::Visa[0, 6]) expect(credit_card.last_4).to eq(Braintree::Test::CreditCardNumbers::Visa[-4..-1]) expect(credit_card.token).to eq(result.credit_card.token) expect(credit_card.expiration_date).to eq("05/2012") end it "returns associated subscriptions with the credit card" do customer = Braintree::Customer.create.customer credit_card = Braintree::CreditCard.create( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ).credit_card subscription = Braintree::Subscription.create( :payment_method_token => credit_card.token, :plan_id => "integration_trialless_plan", :price => "1.00", ).subscription found_card = Braintree::PaymentMethod.find(credit_card.token) expect(found_card.subscriptions.first.id).to eq(subscription.id) expect(found_card.subscriptions.first.plan_id).to eq("integration_trialless_plan") expect(found_card.subscriptions.first.payment_method_token).to eq(credit_card.token) expect(found_card.subscriptions.first.price).to eq(BigDecimal("1.00")) end end context "paypal accounts" do it "finds the payment method with the given token" do customer = Braintree::Customer.create! payment_method_token = make_token nonce = nonce_for_paypal_account( :consent_code => "consent-code", :token => payment_method_token, ) result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, ) expect(result).to be_success paypal_account = Braintree::PaymentMethod.find(payment_method_token) expect(paypal_account).to be_a(Braintree::PayPalAccount) expect(paypal_account.token).to eq(payment_method_token) expect(paypal_account.email).to eq("jane.doe@example.com") expect(paypal_account.customer_id).to eq(customer.id) end end context "apple pay cards" do it "finds the payment method with the given token" do customer = Braintree::Customer.create! payment_method_token = make_token result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::ApplePayAmEx, :customer_id => customer.id, :token => payment_method_token, ) expect(result).to be_success apple_pay_card = Braintree::PaymentMethod.find(payment_method_token) expect(apple_pay_card).to be_a(Braintree::ApplePayCard) expect(apple_pay_card).not_to be_nil expect(apple_pay_card.token).to eq(payment_method_token) expect(apple_pay_card.card_type).to eq(Braintree::ApplePayCard::CardType::AmEx) expect(apple_pay_card.default).to eq(true) expect(apple_pay_card.image_url).to match(/apple_pay/) expect(apple_pay_card.expiration_month.to_i).to be > 0 expect(apple_pay_card.expiration_year.to_i).to be > 0 expect(apple_pay_card.source_description).to eq("AmEx 41002") expect(apple_pay_card.customer_id).to eq(customer.id) end it "finds the payment method with the given mpan token" do customer = Braintree::Customer.create! payment_method_token = make_token result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::ApplePayMpan, :customer_id => customer.id, :token => payment_method_token, ) expect(result).to be_success apple_pay_card = Braintree::PaymentMethod.find(payment_method_token) expect(apple_pay_card).to be_a(Braintree::ApplePayCard) expect(apple_pay_card).not_to be_nil expect(apple_pay_card.token).to eq(payment_method_token) expect(apple_pay_card.card_type).to eq(Braintree::ApplePayCard::CardType::Visa) expect(apple_pay_card.default).to eq(true) expect(apple_pay_card.image_url).to match(/apple_pay/) expect(apple_pay_card.expiration_month.to_i).to be > 0 expect(apple_pay_card.expiration_year.to_i).to be > 0 expect(apple_pay_card.source_description).to eq("Visa 8886") expect(apple_pay_card.customer_id).to eq(customer.id) apple_pay_card.merchant_token_identifier == "DNITHE302308980427388297" apple_pay_card.source_card_last4 == "2006" end end context "venmo accounts" do it "finds the payment method with the given token" do customer = Braintree::Customer.create! payment_method_token = make_token result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::VenmoAccount, :customer_id => customer.id, :token => payment_method_token, ) expect(result).to be_success venmo_account = Braintree::PaymentMethod.find(payment_method_token) expect(venmo_account).to be_a(Braintree::VenmoAccount) expect(venmo_account).not_to be_nil expect(venmo_account.token).to eq(payment_method_token) expect(venmo_account.default).to eq(true) expect(venmo_account.image_url).to match(/venmo/) expect(venmo_account.username).to eq("venmojoe") expect(venmo_account.venmo_user_id).to eq("1234567891234567891") expect(venmo_account.source_description).to eq("Venmo Account: venmojoe") expect(venmo_account.customer_id).to eq(customer.id) end end context "google pay cards" do it "finds the proxy card payment method with the given token" do customer = Braintree::Customer.create! payment_method_token = make_token result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::GooglePayDiscover, :customer_id => customer.id, :token => payment_method_token, ) expect(result).to be_success google_pay_card = Braintree::PaymentMethod.find(payment_method_token) expect(google_pay_card).to be_a(Braintree::GooglePayCard) expect(google_pay_card).not_to be_nil expect(google_pay_card.token).to eq(payment_method_token) expect(google_pay_card.card_type).to eq(Braintree::CreditCard::CardType::Discover) expect(google_pay_card.virtual_card_type).to eq(Braintree::CreditCard::CardType::Discover) expect(google_pay_card.expiration_month.to_i).to be > 0 expect(google_pay_card.expiration_year.to_i).to be > 0 expect(google_pay_card.default).to eq(true) expect(google_pay_card.image_url).to match(/android_pay/) expect(google_pay_card.is_network_tokenized?).to eq(false) expect(google_pay_card.source_card_type).to eq(Braintree::CreditCard::CardType::Discover) expect(google_pay_card.source_card_last_4).to eq("1111") expect(google_pay_card.google_transaction_id).to eq("google_transaction_id") expect(google_pay_card.source_description).to eq("Discover 1111") expect(google_pay_card.customer_id).to eq(customer.id) end it "finds the network token payment method with the given token" do customer = Braintree::Customer.create! payment_method_token = make_token result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::GooglePayMasterCard, :customer_id => customer.id, :token => payment_method_token, ) expect(result).to be_success google_pay_card = Braintree::PaymentMethod.find(payment_method_token) expect(google_pay_card).to be_a(Braintree::GooglePayCard) expect(google_pay_card).not_to be_nil expect(google_pay_card.token).to eq(payment_method_token) expect(google_pay_card.card_type).to eq(Braintree::CreditCard::CardType::MasterCard) expect(google_pay_card.virtual_card_type).to eq(Braintree::CreditCard::CardType::MasterCard) expect(google_pay_card.expiration_month.to_i).to be > 0 expect(google_pay_card.expiration_year.to_i).to be > 0 expect(google_pay_card.default).to eq(true) expect(google_pay_card.image_url).to match(/android_pay/) expect(google_pay_card.is_network_tokenized?).to eq(true) expect(google_pay_card.source_card_type).to eq(Braintree::CreditCard::CardType::MasterCard) expect(google_pay_card.source_card_last_4).to eq("4444") expect(google_pay_card.google_transaction_id).to eq("google_transaction_id") expect(google_pay_card.source_description).to eq("MasterCard 4444") expect(google_pay_card.customer_id).to eq(customer.id) end end context "unknown payment methods" do it "finds the payment method with the given token" do customer = Braintree::Customer.create! payment_method_token = make_token result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::AbstractTransactable, :customer_id => customer.id, :token => payment_method_token, ) expect(result).to be_success payment_method = Braintree::PaymentMethod.find(payment_method_token) expect(payment_method).not_to be_nil expect(payment_method.token).to eq(payment_method_token) expect(payment_method.image_url).not_to be_nil expect(payment_method).to be_a Braintree::UnknownPaymentMethod expect(payment_method.customer_id).to eq(customer.id) end end it "raises a NotFoundError exception if payment method cannot be found" do expect do Braintree::PaymentMethod.find("invalid-token") end.to raise_error(Braintree::NotFoundError, 'payment method with token "invalid-token" not found') end end describe "self.delete" do it "deletes an google pay card" do customer = Braintree::Customer.create! create_result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::GooglePayDiscover, :customer_id => customer.id, ) token = create_result.payment_method.token google_card = Braintree::PaymentMethod.find(token) expect(google_card).to be_a(Braintree::GooglePayCard) delete_result = Braintree::PaymentMethod.delete(token) expect(delete_result.success?).to eq(true) expect do Braintree::PaymentMethod.find(token) end.to raise_error(Braintree::NotFoundError) end it "deletes an apple pay card" do customer = Braintree::Customer.create! create_result = Braintree::PaymentMethod.create( :payment_method_nonce => Braintree::Test::Nonce::ApplePayAmEx, :customer_id => customer.id, ) token = create_result.payment_method.token apple_pay_card = Braintree::PaymentMethod.find(token) expect(apple_pay_card).to be_a(Braintree::ApplePayCard) delete_result = Braintree::PaymentMethod.delete(token) expect(delete_result.success?).to eq(true) expect do Braintree::PaymentMethod.find(token) end.to raise_error(Braintree::NotFoundError) end it "deletes a paypal account" do customer = Braintree::Customer.create! paypal_account_token = make_token nonce = nonce_for_paypal_account( :consent_code => "PAYPAL_CONSENT_CODE", :token => paypal_account_token, ) Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, ) paypal_account = Braintree::PaymentMethod.find(paypal_account_token) expect(paypal_account).to be_a(Braintree::PayPalAccount) result = Braintree::PaymentMethod.delete(paypal_account_token, {:revoke_all_grants => false}) expect(result.success?).to eq(true) expect do Braintree::PaymentMethod.find(paypal_account_token) end.to raise_error(Braintree::NotFoundError, "payment method with token \"#{paypal_account_token}\" not found") end it "deletes a credit card" do token = make_token customer = Braintree::Customer.create! nonce = nonce_for_new_payment_method({ :credit_card => { :number => "4111111111111111", :expiration_month => "11", :expiration_year => "2099", :token => token }, :client_token_options => {:customer_id => customer.id} }) Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, ) result = Braintree::PaymentMethod.delete(token) expect(result.success?).to eq(true) expect do Braintree::PaymentMethod.find(token) end.to raise_error(Braintree::NotFoundError, "payment method with token \"#{token}\" not found") end it "raises a NotFoundError exception if payment method cannot be found" do token = make_token expect do Braintree::PaymentMethod.delete(token) end.to raise_error(Braintree::NotFoundError) end end describe "self.update" do context "credit cards" do it "throws validation error when passing invalid pass thru params" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :customer_id => customer.id, :payment_method_nonce => Braintree::Test::Nonce::ThreeDSecureVisaFullAuthentication, :options => {:verify_card => true}, ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_date => "06/2013", :three_d_secure_pass_thru => { :eci_flag => "02", :cavv => "some_cavv", :xid => "some_xid", :three_d_secure_version => "xx", :authentication_response => "Y", :directory_response => "Y", :cavv_algorithm => "2", :ds_transaction_id => "some_ds_transaction_id", }, :options => {:verify_card => true}, ) expect(update_result).to_not be_success error = update_result.errors.for(:verification).first expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::ThreeDSecureVersionIsInvalid) expect(error.message).to eq("The version of 3D Secure authentication must be composed only of digits and separated by periods (e.g. `1.0.2`).") end it "updates the credit card with three_d_secure pass thru params" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :customer_id => customer.id, :payment_method_nonce => Braintree::Test::Nonce::ThreeDSecureVisaFullAuthentication, :options => {:verify_card => true}, ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_date => "06/2013", :three_d_secure_pass_thru => { :eci_flag => "02", :cavv => "some_cavv", :xid => "some_xid", :three_d_secure_version => "1.0.2", :authentication_response => "Y", :directory_response => "Y", :cavv_algorithm => "2", :ds_transaction_id => "some_ds_transaction_id", }, :options => {:verify_card => true}, ) expect(update_result.success?).to eq(true) expect(update_result.payment_method).to eq(credit_card) updated_credit_card = update_result.payment_method expect(updated_credit_card.cardholder_name).to eq("New Holder") expect(updated_credit_card.bin).to eq(Braintree::Test::CreditCardNumbers::MasterCard[0, 6]) expect(updated_credit_card.last_4).to eq(Braintree::Test::CreditCardNumbers::MasterCard[-4..-1]) expect(updated_credit_card.expiration_date).to eq("06/2013") end it "updates the credit card" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_date => "06/2013", ) expect(update_result.success?).to eq(true) expect(update_result.payment_method).to eq(credit_card) updated_credit_card = update_result.payment_method expect(updated_credit_card.cardholder_name).to eq("New Holder") expect(updated_credit_card.bin).to eq(Braintree::Test::CreditCardNumbers::MasterCard[0, 6]) expect(updated_credit_card.last_4).to eq(Braintree::Test::CreditCardNumbers::MasterCard[-4..-1]) expect(updated_credit_card.expiration_date).to eq("06/2013") end it "includes risk data when skip_advanced_fraud_checking is false" do with_fraud_protection_enterprise_merchant do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update( credit_card.token, :cvv => "456", :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_date => "06/2013", :options => { :verify_card => true, :skip_advanced_fraud_checking => false }, ) expect(update_result).to be_success verification = update_result.payment_method.verification expect(verification.risk_data).not_to be_nil end end it "does not include risk data when skip_advanced_fraud_checking is true" do with_fraud_protection_enterprise_merchant do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update( credit_card.token, :cvv => "456", :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_date => "06/2013", :options => { :verify_card => true, :skip_advanced_fraud_checking => true }, ) expect(update_result).to be_success verification = update_result.payment_method.verification expect(verification.risk_data).to be_nil end end context "verification_currency_iso_code" do it "validates verification_currency_iso_code and updates the credit card " do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_date => "06/2013", :options => {:verify_card => true, :verification_currency_iso_code => "USD"}, ) expect(update_result.success?).to eq(true) update_result.payment_method.verification.currency_iso_code == "USD" end it "validates verification_currency_iso_code against the given verification_merchant_account_id and updates the credit card " do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_date => "06/2013", :options => {:verify_card => true, :verification_merchant_account_id => SpecHelper::NonDefaultMerchantAccountId, :verification_currency_iso_code => "USD"}, ) expect(update_result.success?).to eq(true) update_result.payment_method.verification.currency_iso_code == "USD" update_result.payment_method.verification.merchant_account_id == SpecHelper::NonDefaultMerchantAccountId end it "throws validation error when passing invalid verification_currency_iso_code" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_date => "06/2013", :options => {:verify_card => true, :verification_currency_iso_code => "GBP"}, ) expect(update_result).to_not be_success expect(update_result.errors.for(:credit_card).for(:options).on(:verification_currency_iso_code)[0].code).to eq(Braintree::ErrorCodes::CreditCard::CurrencyCodeNotSupportedByMerchantAccount) end it "throws validation error when passing invalid verification_currency_iso_code of the given verification merchant account id" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_date => "06/2013", :options => {:verify_card => true, :verification_merchant_account_id => SpecHelper::NonDefaultMerchantAccountId, :verification_currency_iso_code => "GBP"}, ) expect(update_result).to_not be_success expect(update_result.errors.for(:credit_card).for(:options).on(:verification_currency_iso_code)[0].code).to eq(Braintree::ErrorCodes::CreditCard::CurrencyCodeNotSupportedByMerchantAccount) end end context "billing address" do it "creates a new billing address by default" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", :billing_address => { :street_address => "123 Nigeria Ave" }, ) update_result = Braintree::PaymentMethod.update(credit_card.token, :billing_address => { :region => "IL" }, ) expect(update_result.success?).to eq(true) updated_credit_card = update_result.payment_method expect(updated_credit_card.billing_address.region).to eq("IL") expect(updated_credit_card.billing_address.street_address).to eq(nil) expect(updated_credit_card.billing_address.id).not_to eq(credit_card.billing_address.id) end it "updates the billing address if option is specified" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", :billing_address => { :street_address => "123 Nigeria Ave" }, ) update_result = Braintree::PaymentMethod.update(credit_card.token, :billing_address => { :international_phone => {:country_code => "1", :national_number => "3121234567"}, :region => "IL", :options => {:update_existing => true} }, ) expect(update_result.success?).to eq(true) updated_credit_card = update_result.payment_method expect(updated_credit_card.billing_address.international_phone[:country_code]).to eq("1") expect(updated_credit_card.billing_address.international_phone[:national_number]).to eq("3121234567") expect(updated_credit_card.billing_address.region).to eq("IL") expect(updated_credit_card.billing_address.street_address).to eq("123 Nigeria Ave") expect(updated_credit_card.billing_address.id).to eq(credit_card.billing_address.id) end it "updates the country via codes" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", :billing_address => { :street_address => "123 Nigeria Ave" }, ) update_result = Braintree::PaymentMethod.update(credit_card.token, :billing_address => { :country_name => "American Samoa", :country_code_alpha2 => "AS", :country_code_alpha3 => "ASM", :country_code_numeric => "016", :options => {:update_existing => true} }, ) expect(update_result.success?).to eq(true) updated_credit_card = update_result.payment_method expect(updated_credit_card.billing_address.country_name).to eq("American Samoa") expect(updated_credit_card.billing_address.country_code_alpha2).to eq("AS") expect(updated_credit_card.billing_address.country_code_alpha3).to eq("ASM") expect(updated_credit_card.billing_address.country_code_numeric).to eq("016") end end it "can pass expiration_month and expiration_year" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_month => "07", :expiration_year => "2011", ) expect(update_result.success?).to eq(true) expect(update_result.payment_method).to eq(credit_card) expect(update_result.payment_method.expiration_month).to eq("07") expect(update_result.payment_method.expiration_year).to eq("2011") expect(update_result.payment_method.expiration_date).to eq("07/2011") end it "verifies the update if options[verify_card]=true" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::MasterCard, :expiration_date => "06/2013", :options => {:verify_card => true}, ) expect(update_result.success?).to eq(false) expect(update_result.credit_card_verification.status).to eq(Braintree::Transaction::Status::ProcessorDeclined) expect(update_result.credit_card_verification.gateway_rejection_reason).to be_nil end it "accepts a custom verification amount" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Card Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2020", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :payment_method_nonce => Braintree::Test::Nonce::ProcessorDeclinedMasterCard, :options => {:verify_card => true, :verification_amount => "2.34"}, ) expect(update_result.success?).to eq(false) expect(update_result.credit_card_verification.status).to eq(Braintree::Transaction::Status::ProcessorDeclined) expect(update_result.credit_card_verification.gateway_rejection_reason).to be_nil expect(update_result.credit_card_verification.amount).to eq(BigDecimal("2.34")) end it "can update the billing address" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", :billing_address => { :first_name => "Old First Name", :last_name => "Old Last Name", :company => "Old Company", :street_address => "123 Old St", :extended_address => "Apt Old", :locality => "Old City", :region => "Old State", :postal_code => "12345", :country_name => "Canada" }, ) result = Braintree::PaymentMethod.update(credit_card.token, :options => {:verify_card => false}, :billing_address => { :first_name => "New First Name", :last_name => "New Last Name", :company => "New Company", :street_address => "123 New St", :extended_address => "Apt New", :locality => "New City", :region => "New State", :postal_code => "56789", :country_name => "United States of America" }, ) expect(result.success?).to eq(true) address = result.payment_method.billing_address expect(address.first_name).to eq("New First Name") expect(address.last_name).to eq("New Last Name") expect(address.company).to eq("New Company") expect(address.street_address).to eq("123 New St") expect(address.extended_address).to eq("Apt New") expect(address.locality).to eq("New City") expect(address.region).to eq("New State") expect(address.postal_code).to eq("56789") expect(address.country_name).to eq("United States of America") end it "returns an error response if invalid" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) update_result = Braintree::PaymentMethod.update(credit_card.token, :cardholder_name => "New Holder", :number => "invalid", :expiration_date => "05/2014", ) expect(update_result.success?).to eq(false) expect(update_result.errors.for(:credit_card).on(:number)[0].message).to eq("Credit card number must be 12-19 digits.") end it "can update the default" do customer = Braintree::Customer.create! card1 = Braintree::CreditCard.create( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2009", ).credit_card card2 = Braintree::CreditCard.create( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2009", ).credit_card expect(card1).to be_default expect(card2).not_to be_default Braintree::PaymentMethod.update(card2.token, :options => {:make_default => true}) expect(Braintree::CreditCard.find(card1.token)).not_to be_default expect(Braintree::CreditCard.find(card2.token)).to be_default end end context "paypal accounts" do it "updates a paypal account's token" do customer = Braintree::Customer.create! original_token = random_payment_method_token nonce = nonce_for_paypal_account( :consent_code => "consent-code", :token => original_token, ) original_result = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, ) updated_token = make_token Braintree::PaymentMethod.update( original_token, :token => updated_token, ) updated_paypal_account = Braintree::PayPalAccount.find(updated_token) expect(updated_paypal_account.email).to eq(original_result.payment_method.email) expect do Braintree::PayPalAccount.find(original_token) end.to raise_error(Braintree::NotFoundError, "payment method with token \"#{original_token}\" not found") end it "can make a paypal account the default payment method" do customer = Braintree::Customer.create! result = Braintree::CreditCard.create( :customer_id => customer.id, :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2009", :options => {:make_default => true}, ) expect(result).to be_success nonce = nonce_for_paypal_account(:consent_code => "consent-code") original_token = Braintree::PaymentMethod.create( :payment_method_nonce => nonce, :customer_id => customer.id, ).payment_method.token Braintree::PaymentMethod.update( original_token, :options => {:make_default => true}, ) updated_paypal_account = Braintree::PayPalAccount.find(original_token) expect(updated_paypal_account).to be_default end it "returns an error if a token for account is used to attempt an update" do customer = Braintree::Customer.create! first_token = random_payment_method_token second_token = random_payment_method_token first_nonce = nonce_for_paypal_account( :consent_code => "consent-code", :token => first_token, ) Braintree::PaymentMethod.create( :payment_method_nonce => first_nonce, :customer_id => customer.id, ) second_nonce = nonce_for_paypal_account( :consent_code => "consent-code", :token => second_token, ) Braintree::PaymentMethod.create( :payment_method_nonce => second_nonce, :customer_id => customer.id, ) updated_result = Braintree::PaymentMethod.update( first_token, :token => second_token, ) expect(updated_result).not_to be_success expect(updated_result.errors.first.code).to eq("92906") end end end describe "self.update!" do it "updates the credit card" do customer = Braintree::Customer.create! credit_card = Braintree::CreditCard.create!( :cardholder_name => "Original Holder", :customer_id => customer.id, :cvv => "123", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2012", ) payment_method = Braintree::PaymentMethod.update!(credit_card.token, :cardholder_name => "New Holder", :cvv => "456", :number => Braintree::Test::CreditCardNumbers::MasterCard, :expiration_date => "06/2013", ) expect(payment_method).to eq(credit_card) expect(payment_method.cardholder_name).to eq("New Holder") expect(payment_method.bin).to eq(Braintree::Test::CreditCardNumbers::MasterCard[0, 6]) expect(payment_method.last_4).to eq(Braintree::Test::CreditCardNumbers::MasterCard[-4..-1]) expect(payment_method.expiration_date).to eq("06/2013") end end context "payment method grant and revoke" do before(:each) do @partner_merchant_gateway = Braintree::Gateway.new( :merchant_id => "integration_merchant_public_id", :public_key => "oauth_app_partner_user_public_key", :private_key => "oauth_app_partner_user_private_key", :environment => Braintree::Configuration.environment, :logger => Logger.new("/dev/null"), ) customer = @partner_merchant_gateway.customer.create( :first_name => "Joe", :last_name => "Brown", :company => "ExampleCo", :email => "joe@example.com", :phone => "312.555.1234", :fax => "614.555.5678", :website => "www.example.com", ).customer @credit_card = @partner_merchant_gateway.credit_card.create( :customer_id => customer.id, :cardholder_name => "Adam Davis", :number => Braintree::Test::CreditCardNumbers::Visa, :expiration_date => "05/2009", ).credit_card @oauth_gateway = Braintree::Gateway.new( :client_id => "client_id$#{Braintree::Configuration.environment}$integration_client_id", :client_secret => "client_secret$#{Braintree::Configuration.environment}$integration_client_secret", :logger => Logger.new("/dev/null"), ) access_token = Braintree::OAuthTestHelper.create_token(@oauth_gateway, { :merchant_public_id => "integration_merchant_id", :scope => "grant_payment_method" }).credentials.access_token @granting_gateway = Braintree::Gateway.new( :access_token => access_token, :logger => Logger.new("/dev/null"), ) end describe "self.grant" do it "returns an error result when the grant doesn't succeed" do grant_result = @granting_gateway.payment_method.grant("payment_method_from_grant", true) expect(grant_result).not_to be_success end it "returns a nonce that is transactable by a partner merchant exactly once" do grant_result = @granting_gateway.payment_method.grant(@credit_card.token, :allow_vaulting => false) expect(grant_result).to be_success result = Braintree::Transaction.sale( :payment_method_nonce => grant_result.payment_method_nonce.nonce, :amount => Braintree::Test::TransactionAmounts::Authorize, ) expect(result).to be_success result2 = Braintree::Transaction.sale( :payment_method_nonce => grant_result.payment_method_nonce.nonce, :amount => Braintree::Test::TransactionAmounts::Authorize, ) expect(result2).not_to be_success end it "returns a nonce that is not vaultable" do grant_result = @granting_gateway.payment_method.grant(@credit_card.token, false) customer_result = Braintree::Customer.create() result = Braintree::PaymentMethod.create( :customer_id => customer_result.customer.id, :payment_method_nonce => grant_result.payment_method_nonce.nonce, ) expect(result).not_to be_success end it "returns a nonce that is vaultable" do grant_result = @granting_gateway.payment_method.grant(@credit_card.token, :allow_vaulting => true) customer_result = Braintree::Customer.create() result = Braintree::PaymentMethod.create( :customer_id => customer_result.customer.id, :payment_method_nonce => grant_result.payment_method_nonce.nonce, ) expect(result).to be_success end it "raises an error if the token isn't found" do expect do @granting_gateway.payment_method.grant("not_a_real_token", false) end.to raise_error(Braintree::NotFoundError) end it "returns a valid nonce with no options set" do expect do grant_result = @granting_gateway.payment_method.grant(@credit_card.token) expect(grant_result).to be_success end end end describe "self.revoke" do it "raises an error if the token isn't found" do expect do @granting_gateway.payment_method.revoke("not_a_real_token") end.to raise_error(Braintree::NotFoundError) end it "renders a granted nonce useless" do grant_result = @granting_gateway.payment_method.grant(@credit_card.token) revoke_result = @granting_gateway.payment_method.revoke(@credit_card.token) expect(revoke_result).to be_success customer_result = Braintree::Customer.create() result = Braintree::PaymentMethod.create( :customer_id => customer_result.customer.id, :payment_method_nonce => grant_result.payment_method_nonce.nonce, ) expect(result).not_to be_success end it "renders a granted nonce obtained uisng options hash, useless" do grant_result = @granting_gateway.payment_method.grant(@credit_card.token, :allow_vaulting => true) revoke_result = @granting_gateway.payment_method.revoke(@credit_card.token) expect(revoke_result).to be_success customer_result = Braintree::Customer.create() result = Braintree::PaymentMethod.create( :customer_id => customer_result.customer.id, :payment_method_nonce => grant_result.payment_method_nonce.nonce, ) expect(result).not_to be_success end end end end