Недавно я обнаружил, что в мою старую запись про проверку ИНН иногда заходят живые люди. Мало того, на неё ещё и ссылаются на сайтах с вопросами и ответами. И всё было бы хорошо, если бы тот код не устарел.
Мучаясь угрызениями совести, я решил выложить актуальную версию проверки ИНН. Чтобы не вводить посетителей в заблуждение.
Максимально понятная функция
Функций получилось две. Первый вариант для тех, кто хочет понять, как нужно проверять ИНН в принципе. Там всё максимально просто делается, с кучей комментариев и с текстовыми сообщениями об ошибках в консоли (которые можно заменить на исключения, если кому-то так будет удобнее). Думаю, даже не зная JavaScript несложно понять алгоритм.
/** Проверка ИНН юрлиц, физлиц и ИП
* @param {string} value - строка для проверки
* @return boolean
*/
function checkInn(value){
//первая цифра ИНН может быть нулём, поэтому он не может быть числом
if(typeof value !== 'string'){
console.error(`ИНН должен быть строкой. Получено: ${typeof value}`);
return false;
}
//ИНН юрлиц - 10 символов, ИП - 12 символов
if(value.length !== 10 && value.length !== 12){
console.error(`Некорректная длинна ИНН: ${value.length}`);
return false;
}
//преобразуем строку в массив цифр
const arNumbers = value.split('');
if(arNumbers.length === 0){
console.error('Не удалось разобрать строку в массив символов');
return false;
}
//проверим что у нас в массиве только цифры
for(let symbol of arNumbers){
if(isNaN(Number(symbol))){
console.error(`Некорректный символ "${symbol}" в ИНН`);
return false;
}
}
//формула для юрлиц и ИП отличается
if(arNumbers.length === 10){
//переменная для итоговой суммы
let checkSum;
//каждую цифру мы умножаем на свой коэффициент
//а потом получаем остаток от деления на 11 и на 10
checkSum = ((
2 * arNumbers[0] +
4 * arNumbers[1] +
10 * arNumbers[2] +
3 * arNumbers[3] +
5 * arNumbers[4] +
9 * arNumbers[5] +
4 * arNumbers[6] +
6 * arNumbers[7] +
8 * arNumbers[8]
) % 11 ) % 10;
//проверяем что десятый символ ИНН совпадает с контрольной суммой
if(checkSum === Number(arNumbers[9])){
return true;
}else{
console.error(
`Контрольная сумма не совпала с десятым символом ${checkSum} != ${arNumbers[9]}`
);
return false;
}
//код для ИП
}else if(arNumbers.length === 12){
//в этом случае будет две контрольные суммы
let checkSumOne, checkSumTwo;
checkSumOne = ((
7 * arNumbers[0] +
2 * arNumbers[1] +
4 * arNumbers[2] +
10 * arNumbers[3] +
3 * arNumbers[4] +
5 * arNumbers[5] +
9 * arNumbers[6] +
4 * arNumbers[7] +
6 * arNumbers[8] +
8 * arNumbers[9]
) % 11 ) % 10;
checkSumTwo = ((
3 * arNumbers[0] +
7 * arNumbers[1] +
2 * arNumbers[2] +
4 * arNumbers[3] +
10 * arNumbers[4] +
3 * arNumbers[5] +
5 * arNumbers[6] +
9 * arNumbers[7] +
4 * arNumbers[8] +
6 * arNumbers[9] +
8 * arNumbers[10]
) % 11 ) % 10;
//в этом случае мы проверяем 11 и 12 символы
if(checkSumOne === Number(arNumbers[10]) &&
checkSumTwo === Number(arNumbers[11]))
{
return true;
}else if(checkSumOne !== Number(arNumbers[10])){
console.error(
`Первая контрольная сумма не совпала
с одиннадцатым символом ${checkSumOne} != ${arNumbers[10]}`
);
return false;
}else if(checkSumTwo !== Number(arNumbers[11])){
console.error(
`Вторая контрольная сумма не совпала
с двенадцатым символом ${checkSumTwo} != ${arNumbers[11]}`
);
return false;
}
}
}
Компактная функция
Второй вариант – короткий. Эта функция проверяет ИНН точно так же, но без кучи комментариев и код скомпонован более компактно.
/** Короткая функция проверки ИНН юрлиц, физлиц и ИП
* @param {string} value - строка для проверки
* @return boolean
*/
function checkInnShort(value){
if(typeof value !== 'string' ||
(value.length !== 10 && value.length !== 12) ||
value.split('').some((symbol) => isNaN(Number(symbol)))
) return false;
if(value.length === 10){
return Number(value[9]) === (value.split('').slice(0, -1)
.reduce(
(summ, symbol, index) =>
[2, 4, 10, 3, 5, 9, 4, 6, 8][index] * Number(symbol) + summ,
0)
% 11) % 10;
}else if(value.length === 12){
let checkSumOne = (value.split('').slice(0, -2)
.reduce(
(summ, symbol, index) =>
[7, 2, 4, 10, 3, 5, 9, 4, 6, 8][index] * Number(symbol) + summ,
0)
% 11 ) % 10;
let checkSumTwo = (value.split('').slice(0, -1)
.reduce(
(summ, symbol, index) =>
[3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8][index] * Number(symbol) + summ,
0)
% 11 ) % 10;
return (checkSumOne === Number(value[10]) && checkSumTwo === Number(value[11]));
}
}
Какой выбрать – решать вам.
P.S.
Чтобы этот код заработал в IE нужно заменить шаблонные строки на обычные. Возможно еще что-то не заработает. Я не тестировал =)