При разработке учетных механизмов на управляемых формах 1С часто возникает задача: при изменении реквизита (например, даты) открыть форму списка или форму выбора с установленным отбором, предоставить пользователю возможность выбрать нужную строку и перенести набор реквизитов обратно в форму документа. Разберем по шагам, как правильно передать отбор в форму, как вернуть структуру значений и как избежать типичных ошибок при работе с динамическими списками и датами.
В управляемом интерфейсе 1С открытие подчиненных окон и получение результата выбора строится на асинхронной модели с использованием объекта ОписаниеОповещения. Для передачи жестких условий фильтрации в динамический список формы выбора используется структура параметров с ключом ФиксированныеНастройки.
Проанализируем пример процедуры обработчика события ПриИзменении поля даты на форме документа. Для отбора документов или записей регистра за конкретные сутки необходимо установить границы интервала от НачалоДня до КонецДня:
&НаКлиенте
Процедура ДатаПриИзменении(Элемент)
// Формируем настройки компоновки данных для отбора
ПараметрыФормы = Новый Структура;
Настройки = Новый НастройкиКомпоновкиДанных;
// Граница: Дата >= НачалоДня
ЭлементОтбораДатаНачала = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораДатаНачала.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Дата");
ЭлементОтбораДатаНачала.ВидСравнения = ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
ЭлементОтбораДатаНачала.ПравоеЗначение = НачалоДня(Объект.Дата);
ЭлементОтбораДатаНачала.Использование = Истина;
// Граница: Дата <= КонецДня
ЭлементОтбораДатаОкончания = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораДатаОкончания.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Дата");
ЭлементОтбораДатаОкончания.ВидСравнения = ВидСравненияКомпоновкиДанных.МеньшеИлиРавно;
ЭлементОтбораДатаОкончания.ПравоеЗначение = КонецДня(Объект.Дата);
ЭлементОтбораДатаОкончания.Использование = Истина;
ПараметрыФормы.Вставить("ФиксированныеНастройки", Настройки);
// Создаем описание оповещения для обработки результата выбора
ОповещениеОЗакрытии = Новый ОписаниеОповещения("ПослеВыбораДокумента", ЭтаФорма);
ОткрытьФорму(
"Документ.ПериодическиеСписания.ФормаВыбора",
ПараметрыФормы,
ЭтаФорма,
,,,,
ОповещениеОЗакрытии
);
КонецПроцедуры
Когда пользователю требуется передать не просто ссылку на строку, а сразу набор связанных реквизитов (например, Получатель, Сумма, Кошелек), формируется структура данных. Возврат значения выполняется через вызов процедуры ОповеститьОВыборе или метода Закрыть с передачей сформированной структуры.
Посмотрим на пример обработчика события Выбор таблицы динамического списка в форме выбора:
&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
ВыбранноеЗначение = Новый Структура;
ВыбранноеЗначение.Вставить("Получатель", ТекущиеДанные.Получатель);
ВыбранноеЗначение.Вставить("Сумма", ТекущиеДанные.Сумма);
ВыбранноеЗначение.Вставить("Кошелек", ТекущиеДанные.Кошелек);
ОповеститьОВыборе(ВыбранноеЗначение);
КонецЕсли;
КонецПроцедуры
В модуле формы документа объявляется экспортная процедура, имя которой было передано в конструктор ОписаниеОповещения. В ней обязательно проверяется тип возвращенного значения, так как при закрытии формы крестиком или клавишей Esc в результат придет значение Неопределено.
&НаКлиенте
Процедура ПослеВыбораДокумента(Результат, ДополнительныеПараметры) Экспорт
Если ТипЗнч(Результат) = Тип("Структура") Тогда
Объект.Получатель = Результат.Получатель;
Объект.Сумма = Результат.Сумма;
Объект.КошелекОтправления = Результат.Кошелек;
КонецЕсли;
КонецПроцедуры
Если имена реквизитов структуры полностью совпадают с именами реквизитов объекта, можно применить стандартную функцию: ЗаполнитьЗначенияСвойств(Объект, Результат);.
Если логика учета требует отбирать записи не по точной дате, а по номеру дня месяца (например, все операции за 10-е число любого месяца), рассмотрим два подхода:
ГДЕ ДЕНЬ(Таблица.Период) = &ТекДень и передавать значение через параметр формы при открытии.ДЕНЬ() или МЕСЯЦ() в условии запроса не позволяет СУБД использовать индексы (запрос становится не sargable), что приводит к полному сканированию таблицы (Table Scan). Если объем данных велик, правильнее добавить в регистр или документ отдельный числовой реквизит ДеньМесяца (тип Число(2, 0)) с включенным индексированием и накладывать отбор напрямую по нему.При построении нестандартных запросов для динамических списков формы выбора разработчики иногда используют сложные соединения таблиц (например, для исключения уже обработанных записей). Если в динамическом списке используется соединение по условию неравенства (ПО Таблица1.УИД <> Таблица2.УИД), возникает декартово произведение, приводящее к ошибке дублирования ключей строк.
Выясним причину: динамический список читает данные порциями и требует уникальный ключ для каждой строки. Для исключения уже проведенных или обработанных записей следует использовать классическое левое соединение с проверкой на NULL:
ВЫБРАТЬ
План.Период КАК Период,
План.Регистратор КАК Регистратор,
План.Кошелек КАК Кошелек,
План.Получатель КАК Получатель,
План.Сумма КАК Сумма,
План.УИД КАК УИД
ИЗ
РегистрСведений.ПериодическийПриход КАК План
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.РегистрПоступления КАК Факт
ПО План.УИД = Факт.УИД
ГДЕ
Факт.УИД ЕСТЬ NULL
И ДЕНЬ(План.Период) = &ТекДень
Такой запрос однозначно идентифицирует строки, исключает появление дубликатов и корректно отображает только невыполненные запланированные операции.