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