Как открыть форму выбора с отбором по дате и вернуть выбранные данные в документ в 1С 8.3

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

При разработке учетных механизмов на управляемых формах 1С часто возникает задача: при изменении реквизита (например, даты) открыть форму списка или форму выбора с установленным отбором, предоставить пользователю возможность выбрать нужную строку и перенести набор реквизитов обратно в форму документа. Разберем по шагам, как правильно передать отбор в форму, как вернуть структуру значений и как избежать типичных ошибок при работе с динамическими списками и датами.

Шаг 1. Формирование отбора и асинхронное открытие формы выбора

В управляемом интерфейсе 1С открытие подчиненных окон и получение результата выбора строится на асинхронной модели с использованием объекта ОписаниеОповещения. Для передачи жестких условий фильтрации в динамический список формы выбора используется структура параметров с ключом ФиксированныеНастройки.

Проанализируем пример процедуры обработчика события ПриИзменении поля даты на форме документа. Для отбора документов или записей регистра за конкретные сутки необходимо установить границы интервала от НачалоДня до КонецДня:


&НаКлиенте
Процедура ДатаПриИзменении(Элемент)
    // Формируем настройки компоновки данных для отбора
    ПараметрыФормы = Новый Структура;
    Настройки = Новый НастройкиКомпоновкиДанных;
    
    // Граница: Дата >= НачалоДня
    ЭлементОтбораДатаНачала = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементОтбораДатаНачала.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Дата");
    ЭлементОтбораДатаНачала.ВидСравнения = ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
    ЭлементОтбораДатаНачала.ПравоеЗначение = НачалоДня(Объект.Дата);
    ЭлементОтбораДатаНачала.Использование = Истина;
    
    // Граница: Дата <= КонецДня
    ЭлементОтбораДатаОкончания = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементОтбораДатаОкончания.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Дата");
    ЭлементОтбораДатаОкончания.ВидСравнения = ВидСравненияКомпоновкиДанных.МеньшеИлиРавно;
    ЭлементОтбораДатаОкончания.ПравоеЗначение = КонецДня(Объект.Дата);
    ЭлементОтбораДатаОкончания.Использование = Истина;
    
    ПараметрыФормы.Вставить("ФиксированныеНастройки", Настройки);
    
    // Создаем описание оповещения для обработки результата выбора
    ОповещениеОЗакрытии = Новый ОписаниеОповещения("ПослеВыбораДокумента", ЭтаФорма);
    
    ОткрытьФорму(
        "Документ.ПериодическиеСписания.ФормаВыбора",
        ПараметрыФормы,
        ЭтаФорма,
        ,,,,
        ОповещениеОЗакрытии
    );
КонецПроцедуры

Шаг 2. Возврат выбранных значений из формы выбора

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

Посмотрим на пример обработчика события Выбор таблицы динамического списка в форме выбора:


&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        ВыбранноеЗначение = Новый Структура;
        ВыбранноеЗначение.Вставить("Получатель", ТекущиеДанные.Получатель);
        ВыбранноеЗначение.Вставить("Сумма", ТекущиеДанные.Сумма);
        ВыбранноеЗначение.Вставить("Кошелек", ТекущиеДанные.Кошелек);
        
        ОповеститьОВыборе(ВыбранноеЗначение);
    КонецЕсли;
КонецПроцедуры

Шаг 3. Обработка полученного результата в форме документа

В модуле формы документа объявляется экспортная процедура, имя которой было передано в конструктор ОписаниеОповещения. В ней обязательно проверяется тип возвращенного значения, так как при закрытии формы крестиком или клавишей Esc в результат придет значение Неопределено.


&НаКлиенте
Процедура ПослеВыбораДокумента(Результат, ДополнительныеПараметры) Экспорт
    Если ТипЗнч(Результат) = Тип("Структура") Тогда
        Объект.Получатель = Результат.Получатель;
        Объект.Сумма = Результат.Сумма;
        Объект.КошелекОтправления = Результат.Кошелек;
    КонецЕсли;
КонецПроцедуры

Если имена реквизитов структуры полностью совпадают с именами реквизитов объекта, можно применить стандартную функцию: ЗаполнитьЗначенияСвойств(Объект, Результат);.

Особенности выборки данных по дню месяца и оптимизация запросов

Если логика учета требует отбирать записи не по точной дате, а по номеру дня месяца (например, все операции за 10-е число любого месяца), рассмотрим два подхода:

  1. Использование параметров динамического списка: в запросе динамического списка на форме выбора можно прописать условие ГДЕ ДЕНЬ(Таблица.Период) = &ТекДень и передавать значение через параметр формы при открытии.
  2. Оптимизация производительности: вызов функций ДЕНЬ() или МЕСЯЦ() в условии запроса не позволяет СУБД использовать индексы (запрос становится не sargable), что приводит к полному сканированию таблицы (Table Scan). Если объем данных велик, правильнее добавить в регистр или документ отдельный числовой реквизит ДеньМесяца (тип Число(2, 0)) с включенным индексированием и накладывать отбор напрямую по нему.

Устранение ошибки «Обнаружено дублирование ключевых значений»

При построении нестандартных запросов для динамических списков формы выбора разработчики иногда используют сложные соединения таблиц (например, для исключения уже обработанных записей). Если в динамическом списке используется соединение по условию неравенства (ПО Таблица1.УИД <> Таблица2.УИД), возникает декартово произведение, приводящее к ошибке дублирования ключей строк.

Выясним причину: динамический список читает данные порциями и требует уникальный ключ для каждой строки. Для исключения уже проведенных или обработанных записей следует использовать классическое левое соединение с проверкой на NULL:


ВЫБРАТЬ
    План.Период КАК Период,
    План.Регистратор КАК Регистратор,
    План.Кошелек КАК Кошелек,
    План.Получатель КАК Получатель,
    План.Сумма КАК Сумма,
    План.УИД КАК УИД
ИЗ
    РегистрСведений.ПериодическийПриход КАК План
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.РегистрПоступления КАК Факт
        ПО План.УИД = Факт.УИД
ГДЕ
    Факт.УИД ЕСТЬ NULL
    И ДЕНЬ(План.Период) = &ТекДень

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

← На главную