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