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