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