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