Как реализовать проверку дублей в справочнике и поиск связанных документов при записи элемента в 1С

Программист 1С v8.3 (Управляемые формы) 1С:Розница Управленческий учет Торговля и дистрибуция
← На главную

В процессе разработки в среде 1С:Предприятие 8.3 часто возникает задача контроля уникальности вводимых данных. Обычной настройки уникальности кода или наименования в конфигураторе не всегда достаточно, особенно если логика требует проверки использования этих данных в конкретных бизнес-процессах или документах, таких как Расчет себестоимости. Рассмотрим подробно, как реализовать механизм, который при попытке создания нового номера кузова проверит его наличие в базе и выведет список документов, где он уже фигурирует.

Выбор места реализации логики: Модуль объекта

Первым делом проанализируем, где именно должен исполняться код проверки. Наиболее правильным и практичным местом является Модуль объекта справочника НомераКузовов, а именно обработчик события ПередЗаписью. Проверка на уровне модуля объекта гарантирует, что контроль будет срабатывать всегда: и при ручном вводе пользователем через форму, и при программном создании элемента, и при загрузке из внешних источников.

Разберем основные параметры обработчика ПередЗаписью:

  1. Отказ — если мы установим это значение в Истина, запись объекта в базу данных будет отменена.
  2. РежимЗаписи — позволяет определить, записывается ли объект или удаляется.

Также крайне важно учитывать свойство ОбменДанными.Загрузка. Если в информационную базу загружаются данные из другой системы, дополнительные проверки могут помешать процессу, поэтому их принято пропускать.

Рассмотрим пример начальной структуры кода в модуле объекта:


Процедура ПередЗаписью(Отказ)
    
    // Если идет загрузка данных, проверку пропускаем
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Вызываем нашу функцию проверки
    ПроверитьНаличиеДублейИСсылок(Отказ);
    
КонецПроцедуры

Шаг 1. Поиск дубликата по наименованию в справочнике

Проанализируем ситуацию: пользователь вводит номер кузова в поле Наименование (в этом случае может быть полезен расширенный поиск объекта в базе 1С). Нам нужно выяснить, существует ли уже элемент с таким текстом. Для этого мы будем использовать объект Запрос. Это наиболее производительный способ получения данных из СУБД.

Важный нюанс: если мы просто будем искать по наименованию (отлаживать такие алгоритмы помогает совместимая консоль запросов), то при редактировании уже существующего элемента программа найдет «саму себя» и не даст сохранить изменения. Поэтому в условии запроса мы должны исключить текущую ссылку.

Посмотрим на пример текста запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	НомераКузовов.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.НомераКузовов КАК НомераКузовов
    |ГДЕ
    |	НомераКузовов.Наименование = &Наименование
    |	И НомераКузовов.Ссылка <> &ТекущаяСсылка";

Запрос.УстановитьПараметр("Наименование", ЭтотОбъект.Наименование);
Запрос.УстановитьПараметр("ТекущаяСсылка", ЭтотОбъект.Ссылка);

РезультатЗапроса = Запрос.Выполнить();

Если РезультатЗапроса.Пустой() возвращает Ложь, значит, в системе уже есть другой элемент с таким номером кузова. Теперь нам нужно выяснить, используется ли он в документах.

Шаг 2. Поиск использования номера кузова в документах «Расчет себестоимости»

Когда мы нашли ссылку на существующий дубль, нам необходимо проверить наличие этой ссылки в документах РасчетСебестоимости. Рассмотрим два подхода к решению этой задачи.

Вариант А: Прямой запрос к документам. Мы можем написать запрос к табличной части или реквизитам документа (в зависимости от того, где хранится «номер кузова»). Если в конфигурации Розница 2.2 номер кузова является реквизитом документа, запрос будет выглядеть так:


ЗапросДок = Новый Запрос;
ЗапросДок.Текст = 
    "ВЫБРАТЬ
    |	РасчетСебестоимости.Номер КАК НомерДокумента,
    |	РасчетСебестоимости.Дата КАК ДатаДокумента
    |ИЗ
    |	Документ.РасчетСебестоимости КАК РасчетСебестоимости
    |ГДЕ
    |	РасчетСебестоимости.НомерКузова = &СсылкаНаДубль";

ЗапросДок.УстановитьПараметр("СсылкаНаДубль", НайденаяСсылка);
ВыборкаДок = ЗапросДок.Выполнить().Выбрать();

Вариант Б: Использование универсального метода поиска ссылок. Платформа предоставляет мощный инструмент — метод НайтиСсылки(). Он позволяет найти упоминание объекта во всех таблицах базы данных (документах, регистрах, других справочниках). Это более надежно, так как не требует перечисления всех возможных документов вручную.

Рассмотрим, как работает этот метод:


МассивСсылок = Новый Массив;
МассивСсылок.Добавить(НайденаяСсылка);
ТаблицаСсылок = НайтиСсылки(МассивСсылок);

Для Каждого СтрокаСсылок Из ТаблицаСсылок Цикл
    // Проверяем, что ссылка найдена именно в документе РасчетСебестоимости
    Если ТипЗнч(СтрокаСсылок.Данные) = Тип("ДокументСсылка.РасчетСебестоимости") Тогда
        // Накапливаем номера документов для сообщения
    КонецЕсли;
КонецЦикла;

Шаг 3. Формирование сообщения пользователю

Выясним, как правильно информировать пользователя о проблеме. В современных конфигурациях на базе БСП (Библиотека стандартных подсистем), таких как Розница 2.2, для вывода предупреждений рекомендуется использовать объект СообщениеПользователю. Этот объект позволяет привязать текст ошибки к конкретному полю на форме (в нашем случае — к наименованию), что значительно повышает удобство интерфейса.

Проанализируем пример формирования итогового сообщения:


Если ЕстьДубли И ИмеетсяВДокументах Тогда
    ТекстСообщения = СтрШаблон("Такой номер кузова (%1) уже есть в справочнике и используется в документах 'Расчет себестоимости': %2", 
                                ЭтотОбъект.Наименование, СписокНомеровДокументов);
    
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = ТекстСообщения;
    Сообщение.Поле = "Наименование"; // Привязка к полю формы
    Сообщение.УстановитьДанные(ЭтотОбъект);
    Сообщение.Сообщить();
    
    Отказ = Истина; // Запрещаем запись
КонецЕсли;

Оптимизация производительности: Индексирование

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

Чтобы этого избежать, выполним следующие шаги в конфигураторе:

  1. Откроем справочник НомераКузовов.
  2. Перейдем на вкладку Данные.
  3. Для реквизита, по которому идет поиск (если это не стандартное наименование, а отдельный реквизит НомерКузова), установим свойство Индексировать в значение Индексировать.

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

Дополнительные возможности: Подсистема поиска дублей БСП

Поскольку Розница 2.2 построена на базе БСП, мы можем рассмотреть альтернативный путь без написания кода. В пользовательском режиме (раздел Администрирование — Обслуживание — Поиск и удаление дублей) можно настроить типовые правила поиска по совпадению наименований. Это полезно для периодической очистки базы, однако для оперативного запрета ввода дублей (в момент нажатия кнопки «Записать») все же лучше использовать программный метод в ПередЗаписью, который мы разобрали выше.

Подведем итог: для качественной реализации задачи мы объединяем возможности языка запросов 1С для быстрого поиска, методы платформы для анализа связей и объект СообщениеПользователю для корректного взаимодействия с интерфейсом. Такой подход является наиболее практичным и соответствует стандартам разработки фирмы «1С».

← На главную