class CreditCard < ActiveRecord::Base belongs_to :legal_entity validates_numericality_of :number, :only_integer => true validates_presence_of :number, :expiration_date, :card_type validates_uniqueness_of :number, :scope => 'account_id', :message => 'matches a credit card already on your account' belongs_to :account def validate errors.add("number", "is not a #{card_type} or is invalid") unless number_valid? && number_matches_type? end def self.card_types { 'Visa' => 'visa', 'MasterCard' => 'mastercard', 'Discover' => 'discover', 'American Express' => 'amex' } end def readable_card_type (@@card_types ||= self.class.card_types.invert)[card_type] end def digits @digits ||= number.gsub(/[^0-9]/, '') end def last_digits digits.sub(/^([0-9]+)([0-9]{4})$/) { '*' * $1.length + $2 } end protected def number_valid? total = 0 digits.reverse.scan(/(\d)(\d){0,1}/) do |ud,ad| (ad.to_i*2).to_s.each {|d| total = total + d.to_i} if ad total = total + ud.to_i end total % 10 != 0 end def number_matches_type? digit_length = digits.length case card_type when 'visa' [13,16].include?(digit_length) and number[0,1] == "4" when 'mastercard' digit_length == 16 and ("51" .. "55").include?(number[0,2]) when 'amex' digit_length == 15 and %w(34 37).include?(number[0,2]) when 'discover' digit_length == 16 and number[0,4] == "6011" end end end
You need to create an account or log in to post comments to this site.