NAME

    Validate::CodiceFiscale - Validate an Italian "Codice Fiscale"

VERSION

    This document describes Validate::CodiceFiscale version 0.003002.

SYNOPSIS

    One-liner:

       $ perl -MValidate::CodiceFiscale=r -er RSSMRA98S03B833G

    Module usage:

       use Validate::CodiceFiscale qw< assert_valid_cf is_valid_cf validate_cf >;
    
       my $valid   = 'RSSMRA98S03B833G';
       my $invalid = 'RSICRL99C51C967X';
    
       # the first does not warn, the second does warn
       eval { assert_valid_cf($valid);   1 } or warn "died: $@";
       eval { assert_valid_cf($invalid); 1 } or warn "died: $@";
    
       # plain boolean test, any error short-circuits
       if (is_valid_cf($cf)) { ... }
    
       # get everything that's wrong
       if (my $errors = validate_cf($invalid)) {
          say for $errors->@*; # array with error report, one line per error
       }
    
       # it's possible to pass additional validation options, like specific
       # data. All are optional, if present they're validate, otherwise
       # ignored.
       assert_valid_cf($cf,
          {
             data => {
                name => 'Foo',
                surname => 'Bar',
                sex => 'f',
                date => '1998-03-11',
                place => 'B833',
             }
          }
       );
    
       # the assertion short-circuits by default, failing at the first
       # error. It's possible to check everyting and get a longer error
       # message, in case.
       assert_valid_cf($cf, { all_errors => 1 });
    
       # it's also possible to wrap the error generation, by returning the
       # exception to throw
       assert_valid_cf($cf,
          {
             all_errors => 1,
             on_error => sub {
                my @errors = @_;
                return "number of errors: $n_errors\n";
             }
          }
       );
    
       # of course, it's possible to throw the exception directly
       use Ouch;
       assert_valid_cf($cf, { on_error => sub { ouch 400, $_[0] } });

DESCRIPTION

    This module performs partial validation of Italian Codice Fiscale,
    mainly at the syntactic level. For proper and legally acknowledged
    validation please refer to the official service by Agenzia delle
    Entrate at
    https://telematici.agenziaentrate.gov.it/VerificaCF/Scegli.do?parameter=verificaCf.

    At the basic level, it allows spotting common errors that might come
    from copying/typing the Codice Fiscale, e.g. typing a 0 (zero) instead
    of an uppercase o letter, or similar errors with other digits/letters.

    The validation can optionally take additional data regarding the name,
    surname, birth date, birth place, and sex to perform a more thorough
    validation based on the official rules. This part is subject to false
    validations (negative or positive) for the following reasons:

      * Places are generally validated against available data collected
      from ANPR <https://www.anagrafenazionale.interno.it/> and ISTAT
      <https://www.istat.it/>, but they might be lacking. Additionally,
      there is no attempt at matching similar names, or names that are
      valid but e.g. expressed in their original language.

      * The algorithm to generate the CodiceFiscale might lead to the same
      string for different people. This is accounted for by using a
      substitution of digits with letters, but only Agenzia delle Entrate
      can tell whether the specific person holds the specific variant of
      the code.

    In the end, it provides a reaasonable way of spotting negatives, but it
    might validate codes that would otherwise be considered invalid by the
    reference authority because there is nobody tied to the otherwise
    synctactically valid code.

INTERFACE

    There are four main functions for doing checks, each targeting a
    different style of use, plus an additional function that can be helpful
    for one-liners.

 assert_valid_cf

       assert_valid_cf($cf, %options);

    Check validity of the provided $cf and throw an exception if the check
    fails.

    By default, the exception is thrown:

      * using Carp's croak with a message containing a string joining all
      errors

      * as soon as one of the validation checks fails.

    Supported options:

    all_errors

      collect all errors to be fed into the exception, not only the first
      one.

    data

      pass additional data for validation, as a hash reference optionally
      containing keys name, surname, date, sex, and place.

    on_error

      wrap the exception generation with a sub reference used as a callback
      with the following signature:

         sub (@error_strings) { ... }

      The sub can throw the exception itself; otherwise, its return value
      will be used as the argument for die.

 decode_cf

       my $decoded = decode_cf($cf, %options);

    Perform a full validation and provides back a data structure with the
    parsed data and the outcome of all available tests. This is the most
    complete form of validation that can be performed by this module.

    Supported options:

    data

      pass additional data for validation, as a hash reference optionally
      containing keys name, surname, date, sex, and place.

    years_baseline

      the baseline year for disambiguating two-digits. As an example,
      people born in 1920 and people born in 2020 both have 20 as the year
      part in their respective codes, so this allows setting the right
      expectation. In lack of this parameter, whatever came last is
      selected (in the example above, 20 would be interpreted as 2020).

    The output data structure contains the following keys:

    errors

      pointing to an array reference with a list of validation errors (if
      any);

    portions

      pointing to a hash reference with the disassemble of the input data,
      if possible (it is always possible as long as the input length is 16
      characters).

    date

      as YYYY-MM-DD)

    place

      as string of characters

    sex

      as a single-letter character, either F or M

    year

    month

    day

      as integers.

    The decoded data can be useful to perform further validations, e.g. for
    validating the place name in cases that are not covered by this module
    (e.g. when expressed in a language different from Italian, etc.).

 is_valid_cf

       my $boolean = is_valid_cf($cf, %options);

    Check the validity; it short-circuits at the first error. Returns a
    boolean value.

    It's possible to pass an additional key/value pair with key data and a
    hash reference optionally containing keys name, surname, date, sex, and
    place.

 r

       $ perl -MValidate::CodiceFiscale=r -er RSSMRA98S03B833G

    The r function can be useful in one-liners to check one or more codes
    from the command line. By default, the r function will read input codes
    from @ARGV.

 validate_cf

       my $errors = validate_cf($cf, %options);

    Check the validity and return undef if no errors were encountered, or a
    reference to an array containing the list of errors otherwise.

    Supported options:

    all_errors

      collect all errors to be fed into the exception, not only the first
      one. This option defaults to a true value, to collect all errors;
      it's possible to pass a false value to short-circuit and exit at the
      first error.

    data

      pass additional data for validation, as a hash reference optionally
      containing keys name, surname, date, sex, and place.

    years_baseline

      the baseline year for disambiguating two-digits. As an example,
      people born in 1920 and people born in 2020 both have 20 as the year
      part in their respective codes, so this allows setting the right
      expectation. In lack of this parameter, whatever came last is
      selected (in the example above, 20 would be interpreted as 2020).

SEE ALSO

    String::CodiceFiscale is an alternative and precedent module to deal
    with Codice Fiscale. I'm a bit scared about using a class method error
    to collect validation errors, hence this module.

BUGS AND LIMITATIONS

    Minimum perl version 5.24.

    Report bugs through GitHub (patches welcome) at
    https://github.com/polettix/Validate-CodiceFiscale.

AUTHOR

    Flavio Poletti <flavio@polettix.it>

COPYRIGHT AND LICENSE

    This distribution is mainly composed of code, but it also includes data
    (in the __DATA__ section of the module) that is derived from publicly
    available data sources.

 Code

    Copyright 2023 by Flavio Poletti <flavio@polettix.it>

    Licensed under the Apache License, Version 2.0 (the "License"); you may
    not use this file except in compliance with the License. You may obtain
    a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    implied. See the License for the specific language governing
    permissions and limitations under the License.

 Data

    The data contained in the __DATA__ section of the main module is
    assembled from the following sources:

      * Archive of Italian codes for places, including periods of validity,
      from file ANPR_archivio_comuni.csv
      <https://www.anagrafenazionale.interno.it/wp-content/uploads/ANPR_archivio_comuni.csv>,
      available from Italian Ministero dell'Interno with license CC-BY 4.0
      <https://creativecommons.org/licenses/by/4.0/legalcode.it> (according
      to page Note legali
      <https://www.anagrafenazionale.interno.it/note-legali/> as of
      2023-08-06). The file is accessible from page Archivio storico dei
      comuni
      <https://www.anagrafenazionale.interno.it/area-tecnica/archivio-storico-dei-comuni/>.

      * Archive of codes for foreign places, from file Elenco codici e
      denominazioni delle unità territoriali estere
      <https://www.istat.it/it/files//2011/01/Elenco-codici-e-denominazioni-unita-territoriali-estere.zip>,
      available from ISTAT with license CC-BY 3.0
      <http://creativecommons.org/licenses/by/3.0/it/> (according to page
      Note legali: responsabilità e licenza
      <https://www.istat.it/it/note-legali> as of 2023-08-06). The file is
      accessible from page Codici delle unità territoriali estere
      <https://www.istat.it/it/archivio/6747>.

