TLDR: Нашел в типовой интересный код. По-моему это грубая ошибка и нарушение стандартов. Подробности ниже.
Процедура ПриПолученииПредопределенныхНаборовСвойств(Наборы) Экспорт
Набор = Наборы.Строки.Добавить();
Набор.Имя = "Справочник_ВнешниеПользователи";
Набор.Идентификатор = Новый УникальныйИдентификатор("d9c30d48-a72a-498a-9faa-c078bf652776");
Набор.Используется = ПолучитьФункциональнуюОпцию("ИспользоватьВнешнихПользователей");
Набор = Наборы.Строки.Добавить();
Набор.Имя = "Справочник_Пользователи";
Набор.Идентификатор = Новый УникальныйИдентификатор("2bf06771-775a-406a-a5dc-45a10e98914f");
КонецПроцедуры
На своих внедрениях я активно использую дополнительные реквизиты (и реже сведения). На мой взгляд, этот механизм - одна из наиболее классных фишек БСП. В моей персональной библиотеке 1С (готовится к публикации на этом сайте) есть отдельный модуль для удобной работы с дополнительными реквизитами и сведениями.
Но недавно, создавая клиенту (УТ 11.4.8.73) нового пользователя, я заметил, что вкладка "Дополнительные реквизиты" даже не появляется, хотя у списка пользователей их должно быть 5. Зайдя в существующих пользователей, я обнаружил, что у них вкладка присутствует, но там находятся только уже заполненные допреквизиты, причем они зачеркнуты и в режиме "Только чтение". Обычно подобные эффекты возникают, если дополнительный реквизит помечен на удаление, но в данном случае все было на месте.
Поскольку "пользовательский" анализ не помогал, пришло время открывать Конфигуратор. Достаточно общеизвестно, что дополнительные реквизиты инициализируются в процедуре "ПриСозданииНаСервере" модулей форм соответствующих объектов метаданных. В данной версии за это отвечает следующий код:
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
ДополнительныеПараметры = Новый Структура;
ДополнительныеПараметры.Вставить("ИмяЭлементаДляРазмещения", "СтраницаДополнительныеРеквизиты");
ДополнительныеПараметры.Вставить("ОтложеннаяИнициализация", Истина);
МодульУправлениеСвойствами = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствами");
МодульУправлениеСвойствами.ПриСозданииНаСервере(ЭтотОбъект, ДополнительныеПараметры);
КонецЕсли;
Позволю себе прокомментировать не вполне очевидную конструкцию:
МодульУправлениеСвойствами = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствами");
МодульУправлениеСвойствами.ПриСозданииНаСервере(ЭтотОбъект, ДополнительныеПараметры);
На первый взгляд может показаться, что разработчики 1С перемудрили и стоило написать намного проще:
УправлениеСвойствами.ПриСозданииНаСервере(ЭтотОбъект, ДополнительныеПараметры);
Но на самом деле у более сложной записи есть преимущество - она будет компилироваться даже если в системе не будет общего модуля "УправлениеСвойствами". Поскольку БСП позиционируется как модульная система, подобный трюк там стандартен и часто используется.
В самой процедуре меня поджидал сюрприз:
Если Контекст.ОтложеннаяИнициализация Тогда
Судя по полному коду (не буду приводить его в статье, БСП доступно всем, можете взглянуть самостоятельно) подсистема дополнительных реквизитов поддерживает вариант работы, когда поля для реквизитов создаются в тот момент, когда пользователь открывает соответствующую вкладку (а не в момент открытия формы). И этот механизм использовался в справочнике "Пользователи". Сперва я подумал, что в механизме есть какая-то ошибка, но его отключение (с помощью переопределения процедуры в расширении) не исправило ошибку.
Пришлось более пристально взглянуть на то, как именно 1С получает список дополнительных реквизитов. В процедуре УправлениеСвойствамиСлужебный.ЗначенияСвойств() нашелся следующий запрос:
ВЫБРАТЬ
НаборыСвойств.Набор КАК Набор,
НаборыСвойств.ПорядокНабора КАК ПорядокНабора
ПОМЕСТИТЬ НаборыСвойств
ИЗ
&НаборыСвойств КАК НаборыСвойств
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗРЕШЕННЫЕ
НаборыСвойств.Набор КАК Набор,
НаборыСвойств.ПорядокНабора КАК ПорядокНабора,
СвойстваНаборов.Свойство КАК Свойство,
СвойстваНаборов.ПометкаУдаления КАК ПометкаУдаления,
СвойстваНаборов.НомерСтроки КАК ПорядокСвойства
ПОМЕСТИТЬ СвойстваНаборов
ИЗ
НаборыСвойств КАК НаборыСвойств
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыДополнительныхРеквизитовИСведений.ДополнительныеРеквизиты КАК СвойстваНаборов
ПО (СвойстваНаборов.Ссылка = НаборыСвойств.Набор)
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения КАК Свойства
ПО (СвойстваНаборов.Свойство = Свойства.Ссылка)
ГДЕ
НЕ СвойстваНаборов.ПометкаУдаления
И НЕ Свойства.ПометкаУдаления
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗРЕШЕННЫЕ
Свойства.Ссылка КАК Свойство
ПОМЕСТИТЬ ЗаполненныеСвойства
ИЗ
ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения КАК Свойства
ГДЕ
Свойства.Ссылка В(&Свойства)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
СвойстваНаборов.Набор КАК Набор,
СвойстваНаборов.ПорядокНабора КАК ПорядокНабора,
СвойстваНаборов.Свойство КАК Свойство,
СвойстваНаборов.ПорядокСвойства КАК ПорядокСвойства,
СвойстваНаборов.ПометкаУдаления КАК Удалено
ПОМЕСТИТЬ ВсеСвойства
ИЗ
СвойстваНаборов КАК СвойстваНаборов
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ЗНАЧЕНИЕ(Справочник.НаборыДополнительныхРеквизитовИСведений.ПустаяСсылка),
0,
ЗаполненныеСвойства.Свойство,
0,
ИСТИНА
ИЗ
ЗаполненныеСвойства КАК ЗаполненныеСвойства
ЛЕВОЕ СОЕДИНЕНИЕ СвойстваНаборов КАК СвойстваНаборов
ПО ЗаполненныеСвойства.Свойство = СвойстваНаборов.Свойство
ГДЕ
СвойстваНаборов.Свойство ЕСТЬ NULL
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ВсеСвойства.Набор КАК Набор,
ВсеСвойства.Свойство КАК Свойство,
ДополнительныеРеквизитыИСведения.ВладелецДополнительныхЗначений КАК ВладелецДополнительныхЗначений,
ДополнительныеРеквизитыИСведения.ЗаполнятьОбязательно КАК ЗаполнятьОбязательно,
ВЫБОР
КОГДА &ЭтоОсновнойЯзык
ТОГДА ДополнительныеРеквизитыИСведения.Заголовок
ИНАЧЕ ВЫРАЗИТЬ(ЕСТЬNULL(СвойстваПредставления.Заголовок, ДополнительныеРеквизитыИСведения.Заголовок) КАК СТРОКА(150))
КОНЕЦ КАК Наименование,
ДополнительныеРеквизитыИСведения.ТипЗначения КАК ТипЗначения,
ДополнительныеРеквизитыИСведения.ФорматСвойства КАК ФорматСвойства,
ДополнительныеРеквизитыИСведения.МногострочноеПолеВвода КАК МногострочноеПолеВвода,
ВсеСвойства.Удалено КАК Удалено,
ДополнительныеРеквизитыИСведения.Доступен КАК Доступен,
ДополнительныеРеквизитыИСведения.Виден КАК Виден,
ВЫБОР
КОГДА &ЭтоОсновнойЯзык
ТОГДА ДополнительныеРеквизитыИСведения.Подсказка
ИНАЧЕ ВЫРАЗИТЬ(ЕСТЬNULL(СвойстваПредставления.Подсказка, ДополнительныеРеквизитыИСведения.Подсказка) КАК СТРОКА(150))
КОНЕЦ КАК Подсказка,
ДополнительныеРеквизитыИСведения.ВыводитьВВидеГиперссылки КАК ВыводитьВВидеГиперссылки,
ДополнительныеРеквизитыИСведения.ЗависимостиДополнительныхРеквизитов.(
ЗависимоеСвойство КАК ЗависимоеСвойство,
Реквизит КАК Реквизит,
Условие КАК Условие,
Значение КАК Значение
) КАК ЗависимостиДополнительныхРеквизитов
ИЗ
ВсеСвойства КАК ВсеСвойства
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения КАК ДополнительныеРеквизитыИСведения
ПО ВсеСвойства.Свойство = ДополнительныеРеквизитыИСведения.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения.Представления КАК СвойстваПредставления
ПО (СвойстваПредставления.Ссылка = ДополнительныеРеквизитыИСведения.Ссылка)
И (СвойстваПредставления.КодЯзыка = &КодЯзыка)
УПОРЯДОЧИТЬ ПО
Удалено,
ВсеСвойства.ПорядокНабора,
ВсеСвойства.ПорядокСвойства
Этот запрос делает две вещи - получает актуальные дополнительные реквизиты согласно данным в наборах и объединяет их с дополнительными реквизитами, заполненными в текущем объекте. Но у меня временная таблица "СвойстваНаборов" оказалась пустой. Запрос был перенесен в консоль, и на этапе настройки параметров выяснилось интересное - в справочнике "Наборы свойств дополнительных реквизитов и сведений" было два элемента с именем "Пользователи" - один предопределенный, а другой обычный. Причем в консоли предопределенный элемент давал нужные результаты, а обычный - пустую таблицу.
Создалось впечатление, что каким-то образом появился дубль, и система находит не тот элемент. Недолго думая, я решил попробовать удалить НЕ предопределенный элемент "Пользователи". Но удалить не получилось (ошибка, как выяснилось, была не только с пользователями):
Я склонен воспринимать это сообщение как баг системы. Я четко вижу, что удаляю НЕ ПРЕДОПРЕДЕЛЕННЫЙ элемент, но система пытается убедить меня в обратном. У неё не получилось - я отловил место, в котором возникает это сообщение, и переопределил его в расширении на что-то пустое. После этого "предопределенный элемент" удалился.
Но после этого неожиданно перестала открываться форма справочника "Пользователи". Это меня, мягко говоря, удивило. Удивление выросло, когда я прошелся отладчиком и обнаружил, что в ходе процедуры открытия система получает "битую ссылку" на удаленный элемент справочника. Напоминаю, что элемент был удален "Удалением помеченных объектов", ссылок на него в системе не было. Я копнул чуть глубже, и обнаружил замечательную процедуру:
Процедура ПриПолученииПредопределенныхНаборовСвойств(Наборы) Экспорт
Набор = Наборы.Строки.Добавить();
Набор.Имя = "Справочник_ВнешниеПользователи";
Набор.Идентификатор = Новый УникальныйИдентификатор("d9c30d48-a72a-498a-9faa-c078bf652776");
Набор.Используется = ПолучитьФункциональнуюОпцию("ИспользоватьВнешнихПользователей");
Набор = Наборы.Строки.Добавить();
Набор.Имя = "Справочник_Пользователи";
Набор.Идентификатор = Новый УникальныйИдентификатор("2bf06771-775a-406a-a5dc-45a10e98914f");
КонецПроцедуры
На тех проектах, где у меня был адекватных техлид, за такое били линейкой по пальцам (фигурально выражаясь, естественно. Я всячески против физического насилия над программистами). Из очевидных проблем с подобным программным кодом:
1. Есть механизм предопределенных элементов, который, казалось бы, ПРЕДНАЗНАЧЕН для того чтобы не делать таких вещей.
2. Ломается обработка удаления - она не видит этой "неявной ссылки" на объект.
3. Ломается визуальный интерфейс предопределенных элементов.
Так или иначе, процедура была отрефакторена к чему-то, больше похожему на разумный программный код:
&Вместо("ПриПолученииПредопределенныхНаборовСвойств")
Процедура А1_ПриПолученииПредопределенныхНаборовСвойств(Наборы)
Набор = Наборы.Строки.Добавить();
Набор.Имя = "Справочник_ВнешниеПользователи";
//Набор.Идентификатор = Новый УникальныйИдентификатор("d9c30d48-a72a-498a-9faa-c078bf652776");
Набор.Идентификатор = Справочники.НаборыДополнительныхРеквизитовИСведений.Справочник_ВнешниеПользователи.УникальныйИдентификатор();
Набор.Используется = ПолучитьФункциональнуюОпцию("ИспользоватьВнешнихПользователей");
Набор = Наборы.Строки.Добавить();
Набор.Имя = "Справочник_Пользователи";
//Набор.Идентификатор = Новый УникальныйИдентификатор("2bf06771-775a-406a-a5dc-45a10e98914f");
Набор.Идентификатор = Справочники.НаборыДополнительныхРеквизитовИСведений.Справочник_Пользователи.УникальныйИдентификатор();
КонецПроцедуры
На этом история заканчивается - после исправления формы открываются и дополнительные реквизиты показываются. Ждем следующих интересных решений от фирмы "1С".