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

