Как добавить колонку в журнал документов из табличной части в обычных формах 1С?

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

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

В чем заключается проблема?

Проанализируем ситуацию логически: в журнале каждая строка соответствует одному документу. В табличной части одного документа может быть несколько строк с разными проектами. Возникает вопрос: как уместить данные из множества строк в одну ячейку? К тому же, архитектура обычных форм не позволяет напрямую связывать колонки списка с табличными частями без использования дополнительного кода.

Способ 1: Добавление реквизита в шапку документа

Первый и наиболее простой с точки зрения архитектуры способ — создание нового реквизита в шапке документа. Мы будем записывать в него значение проекта из первой строки табличной части (или сцепленную строку всех проектов) и выводить этот реквизит в журнал.

Рассмотрим по шагам реализацию данного метода:

  1. Создаем новый строковый реквизит документа (например, ПроектШапка).
  2. В модуле документа в обработчике ПередЗаписью прописываем логику его заполнения.
  3. Добавляем этот реквизит в графы журнала и выводим на форму.

Посмотрим на пример кода, который необходимо разместить в обработчике:


Если ИмяТабличнойЧасти.Количество() <> 0 Тогда
    ПроектШапка = ИмяТабличнойЧасти[0].Проект;
КонецЕсли;

Важное замечание: Для однострочных документов (или если проект заполняется без разбиения сумм) это вполне допустимое решение. Однако, если строк несколько, в шапку попадет только первый проект. Писать же в строковый реквизит все проекты через запятую можно, но это усложнит использование стандартных отборов по ссылке.

Способ 2: Динамический вывод через событие ПриПолученииДанных

Если изменять структуру метаданных (добавлять реквизиты) нежелательно, выведем данные программно. В обычных формах для оформления списков используются два события: ПриВыводеСтроки и ПриПолученииДанных. Разберем, почему следует использовать именно второе.

Событие ПриВыводеСтроки срабатывает индивидуально для каждой строки списка. Если делать запрос в нем, при прокрутке журнала платформа сгенерирует сотни микро-запросов, что приведет к сильным "тормозам". Событие ПриПолученииДанных обрабатывает сразу массив строк, видимых на экране, позволяя выполнить один общий запрос к базе данных.

Посмотрим на пример реализации данного алгоритма:


Процедура ЖурналДокументовСписокПриПолученииДанных(Элемент, ОформленияСтрок)
    МассивСсылок = Новый Массив; 
    Соответствие = Новый Соответствие;

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

    Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок); 
    Выборка = Запрос.Выполнить().Выбрать();

    // Заполняем ячейки
    Пока Выборка.Следующий() Цикл
        Оформление = Соответствие.Получить(Выборка.Ссылка);
        Если Оформление <> Неопределено Тогда
            Оформление.Ячейки.Проект.Текст = Выборка.Проект;
            // При необходимости можно задать оформление, например цвет
            Оформление.Ячейки.Проект.ЦветТекста = WebЦвета.Розовый;  
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Нюансы способа: В запросе используется условие В (&МассивСсылок) — это критически важно для работы с массивом. Если кассовый ордер содержит несколько проектов, условие НомерСтроки = 1 можно убрать, а в цикле обхода выборки конкатенировать значения проектов для одной ссылки. Дополнительно можно использовать клиентское кэширование результатов, чтобы избежать повторных запросов при прокрутке списка.

Проблема отбора: как фильтровать по виртуальной колонке?

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

В этом случае на помощь приходит штатный механизм платформы — Критерии отбора. Разберем по шагам его настройку:

  1. В дереве конфигурации создаем новый критерий отбора, например ДокументыПоПроекту.
  2. В свойстве Тип указываем тип ссылки справочника проектов.
  3. В состав критерия включаем реквизит Проект из табличных частей ПКО и РКО.

Это позволит пользователям осуществлять отбор документов по проекту без дублирования данных в шапку документа.

Как это работает в Управляемых формах?

В современных конфигурациях на платформе 1С 8.3 с использованием Управляемых форм (УФ) подобные задачи решаются значительно проще. В УФ основой списка выступает ДинамическийСписок. Достаточно включить в нем опцию произвольного запроса и соединить левым соединением (LEFT JOIN) таблицу документа с табличной частью. Колонки, добавленные таким образом, отлично поддерживают стандартные сортировки и отборы без необходимости писать программный код и использовать события вывода строк.

← На главную