Как отобразить на форме движения из нескольких документов, если данные постоянно перезаписываются?

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

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

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


// Неправильный код, который перезаписывает данные
ИмяРеквизита = СтрокаРегистра.Имя + "НаборЗаписей";
НаборЗаписей = РеквизитФормыВЗначение(ИмяРеквизита);

// Устанавливаем отбор по конкретному документу
НаборЗаписей.Отбор.Регистратор.Установить(ДокументДвижений); 
НаборЗаписей.Прочитать();

// В этот момент в реквизит формы попадают записи ТОЛЬКО последнего документа
ЗначениеВРеквизитФормы(НаборЗаписей, ИмяРеквизита);

При выполнении этого кода в цикле для нескольких документов на форме останутся видимыми только движения последнего документа. Давайте выясним причину такого поведения и рассмотрим правильные подходы.

Почему данные перезаписываются: особенности объекта «НаборЗаписей»

Основная причина проблемы кроется в самом принципе работы объекта НаборЗаписей, когда он подчинен регистратору. Рассмотрим ключевые моменты:

  1. Жесткая привязка к регистратору. Когда вы используете отбор НаборЗаписей.Отбор.Регистратор.Установить(...), вы жестко связываете этот объект в памяти с одним конкретным документом. Объект НаборЗаписей физически не может содержать в себе одновременно записи, относящиеся к разным документам-регистраторам.
  2. Работа метода Прочитать(). Каждый вызов метода Прочитать() выполняет следующие действия: сначала он полностью очищает все записи, которые находились в объекте НаборЗаписей до этого, а затем загружает из базы данных новый набор записей, соответствующий установленному отбору. Таким образом, «дозаписать» данные в существующий набор этим методом невозможно — он всегда работает по принципу полной замены.

Вывод: Попытка загрузить в один и тот же объект НаборЗаписей движения от разных документов в цикле обречена на провал. Каждый новый вызов Прочитать() будет перезаписывать результат предыдущего. Для решения нашей задачи нужен другой инструмент.

Правильный подход: сбор данных в промежуточную коллекцию

Чтобы собрать и отобразить данные из нескольких источников, необходимо использовать промежуточное хранилище. В 1С для этих целей идеально подходит объект ТаблицаЗначений. Он позволяет гибко формировать структуру колонок и накапливать в себе строки с данными из любых источников.

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

  1. Подготовка реквизита формы.

    На форме необходимо создать реквизит с типом ТаблицаЗначений. В конфигураторе определите для этой таблицы колонки, которые соответствуют нужным вам полям из регистра (например, «СчетДт», «СчетКт», «Сумма», «Субконто1» и т.д.). Разместите этот реквизит на форме в виде элемента «Таблица».

  2. Написание кода для сбора данных.

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

    • Создайте новый объект НаборЗаписей для нужного регистра.
    • Установите отбор по текущему документу из цикла.
    • Вызовите метод Прочитать(), чтобы загрузить движения именно этого документа.
    • Организуйте внутренний цикл для обхода всех записей в прочитанном наборе (Для каждого Запись из НаборЗаписей Цикл).
    • Внутри этого цикла добавляйте новую строку в вашу ТаблицуЗначений на форме (МояТаблицаНаФорме.Добавить()) и заполняйте ее колонки данными из текущей записи набора.

Посмотрим на пример кода, реализующего этот алгоритм:


&НаСервере
Процедура СобратьДвиженияНаСервере()
    
    // Получаем нашу таблицу на форме. Предположим, ее имя "ДвиженияДокументов"
    ТаблицаДвижений = РеквизитФормыВЗначение("ДвиженияДокументов");
    ТаблицаДвижений.Очистить();
    
    // Предположим, у нас есть массив документов, по которым нужно собрать движения
    МассивДокументов = ПолучитьМассивСторнируемыхДокументов(); 
    
    // Цикл по документам-регистраторам
    Для каждого ДокументСсылка Из МассивДокументов Цикл
        
        // Для каждого документа создаем СВОЙ объект набора записей
        НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
        НаборЗаписей.Прочитать();
        
        // Обходим прочитанные записи и добавляем их в нашу таблицу
        Для каждого СтрокаДвижения Из НаборЗаписей Цикл
            НоваяСтрока = ТаблицаДвижений.Добавить();
            НоваяСтрока.СчетДт = СтрокаДвижения.СчетДт;
            НоваяСтрока.СчетКт = СтрокаДвижения.СчетКт;
            НоваяСтрока.Сумма = СтрокаДвижения.Сумма;
            // ... заполняем остальные колонки ...
            НоваяСтрока.Регистратор = ДокументСсылка; // Можно добавить колонку для наглядности
        КонецЦикла;
        
    КонецЦикла;
    
    // Возвращаем заполненную таблицу обратно в реквизит формы
    ЗначениеВРеквизитФормы(ТаблицаДвижений, "ДвиженияДокументов");
    
КонецПроцедуры

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

Типичные ошибки: работа с метаданными вместо данных

При попытках решить задачу в лоб новички часто допускают еще одну фундаментальную ошибку: путают объекты данных с объектами метаданных.

Рассмотрим ошибочный код:


// Неправильный код, который вызовет ошибки
Для каждого СтрокаРегистра Из Метаданные.РегистрыБухгалтерии Цикл
    // ...
    Если СтрокаРегистра.Имя = "Хозрасчетный" Тогда
        // Ошибка! Нельзя присваивать значения свойствам объекта метаданных.
        СтрокаРегистра.ЕстьРеквизит = Истина; 
        Продолжить;
    КонецЕсли;
    // ...
КонецЦикла;

В чем здесь ошибка? Коллекция Метаданные.РегистрыБухгалтерии содержит объекты, которые описывают структуру регистров в конфигурации (их имена, состав измерений, ресурсов, реквизитов), но не содержат самих данных (записей). Попытка присвоить значение свойству объекта метаданных (СтрокаРегистра.ЕстьРеквизит = Истина) приведет к ошибке, так как метаданные в режиме исполнения программы доступны только для чтения.

Еще один частый камень преткновения — переменная с именем Регистры, которую можно встретить в типовом коде. Важно понимать, что в платформе 1С нет глобальной переменной или встроенной коллекции с именем Регистры. В типовых конфигурациях это, как правило, локальная переменная (Массив, СписокЗначений или ТаблицаЗначений), которую разработчики заранее заполнили списком нужных регистров для дальнейшей обработки. Если вы копируете фрагмент кода с такой переменной, не найдя и не воспроизведя код ее инициализации, вы получите ошибку «Переменная не определена».

Итог: Для работы с данными используйте менеджеры регистров (например, РегистрыБухгалтерии.Хозрасчетный) и создаваемые ими объекты (НаборЗаписей), а не перебирайте коллекцию метаданных в надежде получить доступ к записям.

← На главную