lib/cfita/codice_fiscale.rb in cfita-0.0.1 vs lib/cfita/codice_fiscale.rb in cfita-0.0.2
- old
+ new
@@ -1,23 +1,29 @@
# frozen_string_literal: true
require 'active_support/all'
+# require './belfiore.rb'
module Cfita
# Controllo codice fiscale italiano
class CodiceFiscale
- attr_reader :codice_fiscale, :data, :errors, :sesso
+ attr_reader :fiscal_code,
+ :sex,
+ :birth_place,
+ :birth_date,
+ :data,
+ :errors
- def initialize(codice_fiscale)
- @codice_fiscale = codice_fiscale.upcase.strip
+ def initialize(fiscal_code)
+ @fiscal_code = fiscal_code.upcase.strip
@data = {}
@errors = []
parse
end
def to_s
- codice_fiscale
+ fiscal_code
end
def valid?
errors.empty?
end
@@ -30,50 +36,114 @@
return if errors.any?
check_checksum
return if errors.any?
- check_sex
+ check_birth_date
+ # check_birth_place
end
def check_size
- size = @codice_fiscale.size
+ size = @fiscal_code.size
errors << "Lunghezza errata (#{size})" unless size == 16
end
def check_chars
- test = @codice_fiscale == @codice_fiscale.parameterize.upcase[/^[A-Z0-9]*$/]
+ test = @fiscal_code == @fiscal_code[/^[A-Z0-9]*$/]
errors << 'Caratteri non ammessi' unless test
end
def check_checksum
- errors << 'Checksum errato' if checksum != @codice_fiscale.last
+ errors << 'Checksum errato' if checksum != @fiscal_code.last
end
def check_sex
- case @codice_fiscale[9]
+ case @fiscal_code[9]
when /[0-3LMNP]/
- @data[:sesso] = 'M'
+ @data[:sex] = 'M'
when /[4-7QRST]/
- @data[:sesso] = 'F'
+ @data[:sex] = 'F'
else
@errors << 'Cifra decina giorno di nascita errata'
end
end
+ def check_birth_place
+ letter = @fiscal_code[11]
+ numbers =
+ @fiscal_code[12..14]
+ .split(//)
+ .map do |c|
+ i = OMOCODICI.index(c)
+ i ? i.to_s : c
+ end
+ .join
+ belfiore = letter + numbers
+
+ @birth_place = BELFIORE[belfiore]
+ @errors << "Codice istat #{belfiore} non trovato" unless @birth_place
+ end
+
+ MESI = 'ABCDEHLMPRST'.freeze
+
+ def check_birth_date
+ yy = cifre(6..7)
+ return if @errors.any?
+
+ day = cifre(9..10)
+ return if @errors.any?
+
+ @errors << 'Cifra decina giorno di nascita errata' if day > 71
+ return if @errors.any?
+
+ @data[:sex] = day > 40 ? 'F' : 'M'
+
+ month = MESI.index(@fiscal_code[8])
+ @errors << 'Mese errato' unless month
+ return if @errors.any?
+
+ @birth_date =
+ Date.new(yy2yyyy(yy), month + 1, day % 40) rescue nil
+
+ @errors << 'Data di nascita errata' unless @birth_date
+ return if @errors.any?
+
+ @data[:birth_date] = @birth_date
+ end
+
+ def yy2yyyy(yy)
+ Date.today.year -
+ (Date.today.year % 100 + 100 - yy ) % 100
+ end
+
+ def cifre(range)
+ result = 0
+ range.each do |position|
+ char = @fiscal_code[position]
+ value = CIFRE.index(char)
+ @errors << "Carattere '#{char}' errato in posizione #{position}" unless value
+ return nil unless value
+
+ result *= 10
+ result += value % 10
+ end
+ result
+ end
+
DISPARI = [
1, 0, 5, 7, 9,
13, 15, 17, 19, 21,
2, 4, 18, 20, 11,
3, 6, 8, 12, 14,
16, 10, 22, 25, 24, 23
].freeze
OMOCODICI = 'LMNPQRSTUV'
+ CIFRE = ('0123456789' + OMOCODICI).freeze
def checksum
tot = 0
- @codice_fiscale[0..14].bytes.first(15).each.with_index do |byte, i|
+ @fiscal_code[0..14].bytes.first(15).each.with_index do |byte, i|
next unless byte
byte -= byte < 65 ? 48 : 65
sign = (i % 2).zero?
tot += sign ? DISPARI[byte] : byte