Module: ActiveMerchant::Billing::CreditCardMethods

Included in:
CreditCard
Defined in:
lib/active_merchant/billing/credit_card_methods.rb

Overview

Convenience methods that can be included into a custom Credit Card object, such as an ActiveRecord based Credit Card object.

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

CARD_COMPANY_DETECTORS =
{
  'visa'               => ->(num) { num =~ /^4\d{12}(\d{3})?(\d{3})?$/ },
  'master'             => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 6), MASTERCARD_RANGES) },
  'elo'                => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 6), ELO_RANGES) },
  'alelo'              => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 6), ALELO_RANGES) },
  'discover'           => ->(num) { num =~ /^(6011|65\d{2}|64[4-9]\d)\d{12,15}|(62\d{14,17})$/ },
  'american_express'   => ->(num) { num =~ /^3[47]\d{13}$/ },
  'naranja'            => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 6), NARANJA_RANGES) },
  'diners_club'        => ->(num) { num =~ /^3(0[0-5]|[68]\d)\d{11}$/ },
  'jcb'                => ->(num) { num =~ /^35(28|29|[3-8]\d)\d{12}$/ },
  'dankort'            => ->(num) { num =~ /^5019\d{12}$/ },
  'maestro'            => lambda { |num|
    (12..19).cover?(num&.size) && (
      in_bin_range?(num.slice(0, 6), MAESTRO_RANGES) ||
      MAESTRO_BINS.any? { |bin| num.slice(0, bin.size) == bin }
    )
  },
  'forbrugsforeningen' => ->(num) { num =~ /^600722\d{10}$/ },
  'sodexo'             => ->(num) { num =~ /^(606071|603389|606070|606069|606068|600818)\d{10}$/ },
  'vr'                 => ->(num) { num =~ /^(627416|637036)\d{10}$/ },
  'cabal'              => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 8), CABAL_RANGES) },
  'unionpay'           => ->(num) { (16..19).cover?(num&.size) && in_bin_range?(num.slice(0, 8), UNIONPAY_RANGES) },
  'carnet'             => lambda { |num|
    num&.size == 16 && (
      in_bin_range?(num.slice(0, 6), CARNET_RANGES) ||
      CARNET_BINS.any? { |bin| num.slice(0, bin.size) == bin }
    )
  }
}
ELECTRON_RANGES =
[
  [400115],
  (400837..400839),
  (412921..412923),
  [417935],
  (419740..419741),
  (419773..419775),
  [424519],
  (424962..424963),
  [437860],
  [444000],
  [459472],
  (484406..484411),
  (484413..484414),
  (484418..484418),
  (484428..484455),
  (491730..491759),
]
CARNET_RANGES =
[
  (506199..506499),
]
CARNET_BINS =
Set.new(
  [
    '286900', '502275', '606333', '627535', '636318', '636379', '639388',
    '639484', '639559', '50633601', '50633606', '58877274', '62753500',
    '60462203', '60462204', '588772'
  ]
)
MASTERCARD_RANGES =
[
  (222100..272099),
  (510000..559999),
]
MAESTRO_BINS =
Set.new(
  ['500033', '581149']
)
MAESTRO_RANGES =
[
  (561200..561269),
  (561271..561299),
  (561320..561356),
  (581700..581751),
  (581753..581800),
  (589998..591259),
  (591261..596770),
  (596772..598744),
  (598746..599999),
  (600297..600314),
  (600316..600335),
  (600337..600362),
  (600364..600382),
  (601232..601254),
  (601256..601276),
  (601640..601652),
  (601689..601700),
  (602011..602050),
  (639000..639099),
  (670000..679999),
]
ELO_RANGES =

dev.elo.com.br/apis/tabela-de-bins, download csv from left sidebar

[
  506707..506708, 506715..506715, 506718..506722, 506724..506724, 506726..506736, 506739..506739, 506741..506743,
  506745..506747, 506753..506753, 506774..506776, 506778..506778, 509000..509001, 509003..509003, 509007..509007,
  509020..509022, 509035..509035, 509039..509042, 509045..509045, 509048..509048, 509051..509071, 509073..509074,
  509077..509080, 509084..509084, 509091..509094, 509098..509098, 509100..509100, 509104..509104, 509106..509109,
  627780..627780, 636368..636368, 650031..650033, 650035..650045, 650047..650047, 650406..650410, 650434..650436,
  650439..650439, 650485..650504, 650506..650530, 650577..650580, 650582..650591, 650721..650727, 650901..650922,
  650928..650928, 650938..650939, 650946..650948, 650954..650955, 650962..650963, 650967..650967, 650971..650971,
  651652..651667, 651675..651678, 655000..655010, 655012..655015, 655051..655052, 655056..655057
]
ALELO_RANGES =

Alelo provides BIN ranges by e-mailing them out periodically. The BINs beginning with the digit 4 overlap with Visa’s range of valid card numbers. By placing the ‘alelo’ entry in CARD_COMPANY_DETECTORS below the ‘visa’ entry, we identify these cards as Visa. This works because transactions with such cards will run on Visa rails.

[
  402588..402588, 404347..404347, 405876..405876, 405882..405882, 405884..405884,
  405886..405886, 430471..430471, 438061..438061, 438064..438064, 470063..470066,
  496067..496067, 506699..506704, 506706..506706, 506713..506714, 506716..506716,
  506749..506750, 506752..506752, 506754..506756, 506758..506762, 506764..506767,
  506770..506771, 509015..509019, 509880..509882, 509884..509885, 509987..509992
]
CABAL_RANGES =
[
  60420100..60440099,
  58965700..58965799,
  60352200..60352299
]
NARANJA_RANGES =
[
  589562..589562
]
UNIONPAY_RANGES =

In addition to the BIN ranges listed here that all begin with 81, UnionPay cards include many ranges that start with 62. Prior to adding UnionPay, cards that start with 62 were all classified as Discover. Because UnionPay cards are able to run on Discover rails, this was kept the same.

[
  81000000..81099999, 81100000..81319999, 81320000..81519999, 81520000..81639999, 81640000..81719999
]

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.in_bin_range?(number, ranges) ⇒ Boolean

Returns:

  • (Boolean)


148
149
150
151
152
153
# File 'lib/active_merchant/billing/credit_card_methods.rb', line 148

def self.in_bin_range?(number, ranges)
  bin = number.to_i
  ranges.any? do |range|
    range.cover?(bin)
  end
end

.included(base) ⇒ Object



144
145
146
# File 'lib/active_merchant/billing/credit_card_methods.rb', line 144

def self.included(base)
  base.extend(ClassMethods)
end

Instance Method Details

#card_verification_value_length(brand) ⇒ Object



188
189
190
191
192
193
194
195
196
197
# File 'lib/active_merchant/billing/credit_card_methods.rb', line 188

def card_verification_value_length(brand)
  case brand
  when 'american_express'
    4
  when 'maestro'
    0
  else
    3
  end
end

#credit_card?Boolean

Returns:

  • (Boolean)


159
160
161
# File 'lib/active_merchant/billing/credit_card_methods.rb', line 159

def credit_card?
  true
end

#electron?Boolean

Returns if the card matches known Electron BINs

Returns:

  • (Boolean)


204
205
206
# File 'lib/active_merchant/billing/credit_card_methods.rb', line 204

def electron?
  self.class.electron?(number)
end

#valid_card_verification_value?(cvv, brand) ⇒ Boolean

Credit card providers have 3 digit verification values This isn’t standardised, these are called various names such as CVC, CVV, CID, CSC and more See: en.wikipedia.org/wiki/Card_security_code American Express is the exception with 4 digits

Below are links from the card providers with their requirements visa: usa.visa.com/personal/security/3-digit-security-code.jsp master: www.mastercard.com/ca/merchant/en/getstarted/Anatomy_MasterCard.html jcb: www.jcbcard.com/security/info.html diners_club: www.dinersclub.com/assets/DinersClub_card_ID_features.pdf discover: www.discover.com/credit-cards/help-center/glossary.html american_express: online.americanexpress.com/myca/fuidfyp/us/action?request_type=un_fuid&Face=en_US

Returns:

  • (Boolean)


184
185
186
# File 'lib/active_merchant/billing/credit_card_methods.rb', line 184

def valid_card_verification_value?(cvv, brand)
  cvv.to_s =~ /^\d{#{card_verification_value_length(brand)}}$/
end

#valid_expiry_year?(year) ⇒ Boolean

Returns:

  • (Boolean)


163
164
165
# File 'lib/active_merchant/billing/credit_card_methods.rb', line 163

def valid_expiry_year?(year)
  (Time.now.year..Time.now.year + 20).cover?(year.to_i)
end

#valid_issue_number?(number) ⇒ Boolean

Returns:

  • (Boolean)


199
200
201
# File 'lib/active_merchant/billing/credit_card_methods.rb', line 199

def valid_issue_number?(number)
  (number.to_s =~ /^\d{1,2}$/)
end

#valid_month?(month) ⇒ Boolean

Returns:

  • (Boolean)


155
156
157
# File 'lib/active_merchant/billing/credit_card_methods.rb', line 155

def valid_month?(month)
  (1..12).cover?(month.to_i)
end

#valid_start_year?(year) ⇒ Boolean

Returns:

  • (Boolean)


167
168
169
# File 'lib/active_merchant/billing/credit_card_methods.rb', line 167

def valid_start_year?(year)
  ((year.to_s =~ /^\d{4}$/) && (year.to_i > 1987))
end