Одной из наиболее частых задач при разработке в среде 1С является обеспечение уникальности данных. Особенно остро этот вопрос стоит для таких реквизитов, как ИНН, так как дублирование контрагентов приводит к серьезным ошибкам в бухгалтерском и налоговом учете. В этой статье мы подробно разберем, как правильно организовать проверку на одинаковые значения, рассмотрим типичные ошибки новичков и внедрим профессиональные методы защиты данных.
Первое, с чем нам необходимо определиться — где именно писать код. Часто начинающие разработчики пытаются реализовать проверку непосредственно в форме элемента. Однако это не совсем корректно. Давайте проанализируем ситуацию: если мы напишем код только в форме, проверка сработает только при ручном вводе пользователем. Если же данные будут загружаться программно (через COM-соединение, JSON, Excel или веб-сервисы), проверка в форме просто не запустится.
Поэтому мы рассмотрим наиболее надежный вариант — размещение кода в Модуле объекта в предопределенной процедуре ПередЗаписью. Этот метод гарантирует выполнение проверки при любых обстоятельствах, вне зависимости от способа записи объекта в базу данных.
Для того чтобы проверить, существует ли уже в базе контрагент с таким же ИНН, нам необходимо выполнить запрос к таблице базы данных. Давайте разберем по шагам, как это сделать правильно. Нам потребуется найти все записи, у которых ИНН совпадает с тем, который мы пытаемся записать.
Посмотрим на пример базового кода, который можно разместить в модуле объекта:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Если объект помечен на удаление, проверку можно пропустить
Если ПометкаУдаления Тогда
Возврат;
КонецЕсли;
// Проверяем, заполнен ли ИНН вообще
Если ПустаяСтрока(ИНН) Тогда
Возврат;
КонецЕсли;
// Выполняем поиск дублей
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Контрагенты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.ИНН = &ИНН";
Запрос.УстановитьПараметр("ИНН", ИНН);
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Контрагент с таким ИНН уже существует в базе! (Ссылка: " + Выборка.Ссылка + ")";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Поле = "ИНН";
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Если вы внимательно проанализируете приведенный выше код, вы заметите одну серьезную проблему. При попытке пересохранить уже существующего контрагента (например, если вы решили изменить его телефон или адрес), система найдет в базе эту же самую карточку и выдаст ошибку о дубле. В результате вы никогда не сможете отредактировать уже записанного контрагента.
Чтобы этого избежать, мы должны добавить в условие запроса исключение текущей ссылки. Давайте модифицируем наш запрос, используя параметр &Ссылка.
// Правильное условие в запросе
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Контрагенты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.ИНН = &ИНН
| И Контрагенты.Ссылка <> &Ссылка";
Запрос.УстановитьПараметр("ИНН", ИНН);
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Теперь система будет искать ИНН среди всех записей, кроме той, которую мы сейчас редактируем. Это обязательное правило для любых проверок на уникальность в 1С.
Проанализируем работу базы данных при выполнении такого запроса. Если в вашем справочнике десятки тысяч контрагентов, поиск по строковому полю ИНН без специальной подготовки может занимать значительное время. Каждый раз при сохранении карточки система будет вынуждена "перелистывать" всю таблицу.
Чтобы проверка работала мгновенно, выполните следующие шаги в Конфигураторе:
Контрагенты.ИНН.После этого СУБД создаст внутренний индекс, и поиск дубля будет происходить практически моментально, вне зависимости от размера базы.
Часто пользователи копируют ИНН из писем или сайтов вместе с невидимыми пробелами. Визуально ИНН выглядит как "7701234567", но в базе может сохраниться как " 7701234567 ". Для системы это разные строки.
Рассмотрим, как обезопасить себя от таких ситуаций. Мы рекомендуем использовать функцию СокрЛП() (Сократить Левые и Правые пробелы) перед началом проверки и непосредственно при записи. Также полезно помнить, что ИНН юридического лица состоит из 10 цифр, а физического лица или ИП — из 12. Вы можете добавить дополнительную проверку на длину строки, чтобы отсечь заведомо некорректные данные.
// Очистка значения перед проверкой
ЧистыйИНН = СокрЛП(ИНН);
// Пример простой проверки формата
ДлинаИНН = СтрДлина(ЧистыйИНН);
Если НЕ (ДлинаИНН = 10 Или ДлинаИНН = 12) Тогда
// Сообщить пользователю о некорректной длине
КонецЕсли;
Если вы работаете в современной конфигурации (например, 1С:Бухгалтерия 3.0 или ERP), то многие задачи по проверке контрагентов уже решены за вас. В БСП существуют готовые механизмы для проверки контрольного числа ИНН (алгоритм, который математически вычисляет валидность номера).
Вместо написания запроса вручную, мы можем обратиться к функциям общих модулей. Например, поиск дублей часто вынесен в специализированные модули проверки контрагентов. Проанализируйте состав вашей конфигурации на наличие модулей ПроверкаКонтрагентов или КонтрагентыСлужебный. Использование типовых функций позволит вам не "изобретать велосипед" и следовать стандартам разработки 1С.
В высоконагруженных системах, где одновременно работают сотни пользователей, может возникнуть ситуация "гонки данных". Представьте: два бухгалтера одновременно нажимают кнопку "Записать" в двух новых карточках с одинаковым ИНН. В момент проверки запросом ни один из них еще не записан в базу, поэтому оба пройдут проверку успешно. В итоге в базе появятся два одинаковых ИНН.
Для решения этой проблемы в профессиональной разработке используются Блокировки данных. Перед выполнением запроса мы должны заблокировать возможность создания записи с таким ИНН для других сессий.
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Контрагенты");
ЭлементБлокировки.УстановитьПараметр("ИНН", ЧистыйИНН);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
// Далее следует код запроса
Подведем итог. Правильная проверка на дубли — это не просто сравнение двух значений. Это комплекс мер, включающий правильный выбор места в коде (ПередЗаписью), использование эффективных запросов с исключением текущей ссылки, индексирование полей и предварительную очистку данных от лишних символов. Следуя этим правилам, вы обеспечите стабильную и быструю работу вашей системы.