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