В процессе разработки в системе 1С:Предприятие 8.3 часто возникает задача отобразить данные из табличной части документа непосредственно в общем списке (журнале). Начинающие разработчики часто сталкиваются с тем, что стандартный механизм настройки «Граф» в журнале позволяет выбирать только реквизиты шапки. Это ограничение обусловлено самой структурой базы данных: между документом и его табличной частью существует связь «один ко многим», и платформа не может автоматически решить, какую именно строку из множества существующих нужно показать в одной ячейке журнала.
В данной статье мы подробно разберем, как обойти это ограничение, проанализируем различные методики — от изменения запроса динамического списка до архитектурных хитростей с дублированием данных, и выясним, какой метод лучше использовать в зависимости от объема вашей базы данных.
Если ваша конфигурация использует Управляемые формы, то работа журнала документов базируется на объекте ДинамическийСписок. По умолчанию он просто считывает данные из таблиц документов, но мы можем изменить это поведение.
Рассмотрим по шагам, как изменить запрос списка:
Список), который имеет тип ДинамическийСписок.Важное предостережение: если вы просто добавите левое соединение с табличной частью документа, то в журнале возникнет дублирование строк. Если в документе 10 строк в табличной части, то сам документ отобразится в списке 10 раз. Чтобы этого избежать, мы должны использовать агрегатные функции или группировку.
Проанализируем пример запроса, который выводит сумму или количество строк, не размножая при этом записи журнала:
ВЫБРАТЬ
ЖурналДокументов.Ссылка КАК Ссылка,
ЖурналДокументов.Дата КАК Дата,
ЖурналДокументов.Номер КАК Номер,
ЖурналДокументов.ТипЗначения КАК ТипЗначения,
(ВЫБРАТЬ МАКСИМУМ(ТЧ.Номенклатура)
ИЗ Документ.СписаниеТоваров.Товары КАК ТЧ
ГДЕ ТЧ.Ссылка = ЖурналДокументов.Ссылка) КАК ПерваяНоменклатура
ИЗ
ЖурналДокументов.Общий КАК ЖурналДокументов
В этом примере мы используем вложенный запрос для получения значения из табличной части. Это позволяет вывести, например, название первого товара из списка. Для изучения других практических способов расширения состава колонок списка подойдёт руководство по методам доработки динамических списков и добавлению полей.
Если вы работаете на современной версии платформы, разработчики 1С предоставили нам мощный инструмент — функцию СОЕДИНИТЬСТРОКИ. Она идеально подходит для решения задачи «вывести список всех товаров в одну колонку через запятую».
Разберем ситуацию: нам нужно в журнале видеть краткий состав документа. В конструкторе запроса динамического списка мы можем написать следующее выражение для нового поля:
ВЫБРАТЬ
Журнал.Ссылка,
СОЕДИНИТЬСТРОКИ(ТЧ.Номенклатура.Наименование, ", ") КАК СоставДокумента
ИЗ
ЖурналДокументов.НашЖурнал КАК Журнал
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Списание.Товары КАК ТЧ ПО ТЧ.Ссылка = Журнал.Ссылка
СГРУППИРОВАТЬ ПО
Журнал.Ссылка
Этот метод элегантен, так как не требует изменения структуры метаданных. Однако стоит помнить, что при большом количестве документов и строк в них, производительность при прокрутке списка может снизиться, так как СУБД придется выполнять сборку строк «на лету».
Как отмечалось в обсуждении на форуме, программное заполнение данных непосредственно в момент открытия журнала — путь к медленной работе системы. Проанализируем более надежный подход, который часто применяется в типовых конфигурациях (например, в 1С:ERP или УТ 11).
Суть метода заключается в хранении текстового представления табличной части в специальном реквизите шапки документа. Выполним следующие действия:
СоставТЧДляСписка (длина может быть неограниченной или, например, 250 символов).ПередЗаписью пропишем код для формирования этой строки.Рассмотрим пример кода для формирования такой строки:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Собираем наименования товаров в одну строку
ТекстСостава = "";
Для Каждого СтрокаТЧ Из Товары Цикл
ТекстСостава = ТекстСостава + ?(ПустаяСтрока(ТекстСостава), "", ", ") + СтрокаТЧ.Номенклатура.Наименование;
// Ограничим длину, чтобы не перегружать базу
Если СтрДлина(ТекстСостава) > 200 Тогда
ТекстСостава = Лев(ТекстСостава, 200) + "...";
Прервать;
КонецЕсли;
КонецЦикла;
ЭтотОбъект.СоставТЧДляСписка = ТекстСостава;
КонецПроцедуры
Теперь в Журнале документов на вкладке «Графы» мы просто создаем новую графу и связываем её с нашим новым реквизитом СоставТЧДляСписка из всех входящих документов. Плюс этого метода: мгновенная отрисовка списка и возможность полнотекстового поиска по содержимому табличных частей прямо в журнале.
Если задача стоит в том, чтобы пользователь просто видел содержимое документа без лишних кликов, не обязательно пытаться «втиснуть» всё в одну строку журнала. Рассмотрим вариант с созданием области просмотра.
На форме журнала под основной таблицей динамического списка можно разместить еще одну таблицу (тоже динамический список или просто таблицу значений). Настроим связь:
СписокТовары).ГДЕ Ссылка = &ТекущийДокумент.ПриАктивацииСтроки основного списка пишем код обновления:
&НаКлиенте
Процедура СписокПриАктивацииСтроки(Элемент)
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
// Передаем ссылку в параметры второго списка
СписокТовары.Параметры.УстановитьЗначениеПараметра("ТекущийДокумент", ТекущиеДанные.Ссылка);
КонецЕсли;
КонецПроцедуры
Этот подход считается наиболее профессиональным с точки зрения UX/UI (пользовательского интерфейса), так как журнал остается чистым и быстрым, а подробная информация всегда доступна в нижней части экрана при навигации по списку. В качестве готового интерфейса с такой компоновкой можно использовать универсальный журнал документов с одновременным просмотром реквизитов и табличных частей.
Подведем итог нашему анализу:
ОБЪЕДИНИТЬ ВСЕ реализуется штатными средствами без потери производительности.МАКСИМУМ.Выбор конкретного метода зависит от ваших технических требований, но помните главное правило 1С: данные в списках должны отображаться быстро, а сложные вычисления лучше проводить в момент записи документа, а не в момент его отображения в журнале.