Как проверить ИНН с помощью JavaScript в 2020 году?

Недавно я обнаружил, что в мою старую запись про проверку ИНН иногда заходят живые люди. Мало того, на неё ещё и ссылаются на сайтах с вопросами и ответами. И всё было бы хорошо, если бы тот код не содержал ошибок.

К сожалению, там не учитывался тот факт, что контрольная сумма может быть больше 9. В этом случае даже валидный ИНН проверку не пройдёт. Такое встречается нечасто, поэтому отловить этот баг было бы не очень легко.

Мучаясь угрызениями совести, я решил выложить актуальную версию проверки ИНН. Чтобы не вводить посетителей в заблуждение.

Максимально понятная функция

Функций получилось две. Первый вариант для тех, кто хочет понять, как нужно проверять ИНН в принципе. Там всё максимально просто делается, с кучей комментариев и с текстовыми сообщениями об ошибках в консоли (которые можно заменить на исключения, если кому-то так будет удобнее). Думаю, даже не зная 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 нужно заменить шаблонные строки на обычные. Возможно еще что-то не заработает. Я не тестировал =)

Ваш отзыв

logo