При разработке сложных отчетов, обработок и механизмов распределения затрат или начислений программисты часто сталкиваются с необходимостью динамического построения таблиц. Типичный сценарий: нужно вывести список сотрудников, а в колонках отобразить все возможные виды расчетов (начисления и удержания), чтобы затем заполнить их суммами.
Однако при попытке добавить колонку, имя которой формируется на основе наименования предопределенного или пользовательского элемента (например, вида расчета «Оклад» или «Районный коэффициент»), система 1С выдает критическую ошибку: «Ошибка при вызове метода контекста (Добавить) ... по причине: Неверное имя колонки».
В этой статье мы подробно разберем, почему возникает эта ошибка, изучим правила именования программных объектов в платформе 1С и рассмотрим пошаговые сценарии правильного создания динамических таблиц на управляемых формах.
Главная ошибка начинающих разработчиков заключается в путанице между техническим именем колонки и её визуальным представлением для пользователя. Платформа 1С предъявляет жесткие требования к свойству Имя колонки таблицы значений. Имя колонки — это программный идентификатор, к которому разработчик будет обращаться в коде. Оно обязано соответствовать правилам именования переменных в языке 1С:
Попытка очистить наименование вида расчета простым методом СтрЗаменить(Выборка.Наименование, " ", "") обречена на провал. В реальной базе наименования могут содержать скобки (например, «Оклад (по дням)»), знаки процентов («Премия 10%») или дефисы. Любой из этих символов приведет к аварийному завершению работы кода.
Для создания надежного алгоритма нам необходимо разделить два понятия: техническое имя колонки (уникальное и понятное платформе) и заголовок колонки (то, что увидит пользователь на экране).
У метода Добавить() коллекции колонок таблицы значений есть три основных параметра: Имя, Тип и Заголовок. В качестве технического имени мы можем использовать уникальный идентификатор (GUID) объекта или сквозной индекс с безопасным префиксом, а в качестве заголовка — реальное наименование вида расчета со всеми пробелами и спецсимволами.
Рассмотрим пример генерации имен на основе GUID элементов плана видов расчета:
ТабЗначений = Новый ТаблицаЗначений;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Начисления.Ссылка КАК Ссылка,
| Начисления.Наименование КАК Наименование
|ИЗ
| ПланВидовРасчета.Начисления КАК Начисления";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Формируем безопасное техническое имя на основе GUID ссылки, убирая дефисы
УникальныйКод = СтрЗаменить(Строка(Выборка.Ссылка.УникальныйИдентификатор()), "-", "");
ИмяКолонки = "ВР_" + УникальныйКод;
// Добавляем колонку: Имя (техническое), Тип данных, Заголовок (пользовательский)
ТабЗначений.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Число"), Выборка.Наименование);
КонецЦикла;
При таком подходе платформа гарантированно создаст колонку с корректным системным именем, а в интерфейсе программы пользователь увидит красивое и понятное название начисления.
Если вам по каким-то причинам критически важно иметь осмысленные технические имена колонок в коде, мы можем написать специальную функцию-санитайзер. Она будет проверять каждый символ исходной строки и собирать валидный идентификатор 1С.
Проанализируем пример такой функции:
Функция ПолучитьВалидныйИдентификатор(ИсходнаяСтрока) Экспорт
РазрешенныеСимволы = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZабвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ_";
Цифры = "0123456789";
Результат = "";
Для Позиция = 1 По СтрДлина(ИсходнаяСтрока) Цикл
Символ = Сред(ИсходнаяСтрока, Позиция, 1);
Если Найти(РазрешенныеСимволы, Символ) > 0 Тогда
Результат = Результат + Символ;
ИначеЕсли Найти(Цифры, Символ) > 0 И Позиция > 1 Тогда
// Цифру добавляем в имя, только если она стоит не на первом месте
Результат = Результат + Символ;
КонецЕсли;
КонецЦикла;
// Если в результате очистки получилась пустая строка или имя начинается с цифры
Если ПустаяСтрока(Результат) Тогда
Результат = "Колонка_" + Формат(ТекущаяДата(), "ДФ=yyyyMMddhhmmss");
ИначеЕсли Найти(Цифры, Лев(Результат, 1)) > 0 Тогда
Результат = "ПВР_" + Результат;
КонецЕсли;
Возврат Результат;
КонецФункции
Используя эту функцию, мы можем безопасно добавлять колонки, формируя их имена из названий начислений:
ИмяКолонки = ПолучитьВалидныйИдентификатор(Выборка.Наименование);
// Проверяем на дублирование имен в таблице
Если ТабЗначений.Колонки.Найти(ИмяКолонки) = Неопределено Тогда
ТабЗначений.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Число"), Выборка.Наименование);
КонецЕсли;
Создать ТаблицаЗначений в оперативной памяти сервера — это лишь половина дела. Если вы попытаетесь напрямую передать динамически созданную таблицу в реквизит формы с помощью метода ЗначениеВРеквизитФормы(ТабЗначений, "Свод"), платформа вернет ошибку, если структура колонок реквизита на форме не совпадает со структурой таблицы в памяти.
На управляемых формах 1С структура данных должна быть жестко задекларирована. Чтобы динамически отобразить таблицу на экране, необходимо выполнить три обязательных шага в серверном контексте формы:
ИзменитьРеквизиты().ЗначениеВРеквизитФормы().Давайте подробно разберем по шагам готовый рабочий шаблон для вывода динамической таблицы на управляемую форму:
&НаСервере
Процедура СформироватьДинамическуюТаблицуНаФорме()
// Шаг 1. Готовим исходную таблицу значений в памяти
ТабЗначений = Новый ТаблицаЗначений;
ТабЗначений.Колонки.Добавить("Сотрудник", Новый ОписаниеТипов("СправочникСсылка.ФизическиеЛица"), "Сотрудник");
// Получаем виды расчетов для колонок
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка, Наименование ИЗ ПланВидовРасчета.Начисления");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ИмяКолонки = "ВР_" + СтрЗаменить(Строка(Выборка.Ссылка.УникальныйИдентификатор()), "-", "");
ТабЗначений.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Число"), Выборка.Наименование);
КонецЦикла;
// Шаг 2. Удаляем старые динамические колонки с формы, если они были созданы ранее
// Это важно для предотвращения дублирования при повторном нажатии кнопок
МассивУдаляемыхРеквизитов = Новый Массив;
Для каждого Реквизит Из ПолучитьРеквизиты("Свод") Цикл
Если Реквизит.Имя <> "Сотрудник" Тогда
МассивУдаляемыхРеквизитов.Добавить("Свод." + Реквизит.Имя);
// Удаляем визуальный элемент с формы
ЭлементКолонки = Элементы.Найти("Свод_" + Реквизит.Имя);
Если ЭлементКолонки <> Неопределено Тогда
Элементы.Удалить(ЭлементКолонки);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если МассивУдаляемыхРеквизитов.Количество() > 0 Тогда
ИзменитьРеквизиты(, МассивУдаляемыхРеквизитов);
КонецЕсли;
// Шаг 3. Добавляем новые реквизиты на форму
МассивНовыхРеквизитов = Новый Массив;
Для каждого Колонка Из ТабЗначений.Колонки Цикл
// Пропускаем статическую колонку "Сотрудник", если она уже задана в метаданных формы
Если Колонка.Имя = "Сотрудник" Тогда
Продолжить;
КонецЕсли;
НовыйРеквизит = Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения, "Свод", Колонка.Заголовок);
МассивНовыхРеквизитов.Добавить(НовыйРеквизит);
КонецЦикла;
ИзменитьРеквизиты(МассивНовыхРеквизитов);
// Шаг 4. Заполняем реквизит формы данными
ЗначениеВРеквизитФормы(ТабЗначений, "Свод");
// Шаг 5. Визуализируем колонки на форме
Для каждого Колонка Из ТабЗначений.Колонки Цикл
Если Колонка.Имя = "Сотрудник" Тогда
Продолжить;
КонецЕсли;
ИмяЭлементаКолонки = "Свод_" + Колонка.Имя;
НоваяКолонка = Элементы.Добавить(ИмяЭлементаКолонки, Тип("ПолеФормы"), Элементы.Свод);
НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
НоваяКолонка.ПутьКДанным = "Свод." + Колонка.Имя;
НоваяКолонка.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Авто;
КонецЦикла;
КонецПроцедуры
Этот код представляет собой законченное и универсальное решение для динамического вывода любых данных. Он автоматически очищает форму от старых колонок при каждом вызове процедуры и корректно перестраивает интерфейс под текущий набор видов расчета.
Программное создание колонок и изменение реквизитов формы — довольно трудоемкий процесс, который нагружает серверную часть приложения и усложняет отладку кода. Если вашей конечной задачей является вывод кросс-таблицы (где по строкам идут сотрудники, по колонкам — начисления, а на пересечении — суммы), 1С предоставляет мощный стандартный механизм, который делает это автоматически.
Речь идет о Системе компоновки данных (СКД). Мы можем создать схему компоновки программно или через конструктор макета, настроив структуру типа «Таблица»:
Сотрудник.ВидРасчета.Сумма.Платформа сама выполнит группировку данных, создаст необходимое количество колонок под каждый вид расчета, подпишет их реальными наименованиями и выведет готовый результат в табличный документ на форме. Этот метод полностью избавляет разработчика от написания кода по ручному управлению элементами формы и гарантирует отсутствие ошибок с неверными именами колонок.