Class: Plastic

Inherits:
Object
  • Object
show all
Defined in:
lib/plastic/track.rb,
lib/plastic/core.rb,
lib/plastic/version.rb,
lib/plastic/duck_type.rb,
lib/plastic/validations.rb

Overview

Defined Under Namespace

Modules: VERSION

Constant Summary collapse

BRANDS =
[:visa, :mastercard, :american_express, :discover, :jcb]
TRACK_1_PARSER =

Track 1, Format B

Start sentinel — one character (generally ‘%’) Format code=“B” — one character (alpha only) Primary account number (PAN) — up to 19 characters. Usually, but not always, matches the credit card number printed on the front of the card. Field Separator — one character (generally ‘^’) Name — two to 26 characters Field Separator — one character (generally ‘^’) Expiration date — four characters in the form YYMM. Service code — three characters Discretionary data — may include Pin Verification Key Indicator (PVKI, 1 character), PIN Verification Value (PVV, 4 characters), Card Verification Value or Card Verification Code (CVV or CVK, 3 characters) End sentinel — one character (generally ‘?’)

/
  \A                                      # Start of string
  %?                                      # Start sentinel
  [bB]                                    # Format code
  (\d{12,19}|\d{4}\ \d{6}\ \d{5})         # PAN
  \^                                      # Field separator
  (                                       # Name field
    (?=[^^]{2,26})                        # Lookahead assertion
    ([^\/]+)                              # Surname
    (?:\/?([^.]+)(?:\.?([^^]+))?)?        # Given name and title
  )                                       #
  \^                                      # Field separator
  (\d{4})                                 # Expiration
  (\d{3})                                 # Service code
  ([^?]*)                                 # Discretionary data
  \??                                     # End sentinel
  \z                                      # End of string
/x.freeze
TRACK_2_PARSER =

Track 2

Start sentinel — one character (generally ‘;’) Primary account number (PAN) — up to 19 characters. Usually, but not always, matches the credit card number printed on the front of the card. Separator — one char (generally ‘=’) Expiration date — four characters in the form YYMM. Service code — three characters Discretionary data — as in track one End sentinel — one character (generally ‘?’)

/\A;?(\d{12,19})\=(\d{4})(.{3})([^\?]*)\??\z/.freeze
DUCK_TYPE_INTERFACE =

ActiveMerchant::Billing::CreditCard

[
  [:number, :pan],
  [:first_name, :given_name],
  [:last_name, :surname],
  [:verification_value, :cvv2],
  [:security_code, :cvv2],
  [:expiration_date, :expiration],
  [:track1, :track_1],
  [:track2, :track_2],
]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes = {}) ⇒ Plastic

Returns a new instance of Plastic.



9
10
11
12
13
14
15
16
# File 'lib/plastic/core.rb', line 9

def initialize(attributes={})
  if attributes.kind_of? Hash
    self.update! attributes
    parse_tracks!
  else
    parse_track! attributes
  end
end

Instance Attribute Details

#cvv2Object

Returns the value of attribute cvv2.



6
7
8
# File 'lib/plastic/core.rb', line 6

def cvv2
  @cvv2
end

#expirationObject

Returns the value of attribute expiration.



4
5
6
# File 'lib/plastic/core.rb', line 4

def expiration
  @expiration
end

#given_nameObject

Returns the value of attribute given_name.



5
6
7
# File 'lib/plastic/core.rb', line 5

def given_name
  @given_name
end

#panObject

Returns the value of attribute pan.



4
5
6
# File 'lib/plastic/core.rb', line 4

def pan
  @pan
end

#service_codeObject

Returns the value of attribute service_code.



6
7
8
# File 'lib/plastic/core.rb', line 6

def service_code
  @service_code
end

#surnameObject

Returns the value of attribute surname.



5
6
7
# File 'lib/plastic/core.rb', line 5

def surname
  @surname
end

#titleObject

Returns the value of attribute title.



5
6
7
# File 'lib/plastic/core.rb', line 5

def title
  @title
end

#track_1Object

Returns the value of attribute track_1.



7
8
9
# File 'lib/plastic/core.rb', line 7

def track_1
  @track_1
end

#track_2Object

Returns the value of attribute track_2.



7
8
9
# File 'lib/plastic/core.rb', line 7

def track_2
  @track_2
end

#track_nameObject

Returns the value of attribute track_name.



5
6
7
# File 'lib/plastic/core.rb', line 5

def track_name
  @track_name
end

Class Method Details

.track_1_parserObject



46
47
48
# File 'lib/plastic/track.rb', line 46

def self.track_1_parser
  TRACK_1_PARSER
end

.track_2_parserObject



75
76
77
# File 'lib/plastic/track.rb', line 75

def self.track_2_parser
  TRACK_2_PARSER
end

Instance Method Details

#brandObject



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/plastic/core.rb', line 41

def brand
  case pan
  when /^4\d{15}$/        then :visa
  when /^5[1-5]\d{14}$/   then :mastercard
  when /^677189\d{10}$/   then :mastercard
  when /^6011\d{12}$/     then :discover
  when /^64[4-9]\d{13}$/  then :discover
  when /^65\d{14}$/       then :discover
  when /^3[47]\d{13}$/    then :american_express
  when /^352[8-9]\d{12}$/ then :jcb
  when /^35[3-8]\d{13}$/  then :jcb
  end
end

#expiration_monthObject



37
38
39
# File 'lib/plastic/core.rb', line 37

def expiration_month
  expiration_mm.to_i
end

#expiration_yearObject



33
34
35
# File 'lib/plastic/core.rb', line 33

def expiration_year
  DateTime.strptime(expiration_yy, "%y").year
end

#monthObject



24
25
26
# File 'lib/plastic/duck_type.rb', line 24

def month
  expiration ? "%02d" % expiration_month : nil
end

#nameObject



25
26
27
# File 'lib/plastic/core.rb', line 25

def name
  [title, given_name, surname].flatten.compact.join(" ").strip
end

#parse_track!(value) ⇒ Object



9
10
11
12
# File 'lib/plastic/track.rb', line 9

def parse_track!(value)
  parse_track_2! value
  parse_track_1! value
end

#parse_track_1!(value = nil) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/plastic/track.rb', line 50

def parse_track_1!(value=nil)
  value ||= track_1
  if matched = self.class.track_1_parser.match(value.to_s)
    self.pan = matched[1].delete(' ')
    self.track_name = matched[2]
    self.surname = matched[3]
    self.given_name = matched[4]
    self.title = matched[5]
    self.expiration = matched[6]
    self.service_code = matched[7]
  end
end

#parse_track_2!(value = nil) ⇒ Object



79
80
81
82
83
84
85
# File 'lib/plastic/track.rb', line 79

def parse_track_2!(value=nil)
  value ||= track_2
  if matched = self.class.track_2_parser.match(value.to_s)
    self.pan = matched[1]
    self.expiration = matched[2]
  end
end

#parse_tracks!Object



4
5
6
7
# File 'lib/plastic/track.rb', line 4

def parse_tracks!
  parse_track_2!
  parse_track_1!
end

#update!(attributes = {}) ⇒ Object



18
19
20
21
22
23
# File 'lib/plastic/core.rb', line 18

def update!(attributes={})
  attributes.each do |key, value|
    setter_method_name = :"#{key}="
    send(setter_method_name, value) if respond_to?(setter_method_name)
  end
end

#valid?Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/plastic/core.rb', line 55

def valid?
  value_is_present?(pan) && value_is_present?(expiration) && valid_pan? && valid_expiration?
end

#valid_expiration?Boolean

Returns:

  • (Boolean)


8
9
10
11
12
13
14
15
16
17
18
# File 'lib/plastic/validations.rb', line 8

def valid_expiration?
  return false unless valid_expiration_year? && valid_expiration_month?
  this = Time.now.utc
  if this.year == expiration_year
    (this.month..12).include?(expiration_month)
  elsif expiration_year > this.year
    true
  else
    false
  end
end

#valid_pan?Boolean

Returns:

  • (Boolean)


4
5
6
# File 'lib/plastic/validations.rb', line 4

def valid_pan?
  valid_pan_length? && valid_pan_checksum?
end

#yearObject



20
21
22
# File 'lib/plastic/duck_type.rb', line 20

def year
  expiration ? DateTime.new(expiration_year).strftime("%y") : nil
end