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,16}$/ },
  '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}$/ },
  'alia'               => ->(num) { num =~ /^(504997|505878|601030|601073|505874)\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(
  %w[
    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(
  %w[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)

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

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

.included(base) ⇒ Object


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

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

Instance Method Details

#card_verification_value_length(brand) ⇒ Object


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

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

#credit_card?Boolean

Returns:

  • (Boolean)

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

def credit_card?
  true
end

#electron?Boolean

Returns if the card matches known Electron BINs

Returns:

  • (Boolean)

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

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)

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

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

#valid_expiry_year?(year) ⇒ Boolean

Returns:

  • (Boolean)

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

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

#valid_issue_number?(number) ⇒ Boolean

Returns:

  • (Boolean)

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

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

#valid_month?(month) ⇒ Boolean

Returns:

  • (Boolean)

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

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

#valid_start_year?(year) ⇒ Boolean

Returns:

  • (Boolean)

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

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