class CreditOfficer::CreditCard
ActiveModel compliant class that represents credit card information Use this to populate and validate credit card details
It is not recommended that you persist credit card information unless you absolutely must. Many payment processors proviider you with a mechanism to store this private information
@example
cc = CreditOfficer::CreditCard.new({ :number => "411111111111111", :provider_name => "visa", :name_on_card => "John Doe", :expiration_year => 2010, :expiration_month => 1 }).valid? => true cc.number = "" cc.valid? => false cc.errors.full_messages => ["Number can't be blank"]
Constants
- I18N_ERROR_SCOPE
- PROVIDERS_AND_FORMATS
- SWITCH_OR_SOLO_PROVIDERS
Attributes
- String
-
downcased name of the credit card provider
(see {PROVIDERS_AND_FORMATS} for a valid list
- String
-
the CVV/CVV2 value found on the back or front of cards depending on their brand
validation of this string can be turned off via class setting require_verification_value
- String
-
the CVV/CVV2 value found on the back or front of cards depending on their brand
validation of this string can be turned off via class setting require_verification_value
- Integer
-
the integer based representation of the month when the credit card expires (1-12 e.g)
- Integer
-
the year when the credit card expires
@note paired with the month, this must be in the future for the credit card to be valid
- String
-
Solo or Switch Card attribute representing the issue number found on the card
- String
-
the name found on the front of the card
- String
-
the number found on card
- String
-
downcased name of the credit card provider
(see {PROVIDERS_AND_FORMATS} for a valid list
- Integer
-
Solo or Switch card attribute representing the start date found on the card
- Integer
-
Solo or Switch card attribute representing the start year found on the card
- String
-
the CVV/CVV2 value found on the back or front of cards depending on their brand
validation of this string can be turned off via class setting require_verification_value
Public Class Methods
@return [Array<String>] list of providers @note defaults to {PROVIDERS_AND_FORMATS}.keys
# File lib/credit_officer/credit_card.rb, line 164 def self.supported_providers @supported_providers end
configure your list of supported providers @param Array<String> providers you wish to support (amex, visa, etc) (refer to {PROVIDERS_AND_FORMATS}) @note matches specified providers against the supported whitelist {PROVIDERS_AND_FORMATS}
# File lib/credit_officer/credit_card.rb, line 158 def self.supported_providers=(providers) @supported_providers = providers.collect{|i| i.downcase} & PROVIDERS_AND_FORMATS.keys end
checks the configuration setting require_verification_value to see if verification is required
# File lib/credit_officer/credit_card.rb, line 127 def self.verification_value_required? require_verification_value end
Protected Class Methods
# File lib/credit_officer/credit_card.rb, line 259 def self.supported_providers_and_formats #match supported providers against constant's whitelist valid_supported_providers = supported_providers & PROVIDERS_AND_FORMATS.keys supported_providers.inject(ActiveSupport::OrderedHash.new) do |ordered_hash, provider_name| ordered_hash[provider_name] = PROVIDERS_AND_FORMATS[provider_name] ordered_hash end end
Public Instance Methods
# File lib/credit_officer/credit_card.rb, line 175 def derive_provider_name self.class.supported_providers_and_formats.each do |name, format| if number =~ format self.provider_name = name return end end end
@return [CreditOfficer::MonthYearPair] month year pair that represents the expiration date
# File lib/credit_officer/credit_card.rb, line 132 def expiration_date CreditOfficer::MonthYearPair.new(:month => expiration_month, :year => expiration_year) end
# File lib/credit_officer/credit_card.rb, line 184 def masked_number if number.present? && number.size >= 4 "X" * (number.size - 4) + number[-4..-1] end end
sets the provider name @param [String] the provider name you wish to set sets the provider name to its downcased equivalent @example note the downcase
credit_card.provider_name = "VISA" => "visa"
# File lib/credit_officer/credit_card.rb, line 149 def provider_name=(provider) unless provider.nil? @provider_name = provider.downcase end end
@return [CreditOfficer::MonthYearPair] month year pair that represents the start date @note this applies to switch and solo cards only
# File lib/credit_officer/credit_card.rb, line 139 def start_date CreditOfficer::MonthYearPair.new(:month => start_month, :year => start_year) end
@return [Boolean] whether or not the provider name indicates the card is a switch or solo card
# File lib/credit_officer/credit_card.rb, line 171 def switch_or_solo? SWITCH_OR_SOLO_PROVIDERS.include?(provider_name) end
Protected Instance Methods
# File lib/credit_officer/credit_card.rb, line 255 def checksum_valid? LuhneyBin.validate(number) end
# File lib/credit_officer/credit_card.rb, line 198 def expiration_date_is_in_future if expiration_date.valid? && expiration_date.end_is_in_past? errors.add(:expiration_year, translate(:expired, :scope => I18N_ERROR_SCOPE, :default => "is expired")) end end
# File lib/credit_officer/credit_card.rb, line 207 def expiration_date_is_in_recent_future if expiration_date.valid? && expiration_date.exceeds_recent_future? errors.add(:expiration_year, translate(:exceeds_recent_future, :scope => I18N_ERROR_SCOPE, :default => "is not a valid year")) end end
# File lib/credit_officer/credit_card.rb, line 239 def issue_number_is_valid unless issue_number =~ /^\d{1,2}$/ errors.add(:issue_number, translate(:invalid_issue_number, :scope => I18N_ERROR_SCOPE, :default => "is not valid")) end end
# File lib/credit_officer/credit_card.rb, line 215 def number_is_valid if (provider_name.present? || self.class.automatically_derive_provider_name) && number.present? if self.class.supported_providers_and_formats[provider_name].nil? || !(number =~ self.class.supported_providers_and_formats[provider_name]) || !checksum_valid? errors.add(:number, translate(:invalid_format, :scope => I18N_ERROR_SCOPE, :default => "is not a valid card number")) end end end
# File lib/credit_officer/credit_card.rb, line 229 def provider_name_is_supported if !self.class.automatically_derive_provider_name && !self.class.supported_providers.include?(provider_name.try(:downcase)) errors.add(:provider_name, translate(:unsupported_provider, :scope => I18N_ERROR_SCOPE, :default => "is not supported")) end end
# File lib/credit_officer/credit_card.rb, line 191 def run_validations! derive_provider_name if self.class.automatically_derive_provider_name super end
# File lib/credit_officer/credit_card.rb, line 247 def start_date_is_in_the_past if start_date.valid? && start_date.start_is_in_future? errors.add(:start_year, translate(:futuristic_start_date, :scope => I18N_ERROR_SCOPE, :default => "is in the future")) end end