gifts2017

Получение дерева подчиненности.

Опубликовал sbv2005 (sbv2005) в раздел Программирование - Практика программирования

Одна функция и 3 процедуры, которые следует разместить в общем модуле (клиент, сервер). Возвращает дерево значений родительских и подчиненных документов от переданного документа через входной параметр "Ссылка". Выполняться может на сервере.

 

 

 

// Получение дерева подчиненности (родительские и подчиненные документы)
Функция ДеревоПодчиненности(Ссылка) Экспорт

   
ДеревоДокументов = Новый ДеревоЗначений;
   
ДеревоДокументов.Колонки.Добавить("Ссылка");
   
ДеревоДокументов.Колонки.Добавить("ДокументПредставление");
   
ДеревоДокументов.Колонки.Добавить("Проведен");
   
ДеревоДокументов.Колонки.Добавить("ПометкаУдаления");
   
ДеревоДокументов.Колонки.Добавить("ВидДокумента");
   
мУжеВСписке = Новый Соответствие;

    мДерево = ДеревоДокументов;
   
ВывестиРодительскиеДокументы(Ссылка, мУжеВСписке, мДерево);
   
ВывестиПодчиненныеДокументы(мДерево, мУжеВСписке);

    Возврат
ДеревоДокументов;

КонецФункции
//
Процедура ВывестиРодительскиеДокументы(ДокументСсылка, мУжеВСписке, мДерево)

   
МетаданныеДокумента = ДокументСсылка.Метаданные();
   
СписокРеквизитов = Новый СписокЗначений;

    Для Каждого
Реквизит ИЗ МетаданныеДокумента.Реквизиты Цикл
       
ТипыРеквизита = Реквизит.Тип.Типы();
        Для Каждого
ТекущийТип ИЗ ТипыРеквизита Цикл
           
МетаданныеРеквизита = Метаданные.НайтиПоТипу(ТекущийТип);

            Если
МетаданныеРеквизита<>Неопределено И Метаданные.Документы.Содержит(МетаданныеРеквизита)
                И
ПравоДоступа("Чтение", МетаданныеРеквизита) Тогда
                Попытка
                   
ЗначениеРеквизита = ДокументСсылка[Реквизит.Имя];
                Исключение
                    Прервать;
                КонецПопытки;
                ЕСли
ЗначениеРеквизита<>Неопределено И НЕ ЗначениеРеквизита.Пустая() И ТипЗнч(ЗначениеРеквизита) = ТекущийТип
                    И мУжеВСписке[ЗначениеРеквизита] = Неопределено И СписокРеквизитов.НайтиПоЗначению(ДокументСсылка[Реквизит.Имя]) = Неопределено Тогда
                   
СписокРеквизитов.Добавить(ЗначениеРеквизита,Формат(ЗначениеРеквизита.Дата,"ДФ=yyyyMMddЧЧММсс"));
                КонецЕсли;
            КонецЕсли;

        КонецЦикла;
    КонецЦикла;

    Для Каждого
ТЧ Из МетаданныеДокумента.ТабличныеЧасти Цикл
       
СтрРеквизитов = "";

        Попытка
           
СодержимоеТЧ = ДокументСсылка[ТЧ.Имя].Выгрузить();
        Исключение
            Прервать;
        КонецПопытки;

        Для Каждого
Реквизит ИЗ ТЧ.Реквизиты Цикл
           
ТипыРеквизита = Реквизит.Тип.Типы();
            Для Каждого
ТекущийТип ИЗ ТипыРеквизита Цикл
               
МетаданныеРеквизита = Метаданные.НайтиПоТипу(ТекущийТип);
                Если
МетаданныеРеквизита<>Неопределено И Метаданные.Документы.Содержит(МетаданныеРеквизита)
                    И
ПравоДоступа("Чтение", МетаданныеРеквизита) Тогда
                   
СтрРеквизитов = СтрРеквизитов + ?(СтрРеквизитов = "", "", ", ") + Реквизит.Имя;
                    Прервать;
                КонецЕсли;
            КонецЦикла;
        КонецЦикла;

       
СодержимоеТЧ.Свернуть(СтрРеквизитов);
        Для Каждого
КолонкаТЧ ИЗ СодержимоеТЧ.Колонки Цикл
            Для Каждого
СтрокаТЧ ИЗ СодержимоеТЧ Цикл
                Попытка
                   
ЗначениеРеквизита = СтрокаТЧ[КолонкаТЧ.Имя];
                Исключение
                    Продолжить;
                КонецПопытки;
               
МетаданныеЗначения = Метаданные.НайтиПоТипу(ТипЗнч(ЗначениеРеквизита));
                Если
МетаданныеЗначения = Неопределено Тогда
                   
// базовый тип
                   
Продолжить;
                КонецЕсли;

                ЕСли
ЗначениеРеквизита<>Неопределено И НЕ ЗначениеРеквизита.Пустая()
                    И
Метаданные.Документы.Содержит(МетаданныеЗначения)
                    И
мУжеВСписке[ЗначениеРеквизита] = Неопределено Тогда
                    Если
СписокРеквизитов.НайтиПоЗначению(ЗначениеРеквизита) = Неопределено Тогда
                       
СписокРеквизитов.Добавить(ЗначениеРеквизита,Формат(ЗначениеРеквизита.Дата,"ДФ=yyyyMMddЧЧММсс"));
                    КонецЕсли;
                КонецЕсли;
            КонецЦикла;
        КонецЦикла;
    КонецЦикла;
   
СписокРеквизитов.СортироватьПоПредставлению();
   
мУжеВСписке.Вставить(ДокументСсылка, Истина);

    Если
СписокРеквизитов.Количество() = 1 Тогда
       
ВывестиРодительскиеДокументы(СписокРеквизитов[0].Значение, мУжеВСписке, мДерево);
    ИначеЕсли
СписокРеквизитов.Количество() > 1 Тогда
       
ВывестиБезРодителей(СписокРеквизитов, мУжеВСписке, мДерево);
    КонецЕсли;


   
СтрокаДерева = мДерево.Строки.Добавить();
   
Запрос = Новый Запрос("ВЫБРАТЬ РАЗРЕШЕННЫЕ Ссылка, Проведен, ПометкаУдаления, Представление, """ + МетаданныеДокумента.Имя + """ КАК Метаданные
    | ИЗ Документ."
+МетаданныеДокумента.Имя + " ГДЕ Ссылка = &Ссылка");

   
Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);

   
Выборка  = Запрос.Выполнить().Выбрать();
    Если
Выборка.Следующий() Тогда
       
СтрокаДерева.Ссылка = Выборка.Ссылка;
       
СтрокаДерева.ДокументПредставление = Выборка.Ссылка.Метаданные().Синоним + " " + Выборка.Ссылка.Номер;
       
СтрокаДерева.Проведен = Выборка.Проведен;
       
СтрокаДерева.ПометкаУдаления = Выборка.ПометкаУдаления;
       
СтрокаДерева.ВидДокумента = Выборка.Метаданные;
    Иначе
       
СтрокаДерева.Ссылка= ДокументСсылка;
    КонецЕсли;

   
мДерево = СтрокаДерева;

КонецПроцедуры
//
Процедура ВывестиПодчиненныеДокументы(СтрокаДерева, мУжеВСписке)

   
ТекущийДокумент = СтрокаДерева.Ссылка;
   
ТипДокумента = ТипЗнч(ТекущийДокумент);
   
СтруктураРеквизитов = Новый ТаблицаЗначений;
   
СтруктураРеквизитов.Колонки.Добавить("ПутьКДанным");
   
СтруктураРеквизитов.Колонки.Добавить("ИмяРеквизита");

    Для каждого
Док ИЗ Метаданные.Документы Цикл
        Если НЕ
ПравоДоступа("Чтение", Док) Тогда
            Продолжить;
        КонецЕсли;

        Для Каждого
Реквизит Из Док.Реквизиты Цикл
            Если
Реквизит.Тип.СодержитТип(ТипДокумента) Тогда
               
НовСтр = СтруктураРеквизитов.Добавить();
               
НовСтр.ПутьКДанным = Док.Имя;
               
НовСтр.ИмяРеквизита = Реквизит.Имя;
            КонецЕсли;
        КонецЦикла;

        Для Каждого
ТЧ ИЗ Док.ТабличныеЧасти Цикл
            Для Каждого
Реквизит Из ТЧ.Реквизиты Цикл
                Если
Реквизит.Тип.СодержитТип(ТипДокумента) Тогда
                   
НовСтр = СтруктураРеквизитов.Добавить();
                   
НовСтр.ПутьКДанным = Док.Имя+"."+ТЧ.Имя;
                   
НовСтр.ИмяРеквизита = Реквизит.Имя;
                КонецЕсли;
            КонецЦикла;
        КонецЦикла;

    КонецЦикла;
   
ТекстЗапроса = "";
    Для Каждого
КлючИЗначение Из СтруктураРеквизитов Цикл

        Если
Найти(КлючИЗначение.ПутьКДанным, ".") = 0 Тогда

           
ТекстЗапроса = ТекстЗапроса + "
            |Выбрать "
+ ?(ТекстЗапроса="", "РАЗРЕШЕННЫЕ ", "") + "Ссылка, Ссылка.Дата Как ДатаДок, Представление, Проведен, ПометкаУдаления, """+ КлючИЗначение.ПутьКДанным +""" КАК ВидДокумента ИЗ Документ."+КлючИЗначение.ПутьКДанным+"
            |ГДЕ "
+КлючИЗначение.ИмяРеквизита+"=&ДокументОснование
            |ОБЪЕДИНИТЬ ВСЕ
            |"
;

        Иначе
           
ПозицияТочки = Найти(КлючИЗначение.ПутьКДанным, ".");
           
ТекстЗапроса = ТекстЗапроса + "
            |Выбрать "
+ ?(ТекстЗапроса="", "РАЗРЕШЕННЫЕ ", "") + "Ссылка, Ссылка.Дата Как ДатаДок, Ссылка.Представление,  Ссылка.Проведен, Ссылка.ПометкаУдаления, """+ Лев(КлючИЗначение.ПутьКДанным, ПозицияТочки-1) +""" КАК ВидДокумента ИЗ Документ."+КлючИЗначение.ПутьКДанным+"
            |ГДЕ "
+КлючИЗначение.ИмяРеквизита+"=&ДокументОснование
            |ОБЪЕДИНИТЬ ВСЕ
            |"
;

        КонецЕсли;
    КонецЦикла;

    Если
ТекстЗапроса="" Тогда
        Возврат;
    КонецЕсли;

   
ТекстЗапроса = Лев (ТекстЗапроса, СтрДлина(ТекстЗапроса)-15);
   
ТекстЗапроса = ТекстЗапроса+ "
    |УПОРЯДОЧИТЬ ПО  ДатаДок"
;

   
Запрос = Новый Запрос(ТекстЗапроса);
   
Запрос.УстановитьПараметр("ДокументОснование", ТекущийДокумент);
   
Выборка = Запрос.Выполнить().Выбрать();


    Пока
Выборка.Следующий() Цикл
        Если
мУжеВСписке[Выборка.Ссылка] = Неопределено Тогда
           
НоваяСтрока = СтрокаДерева.Строки.Добавить();
           
НоваяСтрока.Ссылка = Выборка.Ссылка;
           
НоваяСтрока.ДокументПредставление = Выборка.Ссылка.Метаданные().Синоним + " " + Выборка.Ссылка.Номер;
           
НоваяСтрока.Проведен = Выборка.Проведен;
           
НоваяСтрока.ПометкаУдаления = Выборка.ПометкаУдаления;
           
НоваяСтрока.ВидДокумента = Выборка.ВидДокумента;
           
мУжеВСписке.Вставить(Выборка.Ссылка, Истина);
           
ВывестиПодчиненныеДокументы(НоваяСтрока, мУжеВСписке);
        КонецЕсли;
    КонецЦикла;

КонецПроцедуры
//
Процедура ВывестиБезРодителей(СписокДокументов, мУжеВСписке, мДерево)

    Для Каждого
ЭлементСписка Из СписокДокументов Цикл

       
МетаданныеДокумента = ЭлементСписка.Значение.Метаданные();

       
Запрос = Новый Запрос("ВЫБРАТЬ РАЗРЕШЕННЫЕ Ссылка, Проведен, ПометкаУдаления, Представление, """ + МетаданныеДокумента.Имя + """ КАК Метаданные
        | ИЗ Документ."
+МетаданныеДокумента.Имя + " ГДЕ Ссылка = &Ссылка");

       
Запрос.УстановитьПараметр("Ссылка", ЭлементСписка.Значение);

       
Выборка  = Запрос.Выполнить().Выбрать();
        ЕСли
Выборка.Следующий() Тогда
            Если
мУжеВСписке[Выборка.Ссылка] = Неопределено Тогда
               
СтрокаДерева = мДерево.Строки.Добавить();
               
СтрокаДерева.Ссылка= Выборка.Ссылка;
               
СтрокаДерева.ДокументПредставление = Выборка.Ссылка.Метаданные().Синоним + " " + Выборка.Ссылка.Номер;
               
СтрокаДерева.Проведен = Выборка.Проведен;
               
СтрокаДерева.ПометкаУдаления = Выборка.ПометкаУдаления;
               
СтрокаДерева.ВидДокумента = Выборка.Метаданные;
               
мУжеВСписке.Вставить(Выборка.Ссылка, Истина);
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;

   
мДерево = СтрокаДерева;

КонецПроцедуры


См. также

Подписаться Добавить вознаграждение

Комментарии

1. Олег (OLEG4120) 27.04.11 09:00
2. Владимир Пушин (vladnet) 27.04.11 11:13
По мне так нет такого понятия как дерево подчиненных документов, есть граф подчиненных документов http://infostart.ru/public/20369/
3. sbv2005 (sbv2005) 27.04.11 12:08
(2) Писал как вариант для оперативного алгоритма, поэтому и делал под сервер тоже, без форм.
4. Дмитрий Елисеев (w-divin) 27.04.11 14:12
(2) По мне - так есть дерево подчиненных документов, имеющее корень(родительский, первый документ) и ветви (всё что на него ссылается). а по графу - я в Вашей теме оставил пару комментов (((
5. Дмитрий Елисеев (w-divin) 27.04.11 14:22
(2) и опять же производительность:
Данный вариант:
Замер:
Результат:

И Ваш вариант (дубль из коммента в Вашей теме):
Замер:
Результат:
6. Дмитрий Елисеев (w-divin) 27.04.11 14:25
(0) за "под сервер" плюсеГ ))) все леньки было самому рисовать ))) как оказалось не зря ленился )))
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа