Как добавить и оптимизировать вывод суммы из движений в динамическом списке документов «Требование-накладная» в 1С:Бухгалтерия 3.0?

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

В процессе разработки и кастомизации типовых решений, таких как 1С:Бухгалтерия предприятия 3.0, часто возникает необходимость дополнить стандартные формы списков документов дополнительной информацией, которой нет в реквизитах самого документа. Одной из наиболее популярных задач является вывод общей суммы документа непосредственно в списке, если эта сумма не хранится в «шапке» документа, а рассчитывается на основании его движений или табличной части.

В данной статье мы подробно разберем, как реализовать вывод суммы для документа Требование-накладная, используя возможности динамического списка, и как при этом не допустить критического снижения производительности системы. Мы проанализируем различные подходы — от редактирования запроса до использования специализированных обработчиков событий формы.

Метод 1. Использование произвольного запроса в динамическом списке

Основной механизм отображения данных в списках управляемых форм — это ДинамическийСписок. По умолчанию он считывает данные из основной таблицы (в нашем случае Документ.ТребованиеНакладная). Чтобы добавить расчетное поле, нам необходимо переключить список в режим произвольного запроса. Давайте разберем этот процесс по шагам.

  1. Откроем форму списка документа в конфигураторе или через расширение (что предпочтительнее для БП 3.0).
  2. Перейдем на закладку Реквизиты и найдем основной реквизит формы — Список.
  3. В окне свойств реквизита установим флаг Произвольный запрос.
  4. Нажмем на гиперссылку Открыть рядом с настройкой запроса.

Теперь рассмотрим, как составить запрос так, чтобы получить сумму из проводок. Нам необходимо выполнить левое соединение с регистром бухгалтерии Хозрасчетный (или виртуальной таблицей оборотов), так как Требование-накладная делает движения по счетам учета материалов (например, счет 10).

Проанализируем пример запроса, который позволяет получить итоговую сумму по каждому документу:


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

Важный нюанс: Обратите внимание, что мы используем ЛЕВОЕ СОЕДИНЕНИЕ. Это гарантирует, что в списке останутся даже те документы, которые еще не проведены и не имеют движений (для них сумма будет равна 0 благодаря функции ЕСТЬNULL).

Метод 2. Оптимизация производительности: Виртуальные таблицы vs Реальные таблицы

Как было отмечено в обсуждении, неправильное использование соединений в динамическом списке может привести к тому, что производительность «пробьет дно». Это происходит потому, что динамический список выполняет запрос порциями при каждом скроллинге или поиске. Если запрос тяжелый, пользователь почувствует существенные задержки.

Выясним причину замедления. Когда мы соединяемся с реальной таблицей регистра бухгалтерии без ограничений, СУБД приходится обрабатывать колоссальный объем данных. Чтобы оптимизировать работу, следует придерживаться следующих правил:

Разберем вариант с виртуальной таблицей оборотов, который работает быстрее:


ВЫБРАТЬ
    ДокументТН.Ссылка КАК Ссылка,
    ЕСТЬNULL(ХозрасчетныйОбороты.СуммаОборот, 0) КАК СуммаДокумента
ИЗ
    Документ.ТребованиеНакладная КАК ДокументТН
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Обороты(&НачалоПериода, &КонецПериода, , , , , , ) КАК ХозрасчетныйОбороты
        ПО ДокументТН.Ссылка = ХозрасчетныйОбороты.Регистратор

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

Метод 3. Обработчик «ПриПолученииДанныхНаСервере»

Если запрос в динамическом списке все же работает медленно или логика расчета суммы слишком сложна для языка запросов (например, нужно учитывать специфические налоговые корректировки), рассмотрим альтернативный метод — использование события ПриПолученииДанныхНаСервере.

Этот метод работает по принципу «ленивых вычислений»: расчет производится только для тех строк, которые в данный момент отображаются на экране пользователя (обычно это 20-40 строк).

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

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

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


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

КонецПроцедуры

Преимущество метода: База данных выполняет очень легкий запрос по конкретным индексам (ссылкам), что практически не нагружает сервер даже при миллионах записей в регистре.

Метод 4. Архитектурный подход: Избыточность данных

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

Рассмотрим, как это сделать правильно:

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

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

Заключение

Мы рассмотрели несколько способов решения задачи. Если база данных небольшая, произвольный запрос с левым соединением к виртуальной таблице оборотов будет самым быстрым в реализации решением. Для крупных баз с миллионами проводок рекомендуем использовать либо событие ПриПолученииДанныхНаСервере, либо добавление реквизита в шапку документа. Помните, что в современных версиях БП 3.0 работа с материалами часто перенесена в документ Расход материалов, поэтому предварительно проверьте, какой именно объект используется в вашей системе.

← На главную