gifts2017

Алгоритм проверки уникальности и корректности ИНН, КПП при записи контрагента для БП 1.6 и 2.0 через подписку на события

Опубликовал Сергей (DSatan) в раздел Программирование - Практика программирования

В УПП есть типовой механизм проверки контрагента на уникальность при записи.
В БП 2.0 такой типовой проверки нет, пришлось добавлять свою, к тому же логика УПП-шной проверки меня не совсем устраивает.

Предлагаю свой вариант алгоритма проверки ИНН и КПП при записи элемента справочника Контрагенты.

Ни на что не претендую, если инфа будет кому-то полезна, значит не зря потратил время :).
К тому же этот вопрос возникает с неизменной периодичностью на всех форумах.

Реализовано с помощью подписки на событие, что позволяет спокойно обновлять конфигурацию.

Приведенный ниже код проверяет корректность в ИНН и КПП на:
    - длина
    - недопустимые символы
    - уникальность ИНН+КПП (для юрлица) или уникальность ИНН (для физлица)
    - проверка корректности ИНН на контрольный разряд

P.S. это первая публикация, сильно не ругайте, если есть замечания - сообщите

обновлено 13.03.2012 : добавлена проверка на Отказ, ОбменДанными.Загрузка,  ЭтоГруппа (спасибо http://forum.infostart.ru/forum24/topic51955/message616590/#message616590)

В конфигурации БП реализовал следующим образом:

1) создал подписку на событие

Источник: СправочникОбъект.Контрагенты

Событие: ПередЗаписью

Обработчик: МойОбщийМодуль.ПередЗаписьюКонтрагента (где МойОбщийМодуль - собственный общий модуль, но можно при желании можно и в один из типовых засунуть)

2) собственно сам обработчик

//добавлено - 11/05/2010 (проверка на корректность и уникальность ИНН и КПП)
Процедура ПередЗаписьюКонтрагента(Источник, Отказ) Экспорт

    Если Отказ ИЛИ Источник.ОбменДанными.Загрузка ИЛИ Источник.ЭтоГруппа Тогда
        Возврат;
    КонецЕсли;

    Если
Источник.ЮрФизЛицо = Перечисления.ЮрФизЛицо.ФизЛицо Тогда
       
ЭтоФизлицо = Истина;
    Иначе
       
ЭтоФизлицо = Ложь;
    КонецЕсли;

   
// проверка ИНН на заполнение
   
ИНН = Источник.ИНН;
    Если
СтрДлина(ИНН) <> ?(ЭтоФизлицо, 12, 10) Тогда
       
СообщениеОНевозможностиЗаписи = "Неверное количество символов в реквизите ИНН!!!" + Символы.ПС
            + "Текущее количество символов: " + СтрДлина(ИНН) + Символы.ПС
            + "Требуемое количество символов для " + ?(ЭтоФизлицо, "Физлица: 12","Юрлица: 10");
       
ОбщегоНазначения.СообщитьОбОшибке(СообщениеОНевозможностиЗаписи);
       
Отказ = Истина;
        Возврат;
    КонецЕсли;

   
// проверка ИНН на недопустимые символы
   
Результат = Истина;
    Для
а = 1 По СтрДлина(ИНН) Цикл
        Если
Найти("0123456789", Сред(ИНН,а,1)) = 0 Тогда
           
НекорректныйСимвол = Сред(ИНН,а,1);
           
Результат = Ложь;
            Прервать;
        КонецЕсли;
    КонецЦикла;

    Если НЕ
Результат Тогда
        СообщениеОНевозможностиЗаписи = "Недопустимый символ в реквизите ИНН: <" + НекорректныйСимвол + "> !!!";
       
ОбщегоНазначения.СообщитьОбОшибке(СообщениеОНевозможностиЗаписи);
       
Отказ = Истина;
        Возврат;
    КонецЕсли;

   
// проверка ИНН на контрольный разряд

    Если НЕ РегламентированнаяОтчетность.ИННСоответствуетТребованиям(ИНН, ЮрФизЛицо) Тогда
        СообщениеОНевозможностиЗаписи = "ИНН задан неверно (не прошел проверку на контрольный разряд)!!!";
        ОбщегоНазначения.СообщитьОбОшибке(СообщениеОНевозможностиЗаписи);
       
Отказ = Истина;
        Возврат;
    КонецЕсли;

    Если НЕ
ЭтоФизлицо Тогда
   
// проверка КПП на заполнение
       
КПП = Источник.КПП;
        Если
СтрДлина(КПП) <> 9 Тогда
           
СообщениеОНевозможностиЗаписи = "Неверное количество символов в реквизите КПП!!!" + Символы.ПС
            + "Текущее количество символов: " + СтрДлина(КПП) + Символы.ПС
            + "Требуемое количество символов: 9";
           
ОбщегоНазначения.СообщитьОбОшибке(СообщениеОНевозможностиЗаписи);
           
Отказ = Истина;
            Возврат;
        КонецЕсли;

       
// проверка КПП на недопустимые символы
       
Результат = Истина;
        Для
а = 1 По СтрДлина(КПП) Цикл
            Если
Найти("0123456789", Сред(КПП,а,1)) = 0 Тогда
               
НекорректныйСимвол = Сред(КПП,а,1);
               
Результат = Ложь;
                Прервать;
            КонецЕсли;
        КонецЦикла;

        Если НЕ
Результат Тогда
            СообщениеОНевозможностиЗаписи = "Недопустимый символ в реквизите КПП: <" + НекорректныйСимвол + "> !!!";
           
ОбщегоНазначения.СообщитьОбОшибке(СообщениеОНевозможностиЗаписи);
           
Отказ = Истина;
            Возврат;
        КонецЕсли;
    КонецЕсли;

   
// поиск дубликатов в справочнике
   
Запрос = Новый Запрос();
   
Запрос.УстановитьПараметр("ТекущийИНН", ИНН);
   
Запрос.УстановитьПараметр("ТекущийКПП", КПП);
   
Запрос.УстановитьПараметр("Ссылка", Источник.Ссылка);

   
Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
    |    Контрагенты.Ссылка,
    |    ПРЕДСТАВЛЕНИЕ(Контрагенты.Ссылка) КАК ПредставлениеКонтрагента
    |ИЗ
    |    Справочник.Контрагенты КАК Контрагенты
    |ГДЕ
    |    НЕ Контрагенты.Ссылка = &Ссылка
    |    И Контрагенты.ИНН = &ТекущийИНН
    |   "
+ ?(ЭтоФизлицо, "", " И Контрагенты.КПП = &ТекущийКПП");

   
ВыборкаКонтрагентов = Запрос.Выполнить().Выбрать();

    Если
ВыборкаКонтрагентов.Количество() <> 0 Тогда
       
ВыборкаКонтрагентов.Следующий();
       
СообщениеОНевозможностиЗаписи = "Уже существует контрагент с таким ИНН" + ?(ЭтоФизлицо, "", " И КПП") + " (" + ВыборкаКонтрагентов.Ссылка.Код + " " + ВыборкаКонтрагентов.ПредставлениеКонтрагента + ") !!!" ;
       
ОбщегоНазначения.СообщитьОбОшибке(СообщениеОНевозможностиЗаписи);
       
Отказ = Истина;
        Возврат;
    КонецЕсли;

КонецПроцедуры
//финиш - 11/05/2010 (проверка на корректность и уникальность ИНН и КПП)

См. также

Подписаться Добавить вознаграждение

Комментарии

1. igor sarafanov (ms200999) 30.01.12 13:44
Напрашивается проверка по контрольному числу. :)
2. Сергей (DSatan) 30.01.12 15:48
(1) не спорю, можно добавить и такой контроль, например из http://infostart.ru/public/70687/
мне такая проверка не нужна, т.к. часто при создании контрагента-физлица отсутствует информация об ИНН, тогда пользователи используют в качестве ИНН СерияНомерПаспорта+"00"
3. Сергей (DSatan) 30.01.12 21:58
(1) в типовой конфе БП оказывается уже есть функция проверки на контрольное число, добавил сюда эту проверку, спасибо за полезное замечание
4. Димон * (DDos76) 11.02.12 09:17
Спасибо за готовый код! Иногда просто бывает некогда писать и думать - а тут скопировал вставил и работает!
5. Артур Аюханов (artbear) 11.03.12 17:22
Сабж пока слабо готов к реальной эксплуатации
1. Нет проверки на ОбменДанными.Загрузка
2. ИМХО в подобных обработчиках лучше сразу проверять Отказ. Если Истина, то ничего не делать, так будет производительнее для системы.
6. Сергей (DSatan) 13.03.12 08:37
(5) artbear - прав, спасибо за замечания, одна голова хорошо, а две лучше :)
в принципе этот алгоритм используется на практике уже 2 года, но для универсальности добавлю твои предложения
7. JLaikova (JLaikova) 09.09.13 10:35
8. Екатерина Тутубалина (kalaratra) 14.08.14 09:07
Спасибо огромное! Только сегодня пришла такая же задача) Не пришлось самой разбираться)))
9. Рамиль Баширов (bashirov.rs) 04.12.14 14:02
Проверка на значения типа "0000000000" или "1111111111" и т.д. будет? Возможно проверить по регионам ИНН (начинается ли ИНН с кода региона - 01, 02, ... 99) ?
10. Ильшат Мазитов (байт) 17.01.15 20:44
Автору спасибо, благодаря статье сделал все быстро.
11. Андрей Х (Nordkas) 29.01.15 21:53
Спасибо, я не много доработал и получилось очень достойно.
12. Dmitry Bas (b-dm) 19.02.15 18:14
Молодец! Проверка при записи правильное дело.
13. Егор Титов (wertyoz453) 30.09.15 10:42
Хороший вариант реализации, но для работы в нетиповых потребуется и сама функция:

// Проверяет соответствие ИНН требованиям
// Параметры:
//		ИНН - строка - проверяемый индивидуальный номер налогоплательщика,
//		ВладелецИНН - ПеречислениеСсылка.ЮрФизЛицо - тип владельца ИНН: физлицо или юрлицо
Функция ИННСоответствуетТребованиям(Знач ИНН, Знач ТипЛица) Экспорт

	ИНН = СокрЛП(ИНН);
	ДлинаИНН =  СтрДлина(ИНН);

	Если НЕ ОбщегоНазначения.ТолькоЦифрыВСтроке(ИНН) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если Метаданные.Перечисления.Найти("ЮрФизЛицо") = Неопределено Тогда
		ПроверяетсяИННФизЛица = ТипЛица;
	Иначе
		ПроверяетсяИННФизЛица = (ТипЛица = Истина ИЛИ ТипЛица = Перечисления.ЮрФизЛицо.ФизЛицо);
	КонецЕсли;
	
	Если ДлинаИНН = 10  И НЕ ПроверяетсяИННФизЛица Тогда

		КонтрольнаяСумма = 0;

		Для Н = 1 По 9 Цикл

			Если 	  Н = 1 Тогда
				Множитель = 2;
			ИначеЕсли Н = 2 Тогда
				Множитель = 4;
			ИначеЕсли Н = 3 Тогда
				Множитель = 10;
			ИначеЕсли Н = 4 Тогда
				Множитель = 3;
			ИначеЕсли Н = 5 Тогда
				Множитель = 5;
			ИначеЕсли Н = 6 Тогда
				Множитель = 9;
			ИначеЕсли Н = 7 Тогда
				Множитель = 4;
			ИначеЕсли Н = 8 Тогда
				Множитель = 6;
			ИначеЕсли Н = 9 Тогда
				Множитель = 8;
			КонецЕсли; 
			
			Цифра = Число(Сред(ИНН,Н,1));
			КонтрольнаяСумма = КонтрольнаяСумма + Цифра * Множитель;
			
		КонецЦикла; 
		
		КонтрольныйРазряд = (КонтрольнаяСумма %11) %10;
		
		Если КонтрольныйРазряд <> Число(Сред(ИНН,10,1)) Тогда
			Возврат Ложь;
		КонецЕсли; 
		
	ИначеЕсли ДлинаИНН =12 И ПроверяетсяИННФизЛица Тогда
		
		КонтрольнаяСумма11 = 0;
		КонтрольнаяСумма12 = 0;
		
		Для Н=1 По 11 Цикл
			
			// Расчет множителя для 11-го и 12-го разрядов
			Если Н = 1 Тогда
				Множитель11 = 7;
				Множитель12 = 3;
			ИначеЕсли Н = 2 Тогда
				Множитель11 = 2;
				Множитель12 = 7;
			ИначеЕсли Н = 3 Тогда
				Множитель11 = 4;
				Множитель12 = 2;
			ИначеЕсли Н = 4 Тогда
				Множитель11 = 10;
				Множитель12 = 4;
			ИначеЕсли Н = 5 Тогда
				Множитель11 = 3;
				Множитель12 = 10;
			ИначеЕсли Н = 6 Тогда
				Множитель11 = 5;
				Множитель12 = 3;
			ИначеЕсли Н = 7 Тогда
				Множитель11 = 9;
				Множитель12 = 5;
			ИначеЕсли Н = 8 Тогда
				Множитель11 = 4;
				Множитель12 = 9;
			ИначеЕсли Н = 9 Тогда
				Множитель11 = 6;
				Множитель12 = 4;
			ИначеЕсли Н = 10 Тогда
				Множитель11 = 8;
				Множитель12 = 6;
			ИначеЕсли Н = 11 Тогда
				Множитель11 = 0;
				Множитель12 = 8;
			КонецЕсли; 
			
			Цифра = Число(Сред(ИНН,Н,1));
			КонтрольнаяСумма11 = КонтрольнаяСумма11 + Цифра * Множитель11;
			КонтрольнаяСумма12 = КонтрольнаяСумма12 + Цифра * Множитель12;
			
		КонецЦикла; 
		
		КонтрольныйРазряд11 = (КонтрольнаяСумма11 %11) %10;
		КонтрольныйРазряд12 = (КонтрольнаяСумма12 %11) %10;
		
		Если КонтрольныйРазряд11 <> Число(Сред(ИНН,11,1))
			ИЛИ КонтрольныйРазряд12 <> Число(Сред(ИНН,12,1)) Тогда
			Возврат Ложь;
		КонецЕсли; 
		
	Иначе
		
		Возврат Ложь;
		
	КонецЕсли; 
	
	Возврат Истина;
	
КонецФункции
...Показать Скрыть





14. Максим Литвинов (maksa2005) 14.10.15 21:37
Чтобы не вводили вместо чисел буквы и цифры в ИНН и КПП для счастья луше добавить маску в ИНН - 999999999999 и КПП 999999999
serg1974; +1 Ответить
15. Максим Литвинов (maksa2005) 14.10.15 21:38
Не добавил проверку по ИП у которых стоит КПП.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа