require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")

describe Braintree::CreditCard do
  describe "self.create" do
    it "throws and ArgumentError if given exipiration_date and any combination of expiration_month and expiration_year" do
      expect do
        Braintree::CreditCard.create :expiration_date => "anything", :expiration_month => "anything"
      end.to raise_error(ArgumentError, "create with both expiration_month and expiration_year or only expiration_date")
    end

    it "adds credit card to an existing customer" 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)
      credit_card = result.credit_card
      expect(credit_card.token).to match(/\A\w{4,}\z/)
      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.expiration_date).to eq("05/2009")
      expect(credit_card.unique_number_identifier).to match(/\A\w{32}\z/)
      expect(credit_card.venmo_sdk?).to eq(false)
      expect(credit_card.image_url).not_to be_nil
    end

    it "supports creation of cards with security params" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::Visa,
        :expiration_date => "05/2009",
        :cvv => "100",
        :device_data => "device_data",
      )
      expect(result.success?).to eq(true)
    end

    it "can provide expiration month and year separately" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::Visa,
        :expiration_month => "05",
        :expiration_year => "2012",
      )
      expect(result.success?).to eq(true)
      credit_card = result.credit_card
      expect(credit_card.expiration_month).to eq("05")
      expect(credit_card.expiration_year).to eq("2012")
      expect(credit_card.expiration_date).to eq("05/2012")
    end

    it "can specify the desired token" do
      token = "token_#{rand(10**10)}"
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::Visa,
        :expiration_date => "05/2009",
        :cvv => "100",
        :token => token,
      )
      expect(result.success?).to eq(true)
      credit_card = result.credit_card
      expect(credit_card.token).to eq(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.expiration_date).to eq("05/2009")
    end

    it "accepts billing_address_id" do
      customer = Braintree::Customer.create!
      address = Braintree::Address.create!(:customer_id => customer.id, :first_name => "Bobby", :last_name => "Tables")

      credit_card = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa,
        :expiration_date => "05/2009",
        :billing_address_id => address.id,
      ).credit_card

      expect(credit_card.billing_address.id).to eq(address.id)
      expect(credit_card.billing_address.first_name).to eq("Bobby")
      expect(credit_card.billing_address.last_name).to eq("Tables")
    end

    it "accepts empty options hash" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa,
        :expiration_date => "05/2009",
        :options => {},
      )
      expect(result.success?).to eq(true)
    end

    it "verifies the credit card if options[verify_card]=true" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa,
        :expiration_date => "05/2009",
        :options => {:verify_card => true},
      )
      expect(result.success?).to eq(false)
      expect(result.credit_card_verification.status).to eq(Braintree::CreditCardVerification::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.cvv_response_code).to eq("I")
      expect(result.credit_card_verification.avs_error_response_code).to eq(nil)
      expect(result.credit_card_verification.avs_postal_code_response_code).to eq("I")
      expect(result.credit_card_verification.avs_street_address_response_code).to eq("I")
    end

    it "allows passing a specific verification amount" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa,
        :expiration_date => "05/2009",
        :options => {:verify_card => true, :verification_amount => "100.00"},
      )
      expect(result.success?).to eq(false)
      expect(result.credit_card_verification.status).to eq(Braintree::CreditCardVerification::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.cvv_response_code).to eq("I")
      expect(result.credit_card_verification.avs_error_response_code).to eq(nil)
      expect(result.credit_card_verification.avs_postal_code_response_code).to eq("I")
      expect(result.credit_card_verification.avs_street_address_response_code).to eq("I")
    end

    it "returns risk data on verification on credit_card create" do
      with_fraud_protection_enterprise_merchant 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/2020",
          :options => {:verify_card => true},
        )
        verification = credit_card.verification
        expect(verification.risk_data.id).not_to be_nil
        expect(verification.risk_data.decision).not_to be_nil
        expect(verification.risk_data.decision_reasons).not_to be_nil
        expect(verification.risk_data).to respond_to(:device_data_captured)
        expect(verification.risk_data).to respond_to(:fraud_service_provider)
        expect(verification.risk_data).to respond_to(:transaction_risk_score)
      end
    end

    it "includes risk data when skip_advanced_fraud_checking is false" do
      with_fraud_protection_enterprise_merchant do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :cardholder_name => "Original Holder",
          :customer_id => customer.id,
          :cvv => "123",
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "05/2020",
          :options => {
            :skip_advanced_fraud_checking => false,
            :verify_card => true,
          },
        )

        expect(result).to be_success
        verification = result.credit_card.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!
        result = Braintree::CreditCard.create(
          :cardholder_name => "Original Holder",
          :customer_id => customer.id,
          :cvv => "123",
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "05/2020",
          :options => {
            :skip_advanced_fraud_checking => true,
            :verify_card => true,
          },
        )

        expect(result).to be_success
        verification = result.credit_card.verification
        expect(verification.risk_data).to be_nil
      end
    end

    it "exposes the gateway rejection reason on verification" do
      old_merchant = Braintree::Configuration.merchant_id
      old_public_key = Braintree::Configuration.public_key
      old_private_key = Braintree::Configuration.private_key

      begin
        Braintree::Configuration.merchant_id = "processing_rules_merchant_id"
        Braintree::Configuration.public_key = "processing_rules_public_key"
        Braintree::Configuration.private_key = "processing_rules_private_key"

        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "05/2009",
          :cvv => "200",
          :options => {:verify_card => true},
        )
        expect(result.success?).to eq(false)
        expect(result.credit_card_verification.gateway_rejection_reason).to eq(Braintree::CreditCardVerification::GatewayRejectionReason::CVV)
      ensure
        Braintree::Configuration.merchant_id = old_merchant
        Braintree::Configuration.public_key = old_public_key
        Braintree::Configuration.private_key = old_private_key
      end
    end

    it "verifies the credit card if options[verify_card]=true" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa,
        :expiration_date => "05/2009",
        :options => {:verify_card => true, :verification_amount => "1.01"},
      )
      expect(result.success?).to eq(false)
      expect(result.credit_card_verification.status).to eq(Braintree::CreditCardVerification::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.cvv_response_code).to eq("I")
      expect(result.credit_card_verification.avs_error_response_code).to eq(nil)
      expect(result.credit_card_verification.avs_postal_code_response_code).to eq("I")
      expect(result.credit_card_verification.avs_street_address_response_code).to eq("I")
    end

    it "allows user to specify merchant account for verification" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa,
        :expiration_date => "05/2009",
        :options => {
          :verify_card => true,
          :verification_merchant_account_id => SpecHelper::NonDefaultMerchantAccountId
        },
      )
      expect(result.success?).to eq(false)
      expect(result.credit_card_verification.merchant_account_id).to eq(SpecHelper::NonDefaultMerchantAccountId)
    end

    it "does not verify the card if options[verify_card]=false" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa,
        :expiration_date => "05/2009",
        :options => {:verify_card => false},
      )
      expect(result.success?).to eq(true)
    end

    it "validates presence of three_d_secure_version in 3ds pass thru params" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :payment_method_nonce => Braintree::Test::Nonce::Transactable,
        :three_d_secure_pass_thru => {
          :eci_flag => "02",
          :cavv => "some_cavv",
          :xid => "some_xid",
          :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::ThreeDSecureVersionIsRequired)
      expect(error.message).to eq("ThreeDSecureVersion is required.")
    end

    it "accepts three_d_secure pass thru params in the request" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :payment_method_nonce => Braintree::Test::Nonce::Transactable,
        :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(result.success?).to eq(true)

    end

    it "returns 3DS info on cc verification" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :payment_method_nonce => Braintree::Test::Nonce::ThreeDSecureVisaFullAuthentication,
        :options => {:verify_card => true},
      )
      expect(result.success?).to eq(true)

      three_d_secure_info = result.credit_card.verification.three_d_secure_info
      expect(three_d_secure_info.enrolled).to eq("Y")
      expect(three_d_secure_info).to be_liability_shifted
      expect(three_d_secure_info).to be_liability_shift_possible
      expect(three_d_secure_info.status).to eq("authenticate_successful")
      expect(three_d_secure_info.cavv).to eq("cavv_value")
      expect(three_d_secure_info.xid).to eq("xid_value")
      expect(three_d_secure_info.eci_flag).to eq("05")
      expect(three_d_secure_info.three_d_secure_version).to eq("1.0.2")
      expect(three_d_secure_info.ds_transaction_id).to eq(nil)
      expect(three_d_secure_info.three_d_secure_authentication_id).not_to be_nil
    end

    it "adds credit card with billing address to customer" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::MasterCard,
        :expiration_date => "12/2009",
        :billing_address => {
          :street_address => "123 Abc Way",
          :locality => "Chicago",
          :region => "Illinois",
          :postal_code => "60622"
        },
      )
      expect(result.success?).to eq(true)
      credit_card = result.credit_card
      expect(credit_card.bin).to eq(Braintree::Test::CreditCardNumbers::MasterCard[0, 6])
      expect(credit_card.billing_address.street_address).to eq("123 Abc Way")
    end

    it "adds credit card with billing using country_code" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::MasterCard,
        :expiration_date => "12/2009",
        :billing_address => {
          :country_name => "United States of America",
          :country_code_alpha2 => "US",
          :country_code_alpha3 => "USA",
          :country_code_numeric => "840"
        },
      )
      expect(result.success?).to eq(true)
      credit_card = result.credit_card
      expect(credit_card.billing_address.country_name).to eq("United States of America")
      expect(credit_card.billing_address.country_code_alpha2).to eq("US")
      expect(credit_card.billing_address.country_code_alpha3).to eq("USA")
      expect(credit_card.billing_address.country_code_numeric).to eq("840")
    end

    it "returns an error when given inconsistent country information" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::MasterCard,
        :expiration_date => "12/2009",
        :billing_address => {
          :country_name => "Mexico",
          :country_code_alpha2 => "US"
        },
      )
      expect(result.success?).to eq(false)
      expect(result.errors.for(:credit_card).for(:billing_address).on(:base).map { |e| e.code }).to include(Braintree::ErrorCodes::Address::InconsistentCountry)
    end

    it "returns an error response if unsuccessful" do
      customer = Braintree::Customer.create!
      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::Visa,
        :expiration_date => "invalid_date",
      )
      expect(result.success?).to eq(false)
      expect(result.errors.for(:credit_card).on(:expiration_date)[0].message).to eq("Expiration date is invalid.")
    end

    it "can set the default flag" do
      customer = Braintree::Customer.create!
      card1 = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::Visa,
        :expiration_date => "05/2009",
      ).credit_card
      expect(card1).to be_default

      card2 = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::Visa,
        :expiration_date => "05/2009",
        :options => {
          :make_default => true
        },
      ).credit_card
      expect(card2).to be_default

      expect(Braintree::CreditCard.find(card1.token)).not_to be_default
    end

    it "can set the network transaction identifier when creating a credit card" do
      customer = Braintree::Customer.create!

      result = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::Visa,
        :expiration_date => "05/2009",
        :external_vault => {
          :network_transaction_id => "MCC123456789",
        },
      )

      expect(result.success?).to eq(true)
    end

    context "card type indicators" do
      it "sets the prepaid field if the card is prepaid" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::Prepaid,
          :expiration_date => "05/2014",
          :options => {:verify_card => true},
        )
        credit_card = result.credit_card
        expect(credit_card.prepaid).to eq(Braintree::CreditCard::Prepaid::Yes)
      end

      it "sets the healthcare field if the card is healthcare" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::Healthcare,
          :expiration_date => "05/2014",
          :options => {:verify_card => true},
        )
        credit_card = result.credit_card
        expect(credit_card.healthcare).to eq(Braintree::CreditCard::Healthcare::Yes)
        expect(credit_card.product_id).to eq("J3")
      end

      it "sets the durbin regulated field if the card is durbin regulated" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::DurbinRegulated,
          :expiration_date => "05/2014",
          :options => {:verify_card => true},
        )
        credit_card = result.credit_card
        expect(credit_card.durbin_regulated).to eq(Braintree::CreditCard::DurbinRegulated::Yes)
      end

      it "sets the country of issuance field" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::CountryOfIssuance,
          :expiration_date => "05/2014",
          :options => {:verify_card => true},
        )
        credit_card = result.credit_card
        expect(credit_card.country_of_issuance).to eq(Braintree::Test::CreditCardDefaults::CountryOfIssuance)
      end

      it "sets the issuing bank field" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::IssuingBank,
          :expiration_date => "05/2014",
          :options => {:verify_card => true},
        )
        credit_card = result.credit_card
        expect(credit_card.issuing_bank).to eq(Braintree::Test::CreditCardDefaults::IssuingBank)
      end

      it "sets the payroll field if the card is payroll" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::Payroll,
          :expiration_date => "05/2014",
          :options => {:verify_card => true},
        )
        credit_card = result.credit_card
        expect(credit_card.payroll).to eq(Braintree::CreditCard::Payroll::Yes)
        expect(credit_card.product_id).to eq("MSA")
      end

      it "sets the debit field if the card is debit" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::Debit,
          :expiration_date => "05/2014",
          :options => {:verify_card => true},
        )
        credit_card = result.credit_card
        expect(credit_card.debit).to eq(Braintree::CreditCard::Debit::Yes)
      end

      it "sets the commercial field if the card is commercial" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::Commercial,
          :expiration_date => "05/2014",
          :options => {:verify_card => true},
        )
        credit_card = result.credit_card
        expect(credit_card.commercial).to eq(Braintree::CreditCard::Commercial::Yes)
      end

      it "sets negative card type identifiers" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::No,
          :expiration_date => "05/2014",
          :options => {:verify_card => true},
        )
        credit_card = result.credit_card
        expect(credit_card.prepaid).to eq(Braintree::CreditCard::Prepaid::No)
        expect(credit_card.commercial).to eq(Braintree::CreditCard::Prepaid::No)
        expect(credit_card.payroll).to eq(Braintree::CreditCard::Prepaid::No)
        expect(credit_card.debit).to eq(Braintree::CreditCard::Prepaid::No)
        expect(credit_card.durbin_regulated).to eq(Braintree::CreditCard::Prepaid::No)
        expect(credit_card.healthcare).to eq(Braintree::CreditCard::Prepaid::No)
        expect(credit_card.product_id).to eq("MSB")
      end

      it "doesn't set the card type identifiers for an un-identified card" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::CardTypeIndicators::Unknown,
          :expiration_date => "05/2014",
          :options => {:verify_card => true},
        )
        credit_card = result.credit_card
        expect(credit_card.prepaid).to eq(Braintree::CreditCard::Prepaid::Unknown)
        expect(credit_card.commercial).to eq(Braintree::CreditCard::Prepaid::Unknown)
        expect(credit_card.payroll).to eq(Braintree::CreditCard::Prepaid::Unknown)
        expect(credit_card.debit).to eq(Braintree::CreditCard::Prepaid::Unknown)
        expect(credit_card.durbin_regulated).to eq(Braintree::CreditCard::Prepaid::Unknown)
        expect(credit_card.healthcare).to eq(Braintree::CreditCard::Prepaid::Unknown)
        credit_card.country_of_issuance == Braintree::CreditCard::CountryOfIssuance::Unknown
        credit_card.issuing_bank == Braintree::CreditCard::IssuingBank::Unknown
        credit_card.product_id == Braintree::CreditCard::ProductId::Unknown
      end
    end

    context "client API" do
      it "adds credit card to an existing customer using a payment method nonce" do
        nonce = nonce_for_new_payment_method(
          :credit_card => {
            :number => "4111111111111111",
            :expiration_month => "11",
            :expiration_year => "2099",
          },
          :share => true,
        )
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :payment_method_nonce => nonce,
        )

        expect(result.success?).to eq(true)
        credit_card = result.credit_card
        expect(credit_card.bin).to eq("411111")
        expect(credit_card.last_4).to eq("1111")
        expect(credit_card.expiration_date).to eq("11/2099")
      end
    end

    context "card_type" do
      it "is set to Elo" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::Elo,
          :expiration_date => "10/2020",
        )
        expect(result.success?).to eq(true)
        credit_card = result.credit_card
        expect(credit_card.card_type).to eq(Braintree::CreditCard::CardType::Elo)
      end
    end

    context "verification_account_type" do
      it "verifies card with account_type debit" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::Hiper,
          :expiration_month => "11",
          :expiration_year => "2099",
          :options => {
            :verify_card => true,
            :verification_merchant_account_id => SpecHelper::HiperBRLMerchantAccountId,
            :verification_account_type => "debit",
          },
        )

        expect(result).to be_success
      end

      it "verifies card with account_type credit" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::Hiper,
          :expiration_month => "11",
          :expiration_year => "2099",
          :options => {
            :verify_card => true,
            :verification_merchant_account_id => SpecHelper::HiperBRLMerchantAccountId,
            :verification_account_type => "credit",
          },
        )

        expect(result).to be_success
      end

      it "errors with invalid account_type" do
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :number => Braintree::Test::CreditCardNumbers::Hiper,
          :expiration_month => "11",
          :expiration_year => "2099",
          :options => {
            :verify_card => true,
            :verification_merchant_account_id => SpecHelper::HiperBRLMerchantAccountId,
            :verification_account_type => "ach",
          },
        )

        expect(result).to_not 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
        customer = Braintree::Customer.create!
        result = Braintree::CreditCard.create(
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_month => "11",
          :expiration_year => "2099",
          :options => {
            :verify_card => true,
            :verification_account_type => "credit",
          },
        )

        expect(result).to_not be_success
        expect(result.errors.for(:credit_card).for(:options).on(:verification_account_type)[0].code).to eq Braintree::ErrorCodes::CreditCard::VerificationAccountTypeNotSupported
      end
    end
  end

  describe "self.create!" do
    it "returns the credit card if successful" do
      customer = Braintree::Customer.create!
      credit_card = Braintree::CreditCard.create!(
        :customer_id => customer.id,
        :cardholder_name => "Adam Davis",
        :number => Braintree::Test::CreditCardNumbers::Visa,
        :expiration_date => "05/2009",
      )
      expect(credit_card.bin).to eq(Braintree::Test::CreditCardNumbers::Visa[0, 6])
      expect(credit_card.cardholder_name).to eq("Adam Davis")
      expect(credit_card.last_4).to eq(Braintree::Test::CreditCardNumbers::Visa[-4..-1])
      expect(credit_card.expiration_date).to eq("05/2009")
    end

    it "raises a ValidationsFailed if unsuccessful" do
      customer = Braintree::Customer.create!
      expect do
        Braintree::CreditCard.create!(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "invalid_date",
        )
      end.to raise_error(Braintree::ValidationsFailed)
    end
  end

  describe "self.credit" do
    it "creates a credit transaction using the payment method token, returning a result object" do
      customer = Braintree::Customer.create!(
        :credit_card => {
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "05/2010"
        },
      )
      result = Braintree::CreditCard.credit(
        customer.credit_cards[0].token,
        :amount => "100.00",
      )
      expect(result.success?).to eq(true)
      expect(result.transaction.amount).to eq(BigDecimal("100.00"))
      expect(result.transaction.type).to eq("credit")
      expect(result.transaction.customer_details.id).to eq(customer.id)
      expect(result.transaction.credit_card_details.token).to eq(customer.credit_cards[0].token)
      expect(result.transaction.credit_card_details.bin).to eq(Braintree::Test::CreditCardNumbers::Visa[0, 6])
      expect(result.transaction.credit_card_details.last_4).to eq(Braintree::Test::CreditCardNumbers::Visa[-4..-1])
      expect(result.transaction.credit_card_details.expiration_date).to eq("05/2010")
    end
  end

  describe "self.credit!" do
    it "creates a credit transaction using the payment method token, returning the transaction" do
      customer = Braintree::Customer.create!(
        :credit_card => {
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "05/2010"
        },
      )
      transaction = Braintree::CreditCard.credit!(
        customer.credit_cards[0].token,
        :amount => "100.00",
      )
      expect(transaction.amount).to eq(BigDecimal("100.00"))
      expect(transaction.type).to eq("credit")
      expect(transaction.customer_details.id).to eq(customer.id)
      expect(transaction.credit_card_details.token).to eq(customer.credit_cards[0].token)
      expect(transaction.credit_card_details.bin).to eq(Braintree::Test::CreditCardNumbers::Visa[0, 6])
      expect(transaction.credit_card_details.last_4).to eq(Braintree::Test::CreditCardNumbers::Visa[-4..-1])
      expect(transaction.credit_card_details.expiration_date).to eq("05/2010")
    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",
      )
      update_result = Braintree::CreditCard.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.credit_card).to eq(credit_card)
      updated_credit_card = update_result.credit_card
      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")
      expect(updated_credit_card.cardholder_name).to eq("New Holder")
    end

    it "validates presence of three_d_secure_version in 3ds pass thru params" 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",
      )
      result = Braintree::CreditCard.update(credit_card.token,
        :payment_method_nonce => Braintree::Test::Nonce::Transactable,
        :three_d_secure_pass_thru => {
          :eci_flag => "02",
          :cavv => "some_cavv",
          :xid => "some_xid",
          :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::ThreeDSecureVersionIsRequired)
      expect(error.message).to eq("ThreeDSecureVersion is required.")
    end

    it "accepts three_d_secure pass thru params in the request" 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",
      )
      result = Braintree::CreditCard.update(credit_card.token,
        :payment_method_nonce => Braintree::Test::Nonce::Transactable,
        :three_d_secure_pass_thru => {
          :eci_flag => "02",
          :cavv => "some_cavv",
          :three_d_secure_version=> "2.1.0",
          :xid => "some_xid",
          :authentication_response => "Y",
          :directory_response => "Y",
          :cavv_algorithm => "2",
          :ds_transaction_id => "some_ds_transaction_id",
        },
        :options => {:verify_card => true},
      )

      expect(result.success?).to eq(true)
    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!(
          :cardholder_name => "Original Holder",
          :customer_id => customer.id,
          :cvv => "123",
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "05/2020",
        )
        updated_result = Braintree::CreditCard.update(credit_card.token,
          :expiration_date => "05/2021",
          :options => {
            :verify_card => true,
            :skip_advanced_fraud_checking => false,
          },
        )

        expect(updated_result).to be_success
        verification = updated_result.credit_card.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!(
          :cardholder_name => "Original Holder",
          :customer_id => customer.id,
          :cvv => "123",
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "05/2020",
        )
        updated_result = Braintree::CreditCard.update(credit_card.token,
          :expiration_date => "05/2021",
          :options => {
            :verify_card => true,
            :skip_advanced_fraud_checking => true,
          },
        )

        expect(updated_result).to be_success
        verification = updated_result.credit_card.verification
        expect(verification.risk_data).to be_nil
      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::CreditCard.update(credit_card.token,
          :billing_address => {
            :region => "IL"
          },
        )
        expect(update_result.success?).to eq(true)
        updated_credit_card = update_result.credit_card
        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::CreditCard.update(credit_card.token,
          :billing_address => {
            :region => "IL",
            :options => {:update_existing => true}
          },
        )
        expect(update_result.success?).to eq(true)
        updated_credit_card = update_result.credit_card
        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::CreditCard.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.credit_card
        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::CreditCard.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.credit_card).to eq(credit_card)
      expect(update_result.credit_card.expiration_month).to eq("07")
      expect(update_result.credit_card.expiration_year).to eq("2011")
      expect(update_result.credit_card.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::CreditCard.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::CreditCardVerification::Status::ProcessorDeclined)
      expect(update_result.credit_card_verification.gateway_rejection_reason).to be_nil
    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::CreditCard.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.credit_card.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::CreditCard.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::CreditCard.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

    context "verification_account_type" do
      it "updates the credit card with account_type credit" do
        customer = Braintree::Customer.create!
        card = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::Hiper,
          :expiration_date => "06/2013",
        ).credit_card
        update_result = Braintree::CreditCard.update(
          card.token,
          :options => {
            :verify_card => true,
            :verification_account_type => "credit",
            :verification_merchant_account_id => SpecHelper::HiperBRLMerchantAccountId,
          },
        )
        expect(update_result).to be_success
      end

      it "updates the credit card with account_type debit" do
        customer = Braintree::Customer.create!
        card = Braintree::CreditCard.create(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::Hiper,
          :expiration_date => "06/2013",
        ).credit_card
        update_result = Braintree::CreditCard.update(
          card.token,
          :options => {
            :verify_card => true,
            :verification_account_type => "debit",
            :verification_merchant_account_id => SpecHelper::HiperBRLMerchantAccountId,
          },
        )
        expect(update_result).to be_success
      end
    end
  end

  describe "self.update!" do
    it "updates the credit card and returns true if valid" 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",
      )
      updated_credit_card = Braintree::CreditCard.update!(credit_card.token,
        :cardholder_name => "New Holder",
        :number => Braintree::Test::CreditCardNumbers::MasterCard,
        :expiration_date => "06/2013",
      )
      expect(updated_credit_card.token).to eq(credit_card.token)
      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")
      expect(updated_credit_card.cardholder_name).to eq("New Holder")
      expect(updated_credit_card.updated_at.between?(Time.now - 60, Time.now)).to eq(true)
    end

    it "raises a ValidationsFailed 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",
      )
      expect do
        Braintree::CreditCard.update!(credit_card.token,
          :cardholder_name => "New Holder",
          :number => Braintree::Test::CreditCardNumbers::MasterCard,
          :expiration_date => "invalid/date",
        )
      end.to raise_error(Braintree::ValidationsFailed)
    end
  end

  describe "self.delete" do
    it "deletes the credit card" 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 = result.credit_card
      expect(Braintree::CreditCard.delete(credit_card.token)).to eq(true)
      expect do
        Braintree::CreditCard.find(credit_card.token)
      end.to raise_error(Braintree::NotFoundError)
    end
  end

  describe "self.expired" do
    it "can iterate over all items, and make sure they are all expired" do
      customer = Braintree::Customer.all.first

      (110 - Braintree::CreditCard.expired.maximum_size).times do
        Braintree::CreditCard.create!(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "01/#{Time.now.year - 3}",
        )
      end

      collection = Braintree::CreditCard.expired
      expect(collection.maximum_size).to be > 100

      credit_card_ids = collection.map do |c|
        expect(c.expired?).to eq(true)
        c.token
      end.uniq.compact
      expect(credit_card_ids.size).to eq(collection.maximum_size)
    end
  end

  describe "self.expiring_between" do
    it "finds payment methods expiring between the given dates" do
      next_year = Time.now.year + 1
      collection = Braintree::CreditCard.expiring_between(Time.mktime(next_year, 1), Time.mktime(next_year, 12))
      expect(collection.maximum_size).to be > 0
      collection.all? { |pm| expect(pm.expired?).to eq(false) }
      collection.all? { |pm| expect(pm.expiration_year).to eq(next_year.to_s) }
    end

    it "can iterate over all items" do
      customer = Braintree::Customer.all.first

      (110 - Braintree::CreditCard.expiring_between(Time.mktime(2010, 1, 1), Time.mktime(2010,3, 1)).maximum_size).times do
        Braintree::CreditCard.create!(
          :customer_id => customer.id,
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "01/2010",
        )
      end

      collection = Braintree::CreditCard.expiring_between(Time.mktime(2010, 1, 1), Time.mktime(2010,3, 1))
      expect(collection.maximum_size).to be > 100

      credit_card_ids = collection.map { |c| c.token }.uniq.compact
      expect(credit_card_ids.size).to eq(collection.maximum_size)
    end
  end

  describe "self.find" 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::CreditCard.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::CreditCard.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

    it "raises a NotFoundError exception if payment method cannot be found" do
      expect do
        Braintree::CreditCard.find("invalid-token")
      end.to raise_error(Braintree::NotFoundError, 'payment method with token "invalid-token" not found')
    end

    it "raises a NotFoundError exception if searching for a PayPalAccount token" do
      customer = Braintree::Customer.create!
      paypal_account_token = "PAYPAL_ACCOUNT_TOKEN_#{rand(36**3).to_s(36)}"
      paypal_nonce = nonce_for_paypal_account({
          :consent_code => "PAYPAL_CONSENT_CODE",
          :token => paypal_account_token
      })

      Braintree::PaymentMethod.create({
        :payment_method_nonce => paypal_nonce,
        :customer_id => customer.id
      })

      expect do
        Braintree::CreditCard.find(paypal_account_token)
      end.to raise_error(Braintree::NotFoundError, "payment method with token \"#{paypal_account_token}\" not found")
    end
  end

  describe "self.from_nonce" do
    it "finds the payment method with the given nonce" do
      customer = Braintree::Customer.create!
      nonce = nonce_for_new_payment_method(
        :credit_card => {
          :number => "4111111111111111",
          :expiration_month => "11",
          :expiration_year => "2099",
        },
        :client_token_options => {:customer_id => customer.id},
      )

      credit_card = Braintree::CreditCard.from_nonce(nonce)
      customer = Braintree::Customer.find(customer.id)
      expect(credit_card).to eq(customer.credit_cards.first)
    end

    it "does not find a payment method for an unlocked nonce that points to a shared credit card" do
      nonce = nonce_for_new_payment_method(
        :credit_card => {
          :number => "4111111111111111",
          :expiration_month => "11",
          :expiration_year => "2099",
        },
      )
      expect do
        Braintree::CreditCard.from_nonce(nonce)
      end.to raise_error(Braintree::NotFoundError)
    end

    it "does not find the payment method for a consumednonce" do
      customer = Braintree::Customer.create!
      nonce = nonce_for_new_payment_method(
        :credit_card => {
          :number => "4111111111111111",
          :expiration_month => "11",
          :expiration_year => "2099",
        },
        :client_token_options => {:customer_id => customer.id},
      )

      Braintree::CreditCard.from_nonce(nonce)
      expect do
        Braintree::CreditCard.from_nonce(nonce)
      end.to raise_error(Braintree::NotFoundError, /consumed/)
    end
  end

  describe "self.sale" do
    it "creates a sale transaction using the credit card, returning a result object" do
      customer = Braintree::Customer.create!(
        :credit_card => {
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "05/2010"
        },
      )
      result = Braintree::CreditCard.sale(customer.credit_cards[0].token, :amount => "100.00")

      expect(result.success?).to eq(true)
      expect(result.transaction.amount).to eq(BigDecimal("100.00"))
      expect(result.transaction.type).to eq("sale")
      expect(result.transaction.customer_details.id).to eq(customer.id)
      expect(result.transaction.credit_card_details.token).to eq(customer.credit_cards[0].token)
      expect(result.transaction.credit_card_details.bin).to eq(Braintree::Test::CreditCardNumbers::Visa[0, 6])
      expect(result.transaction.credit_card_details.last_4).to eq(Braintree::Test::CreditCardNumbers::Visa[-4..-1])
      expect(result.transaction.credit_card_details.expiration_date).to eq("05/2010")
    end

    it "allows passing a cvv in addition to the token" do
      customer = Braintree::Customer.create!(
        :credit_card => {
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "05/2010"
        },
      )
      result = Braintree::CreditCard.sale(customer.credit_cards[0].token,
        :amount => "100.00",
        :credit_card => {
          :cvv => "301"
        },
      )

      expect(result.success?).to eq(true)
      expect(result.transaction.amount).to eq(BigDecimal("100.00"))
      expect(result.transaction.type).to eq("sale")
      expect(result.transaction.customer_details.id).to eq(customer.id)
      expect(result.transaction.credit_card_details.token).to eq(customer.credit_cards[0].token)
      expect(result.transaction.cvv_response_code).to eq("S")
    end
  end

  describe "self.sale!" do
    it "creates a sale transaction using the credit card, returning the transaction" do
      customer = Braintree::Customer.create!(
        :credit_card => {
          :number => Braintree::Test::CreditCardNumbers::Visa,
          :expiration_date => "05/2010"
        },
      )
      transaction = Braintree::CreditCard.sale!(customer.credit_cards[0].token, :amount => "100.00")
      expect(transaction.amount).to eq(BigDecimal("100.00"))
      expect(transaction.type).to eq("sale")
      expect(transaction.customer_details.id).to eq(customer.id)
      expect(transaction.credit_card_details.token).to eq(customer.credit_cards[0].token)
      expect(transaction.credit_card_details.bin).to eq(Braintree::Test::CreditCardNumbers::Visa[0, 6])
      expect(transaction.credit_card_details.last_4).to eq(Braintree::Test::CreditCardNumbers::Visa[-4..-1])
      expect(transaction.credit_card_details.expiration_date).to eq("05/2010")
    end
  end

  describe "nonce" do
    it "returns the credit card nonce" 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",
      )

      expect(credit_card.nonce).not_to be_nil
    end
  end

  describe "card on file network tokenization" do
    it "should find a network tokenized credit card" do
      credit_card = Braintree::CreditCard.find("network_tokenized_credit_card")
      expect(credit_card.is_network_tokenized?).to eq(true)
    end

    it "should find a non-network tokenized credit card" do
      customer = Braintree::Customer.create!
      credit_card = Braintree::CreditCard.create(
        :customer_id => customer.id,
        :number => Braintree::Test::CreditCardNumbers::Visa,
        :expiration_date => "05/2009",
      ).credit_card
      credit_card_vaulted = Braintree::CreditCard.find(credit_card.token)
      expect(credit_card_vaulted.is_network_tokenized?).to eq(false)
    end
  end
end