При разработке сложных отчетов, механизмов распределения затрат или интеграционных шлюзов в среде «1С:Предприятие 8.3» программисты часто сталкиваются с необходимостью динамического создания колонок в объекте ТаблицаЗначений. Такая потребность возникает, когда структура таблицы (ее «шапка») заранее неизвестна и строится на основе данных информационной базы — например, по видам бюджетов, кодам классификации (КБК/КПС) или статьям финансирования.
Однако после успешного создания колонок разработчики часто сталкиваются с проблемой: стандартное обращение через точку (например, НоваяСтрока.ИмяКолонки) вызывает ошибку компиляции или выполнения, поскольку конфигуратор не знает о существовании этого свойства на этапе написания кода. В этой статье мы подробно разберем, как правильно записывать и читать данные из динамических колонок, рассмотрим типичные критические ошибки при их именовании и изучим более элегантные архитектурные альтернативы.
Платформа «1С:Предприятие 8.3» предоставляет универсальный механизм обращения к свойствам объектов, коллекций и строк таблиц значений через квадратные скобки. Этот синтаксис позволяет передавать имя колонки в виде строкового выражения (строкового литерала или переменной).
Рассмотрим по шагам, как выглядит правильный цикл заполнения таблицы значений данными, когда имена колонок формируются динамически. Предположим, у нас есть исходная таблица или выборка запроса, на основе которой мы строим новую таблицу с уникальными колонками для каждого кода КБК.
Ниже представлен пример кода, демонстрирующий этот подход:
// 1. Создаем пустую таблицу значений
ТаблицаСтатей = Новый ТаблицаЗначений;
ТаблицаСтатей.Колонки.Добавить("КОСГУ", Новый ОписаниеТипов("СправочникСсылка.КлассификацияОперацийСектораГосударственногоУправления"));
// Настройка типа данных для числовых колонок
КЧ = Новый КвалификаторыЧисла(12, 2);
ОписаниеТиповЧ = Новый ОписаниеТипов("Число", , , КЧ);
// 2. Программное создание колонок на основе выборки данных
Для Каждого Стр Из ТЗИсходная Цикл
// Формируем уникальные имена колонок для каждого КБК
ИмяОПС = "ОПС_" + Стр.КБК.Код;
ИмяФФОМС = "ФФОМС_" + Стр.КБК.Код;
ИмяФСС = "ФСС_" + Стр.КБК.Код;
// Проверяем, чтобы колонки не добавились повторно
Если ТаблицаСтатей.Колонки.Найти(ИмяОПС) = Неопределено Тогда
ТаблицаСтатей.Колонки.Добавить(ИмяОПС, ОписаниеТиповЧ);
КонецЕсли;
Если ТаблицаСтатей.Колонки.Найти(ИмяФФОМС) = Неопределено Тогда
ТаблицаСтатей.Колонки.Добавить(ИмяФФОМС, ОписаниеТиповЧ);
КонецЕсли;
Если ТаблицаСтатей.Колонки.Найти(ИмяФСС) = Неопределено Тогда
ТаблицаСтатей.Колонки.Добавить(ИмяФСС, ОписаниеТиповЧ);
КонецЕсли;
КонецЦикла;
// 3. Заполнение созданной таблицы значений данными
Для Каждого СтрокаИсточника Из ТЗИсходная Цикл
// Добавляем новую строку в нашу результирующую таблицу
НоваяСтрока = ТаблицаСтатей.Добавить();
НоваяСтрока.КОСГУ = СтрокаИсточника.КОСГУ;
// Формируем строковое имя колонки, к которой нужно обратиться
ДинамическоеИмяКолонки = "ОПС_" + СтрокаИсточника.КБК.Код;
// Обращаемся к колонке через квадратные скобки и записываем значение
НоваяСтрока[ДинамическоеИмяКолонки] = СтрокаИсточника.СуммаОПС;
// Аналогично для других динамических колонок
НоваяСтрока["ФФОМС_" + СтрокаИсточника.КБК.Код] = СтрокаИсточника.СуммаФФОМС;
НоваяСтрока["ФСС_" + СтрокаИсточника.КБК.Код] = СтрокаИсточника.СуммаФСС;
КонецЦикла;
Использование конструкции НоваяСтрока[ИмяПеременнойСИменемКолонки] полностью решает проблему обращения к колонкам на платформе 1С 8.3.
При динамическом создании колонок разработчики часто допускают опасную ошибку, используя код элемента справочника (например, КБК или КПС) напрямую в качестве имени колонки без предварительной подготовки. Рассмотрим, почему это может привести к аварийному завершению работы программы.
Имя колонки в объекте ТаблицаЗначений должно строго соответствовать правилам написания идентификаторов в языке 1С. Это значит, что имя колонки:
Если код КБК в информационной базе выглядит как "182.1.03.01000.01.1000.110" или содержит дефисы, то попытка выполнить код ТаблицаСтатей.Колонки.Добавить("ОПС" + Стр.КБК.Код) вызовет критическую ошибку: «Недопустимое имя колонки».
Чтобы избежать этой уязвимости, мы должны выполнить предварительную подготовку и очистку имени. Разберем безопасный метод создания колонок:
// Функция очистки строки для использования в качестве идентификатора
ИмяКолонки = "ОПС_" + Стр.КБК.Код;
// Удаляем все недопустимые символы (точки, дефисы, пробелы)
ИмяКолонки = СтрЗаменить(ИмяКолонки, ".", "_");
ИмяКолонки = СтрЗаменить(ИмяКолонки, "-", "_");
ИмяКолонки = СтрЗаменить(ИмяКолонки, " ", "");
// Теперь имя гарантированно корректно для платформы
ТаблицаСтатей.Колонки.Добавить(ИмяКолонки, ОписаниеТиповЧ);
Если вам необходимо выводить пользователю красивые и оригинальные названия КБК (со всеми точками и дефисами), используйте третий параметр метода Добавить() — Заголовок. Заголовок колонки может содержать любые символы без ограничений:
// Имя делаем безопасным техническим идентификатором, а оригинальный код пишем в заголовок
ТехническоеИмя = "ОПС_" + СтрЗаменить(Стр.КБК.Код, ".", "_");
КрасивыйЗаголовок = "ОПС " + Стр.КБК.Код;
ТаблицаСтатей.Колонки.Добавить(ТехническоеИмя, ОписаниеТиповЧ, КрасивыйЗаголовок);
При заполнении табличной части или таблицы значений по сложным алгоритмам может возникнуть ситуация, когда для определенной строки исходных данных соответствующая колонка не была создана. Прямое обращение к отсутствующей колонке по имени вызовет ошибку времени выполнения.
Рекомендуется внедрять в код защитные проверки с использованием метода Найти() коллекции колонок:
ИмяКолонкиДляЗаписи = "ОПС_" + СтрЗаменить(СтрокаИсточника.КБК.Код, ".", "_");
// Проверяем, существует ли колонка в структуре таблицы значений
КолонкаСуществует = ТаблицаСтатей.Колонки.Найти(ИмяКолонкиДляЗаписи);
Если КолонкаСуществует <> Неопределено Тогда
// Запись безопасна, колонка гарантированно присутствует
НоваяСтрока[ИмяКолонкиДляЗаписи] = СтрокаИсточника.СуммаОПС;
Иначе
// Обработка исключительной ситуации или логирование ошибки
ЗаписьЖурналаРегистрации("ОшибкиЗаполнения", УровеньЖурналаРегистрации.Предупреждение, , ,
"Не найдена динамическая колонка: " + ИмяКолонкиДляЗаписи);
КонецЕсли;
Программное создание колонок в таблице значений, последующий обход строк и ручное распределение сумм — это трудоемкий процесс, который часто называют «велосипедом». В платформе 1С 8.3 есть мощный штатный инструмент, способный автоматически разворачивать строки в колонки (создавать кросс-таблицы) — это Система компоновки данных (СКД).
Если перед вами стоит задача разработать отчет или печатную форму, где по вертикали идут статьи расходов, а по горизонтали динамически выводятся статьи финансирования (или КБК), лучшим решением будет использование СКД.
Если вам нужно подключить такой отчет на базе СКД в качестве внешней печатной формы к документу (например, к документу «Отражение зарплаты в бухучете»), вам не нужно переписывать весь отчет в код. Согласно стандартам Библиотеки стандартных подсистем (БСП), вы можете зарегистрировать отчет как внешнюю обработку и программно вывести результат компоновки напрямую в табличный документ.
Проанализируем пример кода модуля внешней печатной формы, которая использует готовый макет СКД для формирования кросс-таблицы:
// Обязательная функция для регистрации печатной формы в БСП
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработкеВводныхДанных();
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиПечатнаяФорма();
ПараметрыРегистрации.Назначение.Добавить("Документ.ОтражениеЗарплатыВБухучетеБюджетныхУчреждений");
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = "Расчет взносов по КБК (внешний)";
НоваяКоманда.Идентификатор = "ПечатьВзносовСКД";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
НоваяКоманда.ВыводитьОповещение = Истина;
Возврат ПараметрыРегистрации;
КонецФункции
// Процедура, вызываемая БСП при нажатии пользователем кнопки печатной формы
Процедура Печать(МассивОбъектовНазначения, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
ПечатнаяФорма = ДополнительныеОтчетыИОбработки.СведенияОПечатнойФорме(КоллекцияПечатныхФорм, "ПечатьВзносовСКД");
Если ПечатнаяФорма <> Неопределено Тогда
ТабличныйДокумент = Новый ТабличныйДокумент;
// Получаем схему компоновки из макета обработки
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
// Передаем ссылку на печатаемый документ в параметры СКД
ПараметрСсылка = Настройки.ПараметрыДанных.Элементы.Найти("СсылкаНаДокумент");
Если ПараметрСсылка <> Неопределено Тогда
ПараметрСсылка.Значение = МассивОбъектовНазначения[0];
ПараметрСсылка.Использование = Истина;
КонецЕсли;
// Инициализируем компоновку и вывод данных
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ОбъектыПечати);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабличныйДокумент);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// Возвращаем сформированный табличный документ в БСП
ПечатнаяФорма.ТабличныйДокумент = ТабличныйДокумент;
ПечатнаяФорма.СинонимМакета = "Расчет взносов по КБК";
КонецЕсли;
КонецПроцедуры
При использовании СКД вам достаточно в структуре настроек отчета перетащить поле КБК в "Колонки", а поле СтатьяРасходов в "Строки". Платформа автоматически сгруппирует данные, сама создаст нужные колонки в табличном документе на лету и заполнит их пересечения суммами взносов. Это полностью исключает ручную рутину и снижает вероятность ошибок при доработке типовых конфигураций.