cfgen
Version:
Calculates codice fiscale from input data
105 lines (87 loc) • 3.57 kB
JavaScript
var strings = require('./strings.js');
var assert = function (data, exceptionstring) {
if (data === undefined || data === null || data === false) {
throw exceptionstring;
}
}
var genders = {
male: 0,
female: 40
};
var checkGender = function(gender) {
var exists = false;
for (var key in genders) {
if (genders[key] === gender) {
exists = true;
}
}
return exists;
}
var mapLocation = function (location, map) {
// check if location is already a code
if (location.match(/[A-Z]\d{3}/)) {
return location;
}
assert(map, "Location requires mapping and no map supplied");
location = map[location];
assert(location, "Could not map location data");
return location;
}
var calculateCF = function (user, maps) {
maps = maps || {};
assert(user, "Missing user data");
assert(user.firstname, "Missing firstname");
assert(user.lastname, "Missing lastname");
assert(user.birthcountry, "Missing birthcountry");
assert(user.dateofbirth, "Missing dateofbirth");
assert(checkGender(user.gender), "Missing or invalid gender");
// if we are in IT, the birthcity is the location component of the codice,
// if we are not in IT, it is the country
var locationcomponent;
if (user.birthcountry.toUpperCase() === "IT") {
locationcomponent = mapLocation(user.birthcity, maps.cities);
} else {
locationcomponent = mapLocation(user.birthcountry, maps.countries);
}
var lastNameCode = getNameCode(user.lastname, false);
var firstNameCode = getNameCode(user.firstname, true);
var year = user.dateofbirth.getFullYear() % 100;
var month = ["A", "B", "C", "D", "E", "H", "L", "M", "P", "R", "S", "T"][user.dateofbirth.getMonth()];
var day = user.dateofbirth.getDate() + user.gender;
var baseCF = lastNameCode + firstNameCode + strings.padLeft(year, "0", 2) + month + strings.padLeft(day, "0", 2) + locationcomponent;
return baseCF + getCheckSum(baseCF);
}
var getNameCode = function(name, isFirstName) {
name = strings.sanitize(name);
var split = strings.separateConsonantsAndVowels(name);
// "for firstname: If the name has more than three consonants, the 2nd is skipped"
if (isFirstName && split.consonants.length > 3){
split.consonants = split.consonants.slice(0, 1) + split.consonants.slice(2, name.length);
}
name = split.consonants + split.vowels;
return (name + "XXX").slice(0, 3);
}
var getCheckSum = function(baseCF) {
var oddCharCodes = [ 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 ];
var sum = 0;
var asciiIndexA = 'A'.charCodeAt(0);
for (var i = 0; i < baseCF.Length; i++) {
var c = baseCF[i];
var digit = parseInt(c);
var lookupId = c.charCodeAt(0) - asciiIndexA;
// odd/even is reversed to wikipedia because i is 0-based and they are 1-based
switch (i % 2) {
case 0:
// for odd numbers -> lookup table
sum += !isNaN(digit) ? oddCharCodes[digit] : oddCharCodes[lookupId];
break;
case 1:
// for even numbers -> use directly
sum += !isNaN(digit) ? digit : lookupId;
break;
}
}
return String.fromCharCode((sum % 26) + asciiIndexA);
};
module.exports.calculateCF = calculateCF;
module.exports.genders = genders;