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

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

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

Анализ проблемы со стандартной структурой Отбор

Рассмотрим, почему простая передача структуры отбора через параметры открытия формы часто приводит к неожиданным результатам. Когда мы открываем форму и передаем структуру:


ПараметрыФормы = Новый Структура;
Отбор = Новый Структура;
Отбор.Вставить("Дата", Объект.Дата);
ПараметрыФормы.Вставить("Отбор", Отбор);
ОткрытьФорму("Документ.ПериодическиеСписания.ФормаВыбора", ПараметрыФормы, ЭтаФорма);

Платформа 1С автоматически применяет этот параметр к динамическому списку формы выбора с видом сравнения Равно. Однако в реальной базе дата документа содержит время (например, 23.05.2017 14:35:10). Если реквизит формы содержит время 00:00:00 или отличается даже на секунду, отбор на точное равенство не вернет ни одного документа. Выясним, как наложить условие на весь интервал суток — от 00:00:00 до 23:59:59.

Решение 1. Передача интервального отбора через ФиксированныеНастройки (Рекомендуемый способ)

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

Разберем реализацию команды открытия формы в модуле формы документа:


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

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

  1. Отбор применяется автоматически ядром платформы при компоновке списка.
  2. Пользователь в открывшейся форме выбора не сможет случайно сбить или отключить этот отбор через стандартные настройки списка, так как он зафиксирован.
  3. Не требуется писать дополнительный код в событиях формы выбора.

Решение 2. Установка отбора в событии ПриСозданииНаСервере формы выбора

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

Посмотрим на код в форме документа:


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

Теперь разберем обработчик в модуле формы выбора. Настроим отбор динамического списка Список в событии ПриСозданииНаСервере:


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

Как правильно вернуть выбранное значение в документ

Рассмотрим частую ошибку начинающих разработчиков: попытку вручную считывать значения колонок из таблицы формы выбора через Элементы.Список.ТекущиеДанные и передавать структуру в процедуру Закрыть(). Это усложняет код и приводит к ошибкам при двойном клике или выборе через клавиатуру.

В платформе 1С правильный алгоритм выглядит следующим образом:

  1. Форма выбора открывается со стандартным режимом выбора (он включен по умолчанию для форм выбора).
  2. При выборе строки платформа автоматически возвращает ссылку на выбранный документ (или ключ записи).
  3. Вызывающая форма перехватывает результат либо через событие ОбработкаВыбора, либо через асинхронное ОписаниеОповещения.
  4. Заполнение реквизитов документа выполняется на сервере по полученной ссылке.

Посмотрим, как организовать получение данных через ОписаниеОповещения:


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

&НаКлиенте
Процедура ПослеВыбораДокумента(ВыбранноеЗначение, ДополнительныеПараметры) Экспорт
    
    Если ЗначениеЗаполнено(ВыбранноеЗначение) Тогда
        ЗаполнитьДокументПоВыбранному(ВыбранноеЗначение);
    КонецЕсли;
    
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьДокументПоВыбранному(СсылкаНаДокумент)
    
    // Считываем реквизиты объекта-образца и заполняем текущий документ
    ОбъектОбразец = СсылкаНаДокумент.ПолучитьОбъект();
    
    Объект.Получатель = ОбъектОбразец.Получатель;
    Объект.Сумма = ОбъектОбразец.Сумма;
    Объект.КошелекОтправления = ОбъектОбразец.КошелекОтправления;
    
КонецПроцедуры

Как избежать открытия пустой формы выбора

Если на выбранную дату в базе нет ни одного документа, открывать пустую форму выбора не имеет смысла. Оптимально перед открытием формы проверить наличие данных серверным запросом:


&НаСервереБезКонтекста
Функция ЕстьДокументыНаДату(ПроверяемаяДата)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |   ПериодическиеСписания.Ссылка КАК Ссылка
        |ИЗ
        |   Документ.ПериодическиеСписания КАК ПериодическиеСписания
        |ГДЕ
        |   ПериодическиеСписания.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
        |   И ПериодическиеСписания.Проведен = ИСТИНА";
        
    Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ПроверяемаяДата));
    Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ПроверяемаяДата));
    
    Возврат НЕ Запрос.Выполнить().Пустой();
    
КонецФункции

В обработчике команды вызываем проверку перед вызовом формы выбора:


&НаКлиенте
Процедура КомандаВыбрать(Команда)
    
    Если НЕ ЕстьДокументыНаДату(Объект.Дата) Тогда
        ПоказатьПредупреждение(, "На выбранную дату проведенных документов не обнаружено.");
        Возврат;
    КонецЕсли;
    
    // Далее код открытия формы выбора...
    
КонецПроцедуры

Такой подход делает интерфейс более отзывчивым, защищает пользователя от работы с пустыми окнами и уменьшает количество лишних клиент-серверных вызовов при инициализации форм.

← На главную