Как вывести значение из табличной части документа в форму списка?

Программист 1С v8.3 (Управляемые формы)
← На главную

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

Способ 1: Добавление реквизита в объект документа (Денормализация)

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

Разберем по шагам:

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

Пример кода для модуля объекта:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Если в документе есть несколько табличных частей (Товары и Услуги),
    // суммируем итоги по каждой из них
    ИтоговаяСумма = Товары.Итог("СуммаНДС") + Услуги.Итог("СуммаНДС");
    
    // Записываем результат в созданный нами реквизит
    СуммаНДСИтого = ИтоговаяСумма;
    
КонецПроцедуры

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

Способ 2: Использование произвольного запроса в динамическом списке

Рассмотрим более современный архитектурный подход. Если мы не хотим изменять структуру базы данных (добавлять реквизиты) и перепроводить документы, мы можем изменить сам запрос, который выбирает данные для списка.

Алгоритм действий:

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

Пример структуры такого запроса:


ВЫБРАТЬ
    ДокументРеализация.Ссылка КАК Ссылка,
    ДокументРеализация.Номер КАК Номер,
    ДокументРеализация.Дата КАК Дата,
    ЕСТЬNULL(ВложенныйЗапрос.СуммаНДС, 0) КАК СуммаНДС
ИЗ
    Документ.РеализацияТоваровУслуг КАК ДокументРеализация
        ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
            ТабЧасть.Ссылка КАК Ссылка,
            СУММА(ТабЧасть.СуммаНДС) КАК СуммаНДС
        ИЗ
            Документ.РеализацияТоваровУслуг.Товары КАК ТабЧасть
        СГРУППИРОВАТЬ ПО
            ТабЧасть.Ссылка) КАК ВложенныйЗапрос
        ПО ДокументРеализация.Ссылка = ВложенныйЗапрос.Ссылка

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

Способ 3: Обновление значения при активизации строки

Иногда требуется выводить сумму не в общую колонку, а в отдельное поле где-нибудь внизу или сбоку от списка, которое меняется при перемещении курсора. Для этого используется событие ПриАктивизацииСтроки таблицы формы.

Реализация:

В модуле формы списка создадим обработчик события и серверную функцию для получения данных.


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    
    ТекДанные = Элементы.Список.ТекущиеДанные;
    
    Если ТекДанные = Неопределено Тогда
        ОбщаяСуммаНДС = 0;
        Возврат;
    КонецЕсли;
    
    // Получаем сумму через серверный вызов
    ОбщаяСуммаНДС = ПолучитьСуммуНДСНаСервере(ТекДанные.Ссылка);
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьСуммуНДСНаСервере(Ссылка)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   СУММА(Товары.СуммаНДС) КАК Сумма
        |ИЗ
        |   Документ.РеализацияТоваровУслуг.Товары КАК Товары
        |ГДЕ
        |   Товары.Ссылка = &Ссылка";
    
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    Результат = Запрос.Выполнить();
    
    Если Результат.Пустой() Тогда
        Возврат 0;
    Иначе
        Выборка = Результат.Выбрать();
        Выборка.Следующий();
        Возврат Выборка.Сумма;
    КонецЕсли;
    
КонецФункции

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

Сравнение методов и рекомендации

Выбор метода зависит от ваших бизнес-задач:

  1. Если нужна фильтрация и сортировка: Однозначно выбираем Способ 1 (добавление реквизита). Это гарантирует максимальную производительность при работе со списком, так как база данных будет работать с простым индексированным полем, а не вычислять сумму "на лету".
  2. Если нельзя менять конфигурацию или нужно быстрое решение без перепроведения: Используем Способ 2 (произвольный запрос). Это гибко и не требует денормализации данных.
  3. Если сумма нужна только для справки: Подойдет Способ 3, но помните, что каждый "клик" по списку будет порождать серверный вызов, что может быть критично при медленном соединении.

Выясним причину, по которой пользователи часто предпочитают именно первый вариант: он позволяет использовать стандартные механизмы 1С для подведения итогов по колонке в подвале списка и исключает любые задержки при прокрутке больших списков документов.

← На главную