Как реализовать контроль уникальности и избежать дублей при вводе документа на основании?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

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

Почему стандартная «ОбработкаЗаполнения» не подходит для диалогов?

Рассмотрим сначала стандартный механизм. Когда пользователь нажимает кнопку «Создать на основании», платформа создает новый объект в памяти и вызывает процедуру ОбработкаЗаполнения в модуле объекта. Проанализируем, почему этого недостаточно для нашей задачи:

  1. Серверный контекст: Процедура ОбработкаЗаполнения выполняется на сервере. В современных управляемых формах вызов интерактивных функций, таких как Вопрос() или Предупреждение(), напрямую из серверного кода запрещен и приведет к ошибке выполнения.
  2. Объект уже создан: Когда выполняется код заполнения, объект уже существует в оперативной памяти. Мы можем отказаться от заполнения реквизитов, но форма нового документа все равно будет инициализирована, что запутает пользователя.
  3. Ограниченность управления: Стандартная обработка не позволяет легко «переключиться» на открытие уже существующего документа вместо создания нового.

Поэтому правильным подходом является перенос логики проверки в команду (кнопку), которая инициирует создание документа. Разберем, как это реализовать.

Решение 1: Использование пользовательской кнопки на форме

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


Процедура КнопкаСоздатьНаОсновании(Кнопка)
    // 1. Ищем, не был ли документ создан ранее
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   АвансовыйОтчет.Ссылка КАК Ссылка
        |ИЗ
        |   Документ.АвансовыйОтчет КАК АвансовыйОтчет
        |ГДЕ
        |   АвансовыйОтчет.ДокументОснование = &ТекущаяСсылка
        |   И АвансовыйОтчет.ПометкаУдаления = ЛОЖЬ";
    
    Запрос.УстановитьПараметр("ТекущаяСсылка", Ссылка);
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Если Выборка.Следующий() Тогда
        // 2. Документ найден. Спрашиваем пользователя
        Режим = РежимДиалогаВопрос.ДаНет;
        Ответ = Вопрос("Документ уже имеется. Открыть существующий (Да) или заполнить заново (Нет)?", Режим, 0);
        
        Если Ответ = КодВозвратаДиалога.Да Тогда
            // Открываем существующий
            ПараметрыФормы = Новый Структура("Ключ", Выборка.Ссылка);
            ОткрытьФорму("Документ.АвансовыйОтчет.ФормаОбъекта", ПараметрыФормы);
            Возврат;
        Иначе
            // Пользователь хочет создать новый или перезаписать
            // Здесь можно либо создать новый, либо получить объект существующего для перезаписи
            ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
        КонецЕсли;
    Иначе
        // 3. Документа еще нет, создаем новый объект
        ДокОбъект = Документы.АвансовыйОтчет.СоздатьДокумент();
    КонецЕсли;

    // 4. Вызываем стандартный или кастомный механизм заполнения
    ДокОбъект.Заполнить(Ссылка);
    
    // 5. Показываем форму пользователю
    ФормаДокумента = ДокОбъект.ПолучитьФорму();
    ФормаДокумента.Открыть();
КонецПроцедуры

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

Решение 2: Особенности для Управляемого интерфейса (Такси)

В управляемых формах работа с диалогами происходит асинхронно. Рассмотрим, как изменится подход. Вместо функции Вопрос() мы должны использовать ПоказатьВопрос() с описанием оповещения.

Алгоритм будет выглядеть следующим образом:

  1. На клиенте проверяем наличие дубля (через внеконтекстный серверный вызов).
  2. Если дубль найден, вызываем ПоказатьВопрос.
  3. В процедуре обработки выбора (Callback) принимаем решение: открывать старый документ или программно создавать новый и передавать его форму клиенту.

Методическая ошибка: Проверка при записи

Как отмечалось в обсуждении, проверка дублей в процедуре ПередЗаписью является «жестким» методом. Представим ситуацию: пользователь потратил 20 минут на заполнение сложной спецификации в документе, нажал кнопку «Записать», и система выдала ошибку: «Такой документ уже есть, запись запрещена». Это крайне негативно сказывается на пользовательском опыте (UX).

Рассмотрим более дружелюбный подход:

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

Защита от «гонки данных» (параллельная работа)

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

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

Использование Регистров сведений для контроля

Если ваша конфигурация предполагает создание миллионов документов, поиск по реквизиту ДокументОснование может замедлиться. Опытные разработчики рекомендуют использовать вспомогательный Регистр сведений (например, «СвязиДокументов»).

Преимущества такого подхода:

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

← На главную