Внимание! Всё это написано во времена 8.1 и до появления настоящей БСП и многих современных инструментов!
Просто собрание процедур и функций, которые я использую в работе с построителями запросов и СКД. Позволяют сэкономить время при разработке, являются эдакой "маленькой БСП". Рассчитаны на серверное исполнение и серверный вызов (там, где это допустимо по контексту).
#Область ОбщиеДействия
// превращает строку вида "Моя хорошая строка" в вид "МояХорошаяСтрока"
Функция ПревращениеНаименованияВИмя(рСтрока,рУбиратьЗапрещённые=Истина) Экспорт
Если рУбиратьЗапрещённые Тогда
стро=УбратьЗапрещённыеСимволы(рСтрока);
Иначе
стро=рСтрока;
КонецЕсли;
резстро=""; СледующаяЗаглавная=Ложь;
Для й=1 По СтрДлина(стро) Цикл
сим=Сред(стро,й,1);
Если сим=" " Тогда
СледующаяЗаглавная=Истина;
Иначе
Если СледующаяЗаглавная или й=1 Тогда
сим=ВРег(сим);
КонецЕсли;
резстро=резстро+сим;
СледующаяЗаглавная=Ложь;
КонецЕсли;
КонецЦикла;
Возврат резстро;
КонецФункции
// превращает строку вида "МояХорошаяСтрока" в вид "Моя хорошая строка"
Функция ПревращениеИмениВНаименование(рСтрока) Экспорт
Если СтрДлина(рСтрока)<=1 Тогда Возврат рСтрока КонецЕсли;
сим=Сред(рСтрока,1,1);
рПредВерхний=(ВРег(сим)=сим);
резстро=сим;
Для й=2 По СтрДлина(рСтрока) Цикл
сим=Сред(рСтрока,й,1);
Если сим="_" Тогда сим="." КонецЕсли;
рТекВерхний=(ВРег(сим)=сим);
Если рТекВерхний и не рПредВерхний Тогда
резстро=резстро+" "+НРег(сим);
Иначе
резстро=резстро+сим;
КонецЕсли;
рПредВерхний=рТекВерхний;
КонецЦикла;
Возврат резстро;
КонецФункции
// оставляет в строке только символы, допустимые в наименованиях согласно нотации 1С
Функция УбратьЗапрещённыеСимволы(Знач рСтрока,рЗапретные="",рНаЧтоЗаменять=Неопределено,рБезЛидирующего=Ложь) Экспорт
стрзнч=СокрЛП(Строка(рСтрока));
Если ПустаяСтрока(рЗапретные) Тогда // по умолчанию считаем таковыми:
рЗапретные="?,=\|:;&""@#$^!~`'[]{}№+-/*%()<>"+Символы.ВК+Символы.ВТаб+Символы.НПП+Символы.ПС+Символы.ПФ+Символы.Таб;
КонецЕсли;
рез="";
Для й=1 По СтрДлина(стрзнч) Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
сим=Сред(стрзнч,й,1);
Если Найти(рЗапретные,сим)=0 Тогда // не запретный
рез=рез+сим;
Иначе
Если рНаЧтоЗаменять<>Неопределено Тогда рез=рез+рНаЧтоЗаменять КонецЕсли; // здесь именно так, сравниваем с Неопределено
КонецЕсли;
КонецЦикла;
Если не рБезЛидирующего Тогда
Числа="0123456789";
Если Найти(Числа,Лев(рез,1))<>0 Тогда рез="_"+рез КонецЕсли;
КонецЕсли;
Возврат рез;
КонецФункции
Функция ПолучитьОписаниеТипаПоЗначению(рЗначение) Экспорт
Попытка
рТипЗнчСвойства=ТипЗнч(рЗначение);
квЧисла=""; квСтроки=""; квДаты="";
мТипов=Новый Массив;
мТипов.Добавить(рТипЗнчСвойства);
Если рТипЗнчСвойства=Тип("Число") Тогда
мстроч=СтрРазделить(Строка(рЗначение),",",Ложь);
квЧисла=Новый КвалификаторыЧисла(СтрДлина(мстроч[0]),?(мстроч.Количество()=1,0,СтрДлина(мстроч[1])),ДопустимыйЗнак.Любой);
ИначеЕсли рТипЗнчСвойства=Тип("Строка") Тогда
квСтроки=Новый КвалификаторыСтроки(СтрДлина(СокрЛП(рЗначение)));
ИначеЕсли рТипЗнчСвойства=Тип("Дата") Тогда
квДаты=Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя); // всегда пусть так
КонецЕсли;
рОписТипов=Неопределено;
рКоманда="рОписТипов=Новый ОписаниеТипов(мТипов,";
рКоманда=рКоманда+?(квЧисла<>"","квЧисла,",",");
рКоманда=рКоманда+?(квСтроки<>"","квСтроки,",",");
рКоманда=рКоманда+?(квДаты<>"","квДаты","");
рКоманда=рКоманда+");";
Выполнить(рКоманда);
Возврат рОписТипов;
Исключение
Сообщить("ПолучитьОписаниеТипаПоЗначению, ошибка: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
Возврат Неопределено;
КонецПопытки;
КонецФункции
// убирает из описания типа Неопределено и Null
Функция ПолучитьОписаниеТипаБезПустых(рОписТипов) Экспорт
мТипов=Новый Массив;
Для каждого рТип Из рОписТипов.Типы() Цикл
Если рТип=Тип("Неопределено") или рТип=Тип("NULL") или рТип=Неопределено или рТип=Null Тогда Продолжить КонецЕсли;
мТипов.Добавить(рТип);
КонецЦикла;
Возврат Новый ОписаниеТипов(мТипов,рОписТипов.КвалификаторыЧисла,рОписТипов.КвалификаторыСтроки,рОписТипов.КвалификаторыДаты);
КонецФункции
// возвращает получившуюся строку
Функция СохранитьНастройкуСКДвСтроку(рНастройка) Экспорт
Попытка
Если ТипЗнч(рНастройка)<>Тип("НастройкиКомпоновкиДанных") Тогда Возврат "" КонецЕсли;
//
рЗаписьХМЛ=Новый ЗаписьXML;
рЗаписьХМЛ.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(рЗаписьХМЛ,рНастройка);
Возврат рЗаписьХМЛ.Закрыть();
Исключение
Сообщить("СохранитьНастройкуСКДвСтроку: ошибка: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
КонецПопытки;
КонецФункции
// возвращает получившуюся настройку СКД
Функция ВосстановитьНастройкуСКДизСтроки(рСтрока) Экспорт
Попытка
Если ПустаяСтрока(рСтрока) Тогда Возврат Неопределено КонецЕсли;
//
рЧтениеХМЛ=Новый ЧтениеXML;
рЧтениеХМЛ.УстановитьСтроку(рСтрока);
рНастройка=СериализаторXDTO.ПрочитатьXML(рЧтениеХМЛ,Тип("НастройкиКомпоновкиДанных"));
Если ТипЗнч(рНастройка)<>Тип("НастройкиКомпоновкиДанных") Тогда Возврат Неопределено КонецЕсли;
Возврат рНастройка;
Исключение
Сообщить("ВосстановитьНастройкуСКДизСтроки: ошибка: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
Возврат Неопределено;
КонецПопытки;
КонецФункции
#КонецОбласти
#Область РаботаСЗапросамиИПостроителями
// Если Построителю просто передать таблицу значений как источник, он её заполнит без разыменоваий. Эта функция
// решает эту проблему, возвращая строку, которую надо занести в Построитель.Текст и сразу ЗаполнитьНастройки()
//
Функция ПолучитьТЗПостроителяПоТаблицеЗначений(рТаблица) Экспорт
тз1=""; тз2=""; разд="";
Для каждого кол Из рТаблица.Колонки Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
рТипКолонки=кол.ТипЗначения.Типы().Получить(0);
Если рТипКолонки=Тип("Массив") или рТипКолонки=Тип("СписокЗначений")
или рТипКолонки=Тип("ТаблицаЗначений") или рТипКолонки=Тип("Структура")
Тогда // просто внесём поле
тз1=тз1+разд+"
| Неопределено КАК "+кол.Имя;
Иначе
метаоб=Метаданные.НайтиПоТипу(рТипКолонки);
Если метаоб<>Неопределено Тогда
тз1=тз1+разд+"
| р"+метаоб.Имя+".Ссылка КАК "+кол.Имя;
Если Найти(тз2,"р"+метаоб.Имя)=0 Тогда
тз2=тз2+разд+"
| "+метаоб.ПолноеИмя()+" КАК р"+метаоб.Имя;
КонецЕсли;
Иначе
// простой тип
Если рТипКолонки=Тип("Число") Тогда
строз="ВЫРАЗИТЬ(0 КАК ЧИСЛО("+СокрЛП(кол.ТипЗначения.КвалификаторыЧисла.Разрядность)+","+СокрЛП(кол.ТипЗначения.КвалификаторыЧисла.РазрядностьДробнойЧасти)+"))";
ИначеЕсли рТипКолонки=Тип("Строка") Тогда
строз="ВЫРАЗИТЬ("""" КАК СТРОКА("+СокрЛП(кол.ТипЗначения.КвалификаторыСтроки.Длина)+"))";
ИначеЕсли рТипКолонки=Тип("Дата") Тогда
строз="ДАТАВРЕМЯ(1,1,1)";
ИначеЕсли рТипКолонки=Тип("Булево") Тогда
строз="ЛОЖЬ";
КонецЕсли;
тз1=тз1+разд+"
| "+строз+" КАК "+кол.Имя;
КонецЕсли;
КонецЕсли;
разд=",";
КонецЦикла;
тз="ВЫБРАТЬ"+тз1+"
|ИЗ"+тз2;
тз=СтрЗаменить(тз,"ИЗ,","ИЗ"); // некогда переделывать
Возврат тз;
КонецФункции
// Возвращает булево - есть ли отборы
Функция ЕстьОтборы(постр) Экспорт
Попытка
Для каждого отб Из постр.Отбор Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
Если отб.Использование Тогда Возврат Истина КонецЕсли;
КонецЦикла;
Возврат Ложь;
Исключение
Возврат Ложь;
КонецПопытки;
КонецФункции
//В процедуру можно передать в качестве источника Построитель (запроса или отчёта), отбор (не СКД!),
// таблицу значений или структуру, имена колонок или ключей которой соответствуют именам колонок отбора
// (ВидСравнения, Значение, ЗначениеПо, ЗначениеС, Имя, Использование, Представление, ПутьКДанным, ТипЗначения;
// Значение, ЗначениеС и ЗначениеПо необходимы в зависимости от установленного вида сравнения, ТипЗначения не обязателен).
// Приёмник структурой быть не может, в остальном аналогичен.
// Если передан параметр рИмяПутьОтбора - копируется только отбор с переданным именем/путём к данным (строка).
Процедура КопироватьОтбор(рОткуда,рКуда,рИмяПутьОтбора="",рТолькоИспользуемые=Ложь) Экспорт
Если ТипЗнч(рОткуда)=Тип("ПостроительОтчета") или ТипЗнч(рОткуда)=Тип("ПостроительЗапроса") Тогда
рОтправитель=рОткуда.Отбор;
ИначеЕсли ТипЗнч(рОткуда)=Тип("Отбор") или ТипЗнч(рОткуда)=Тип("ТаблицаЗначений") Тогда
рОтправитель=рОткуда;
ИначеЕсли ТипЗнч(рОткуда)=Тип("Структура") Тогда
рОтправитель=Новый Массив;
рОтправитель.Добавить(рОткуда);
Иначе
Возврат;
КонецЕсли;
Если ТипЗнч(рКуда)=Тип("ПостроительОтчета") или ТипЗнч(рКуда)=Тип("ПостроительЗапроса") Тогда
рПолучатель=рКуда.Отбор;
ИначеЕсли ТипЗнч(рКуда)=Тип("Отбор") или ТипЗнч(рКуда)=Тип("ТаблицаЗначений") Тогда
рПолучатель=рКуда;
Иначе
Возврат;
КонецЕсли;
Для каждого отб Из рОтправитель Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
Если не ПустаяСтрока(рИмяПутьОтбора)
и СокрЛП(отб.Имя)<>СокрЛП(рИмяПутьОтбора)
и Найти(отб.ПутьКДанным,СокрЛП(рИмяПутьОтбора))=0
Тогда Продолжить КонецЕсли; // указан конкретный элемент отбора, который надо скопировать; остальные не нужны
Если рТолькоИспользуемые и не отб.Использование Тогда Продолжить КонецЕсли;
Попытка
// среди имеющихся ищем не по имени, а по пути и имени
новотб=Неопределено;
Для каждого нотб Из рПолучатель Цикл
Если СокрЛП(нотб.Имя)=СокрЛП(отб.Имя) и СокрЛП(нотб.ПутьКДанным)=СокрЛП(отб.ПутьКДанным) Тогда
новотб=нотб; Прервать
КонецЕсли;
КонецЦикла;
Если новотб=Неопределено Тогда
новотб=рПолучатель.Добавить(отб.ПутьКДанным,отб.Имя,отб.Представление);
КонецЕсли;
новотб.ВидСравнения=отб.ВидСравнения;
Если отб.ВидСравнения=ВидСравнения.Интервал или отб.ВидСравнения=ВидСравнения.ИнтервалВключаяГраницы
или отб.ВидСравнения=ВидСравнения.ИнтервалВключаяНачало или отб.ВидСравнения=ВидСравнения.ИнтервалВключаяОкончание
Тогда
новотб.ЗначениеС=отб.ЗначениеС;
новотб.ЗначениеПо=отб.ЗначениеПо;
Иначе
новотб.Значение=отб.Значение;
КонецЕсли;
новотб.Использование=отб.Использование;
Исключение
Сообщить("Ошибка при копировании отбора "+СокрЛП(отб.ПутьКДанным)+", "+ОписаниеОшибки(),СтатусСообщения.Важное);
КонецПопытки;
КонецЦикла;
КонецПроцедуры
// Сортирует отбор объекта или независимый отбор по строке сортировки; заодно заносит отбор в табзначений
Процедура СортироватьОтбор(рОтбор,рСтрокаСортировки="",рТаблицаОтбора="") Экспорт
Если ТипЗнч(рОтбор)=Тип("ПостроительОтчета") или ТипЗнч(рОтбор)=Тип("ПостроительЗапроса") Тогда
рабОтбор=рОтбор.Отбор;
ИначеЕсли ТипЗнч(рОтбор)=Тип("Отбор") Тогда
рабОтбор=рОтбор;
Иначе
Возврат;
КонецЕсли;
таб=Новый ТаблицаЗначений;
таб.Колонки.Добавить("ВидСравнения");
таб.Колонки.Добавить("Значение");
таб.Колонки.Добавить("ЗначениеС");
таб.Колонки.Добавить("ЗначениеПо");
таб.Колонки.Добавить("Имя");
таб.Колонки.Добавить("Использование");
таб.Колонки.Добавить("Представление");
таб.Колонки.Добавить("ПутьКДанным");
таб.Колонки.Добавить("ТипЗначения");
таб.Колонки.Добавить("ЭлементОтбора"); // служебная
Для каждого отб Из рабОтбор Цикл
Попытка
стро=таб.Добавить();
ЗаполнитьЗначенияСвойств(стро,отб);
стро.ЭлементОтбора=отб;
Исключение
Сообщить("Ошибка для "+СокрЛП(отб.ПутьКДанным)+": "+ОписаниеОшибки(),СтатусСообщения.Важное);
КонецПопытки;
КонецЦикла;
рТаблицаОтбора=таб.Скопировать();
//
Если не ПустаяСтрока(рСтрокаСортировки) Тогда
Попытка
таб.Сортировать(СокрЛП(рСтрокаСортировки));
Исключение
Сообщить("Неверная строка сортировки при сортировке отбора: "+ОписаниеОшибки(),СтатусСообщения.Важное);
Возврат;
КонецПопытки;
Иначе
Возврат; // просто занесение в табзнач, без сортировки
КонецЕсли;
//
// теперь собственно преобразуем переданный объект
Если ТипЗнч(рОтбор)=Тип("ПостроительОтчета") или ТипЗнч(рОтбор)=Тип("ПостроительЗапроса") Тогда
Для й=1 По таб.Количество() Цикл
рОтбор.Отбор.Удалить(таб.Количество()-й);
КонецЦикла;
Для каждого стро Из таб Цикл
отб=рОтбор.Отбор.Добавить(стро.ПутьКДанным,стро.Имя,стро.Представление);
ЗаполнитьЗначенияСвойств(отб,стро);
КонецЦикла;
ИначеЕсли ТипЗнч(рОтбор)=Тип("Отбор") Тогда
Для й=1 По таб.Количество() Цикл
рОтбор.Удалить(таб.Количество()-й);
КонецЦикла;
Для каждого стро Из таб Цикл
отб=рОтбор.Добавить(стро.ПутьКДанным,стро.Имя,стро.Представление);
ЗаполнитьЗначенияСвойств(отб,стро);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
// Ищет среди элементов отбора рПостроителя элемент с путём данных, равным рПутьИлиОтбор (или его разыменованию)
// Если таковой не найден, он создаётся - если передан путь к данным, то только путь и имя, иначе ставятся все свойства
// Если ошибка, возвращает Неопределено
//
Функция ПолучитьОтбор(рПостроитель,рПутьИлиОтбор,рИмя="") Экспорт
рНужныйОтбор=Неопределено;
Если ТипЗнч(рПостроитель)<>Тип("ПостроительЗапроса")
и ТипЗнч(рПостроитель)<>Тип("ПостроительОтчета")
Тогда Возврат рНужныйОтбор КонецЕсли;
Если ТипЗнч(рПутьИлиОтбор)<>Тип("Строка")
и ТипЗнч(рПутьИлиОтбор)<>Тип("ЭлементОтбора")
Тогда Возврат рНужныйОтбор КонецЕсли;
Для каждого отб Из рПостроитель.Отбор Цикл
Если ТипЗнч(рПутьИлиОтбор)=Тип("Строка") Тогда
Если СокрЛП(отб.ПутьКДанным)=СокрЛП(рПутьИлиОтбор) Тогда
рНужныйОтбор=отб; Прервать
КонецЕсли;
ИначеЕсли ТипЗнч(рПутьИлиОтбор)=Тип("ЭлементОтбора") Тогда
Если СокрЛП(отб.ПутьКДанным)=СокрЛП(рПутьИлиОтбор.ПутьКДанным) Тогда
рНужныйОтбор=отб; Прервать
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если рНужныйОтбор=Неопределено Тогда // создаём
Если ТипЗнч(рПутьИлиОтбор)=Тип("Строка") Тогда
рНужныйОтбор=рПостроитель.Отбор.Добавить(СокрЛП(рПутьИлиОтбор),?(ПустаяСтрока(рИмя),СокрЛП(рПутьИлиОтбор),рИмя));
рНужныйОтбор.Представление=ПревращениеИмениВНаименование(рНужныйОтбор.Имя);
ИначеЕсли ТипЗнч(рПутьИлиОтбор)=Тип("ЭлементОтбора") Тогда
рНужныйОтбор=рПостроитель.Отбор.Добавить(СокрЛП(рПутьИлиОтбор.ПутьКДанным),СокрЛП(рПутьИлиОтбор.Имя),СокрЛП(рПутьИлиОтбор.Представление));
КопироватьОтбор(рПутьИлиОтбор,рНужныйОтбор); // все остальные свойства
КонецЕсли;
КонецЕсли;
Возврат рНужныйОтбор;
КонецФункции
// Использует построитель, а не СКД
Функция ВывестиТаблицуЗначенийВМакет(тДанных,рЗаголовок="") Экспорт
Попытка
т=Новый ТабличныйДокумент;
постр=Новый ПостроительОтчета;
постр.ИсточникДанных=Новый ОписаниеИсточникаДанных(тДанных);
постр.ЗаполнениеРасшифровки=ВидЗаполненияРасшифровкиПостроителяОтчета.НеЗаполнять;
постр.ЗаполнитьНастройки();
Для каждого рПоле Из постр.ДоступныеПоля Цикл
кол=тДанных.Колонки.Найти(СокрЛП(рПоле.ПутьКДанным));
Если кол<>Неопределено и не ПустаяСтрока(кол.Заголовок) Тогда
рПоле.Представление=кол.Заголовок;
Иначе
рПоле.Представление=ПревращениеИмениВНаименование(рПоле.ПутьКДанным);
КонецЕсли;
КонецЦикла;
Для каждого рПоле Из постр.ВыбранныеПоля Цикл
кол=тДанных.Колонки.Найти(СокрЛП(рПоле.ПутьКДанным));
Если кол<>Неопределено и не ПустаяСтрока(кол.Заголовок) Тогда
рПоле.Представление=кол.Заголовок;
Иначе
рПоле.Представление=ПревращениеИмениВНаименование(рПоле.ПутьКДанным);
КонецЕсли;
КонецЦикла;
постр.ВыводитьЗаголовокОтчета=Истина;
постр.ОтображатьСостояние=Истина;
постр.ТекстЗаголовка=рЗаголовок;
постр.ВыводитьОбщиеИтоги=Истина;
постр.Выполнить();
#Если Клиент Тогда
постр.МакетОформления=ПолучитьМакетОформления(СтандартноеОформление.Асфальт);
постр.ОформитьМакет();
#КонецЕсли
постр.Вывести(т);
т.ОтображатьЗаголовки=Ложь;
т.ОтображатьСетку=Ложь;
т.ТолькоПросмотр=Истина;
Возврат т;
Исключение
Сообщить("ВывестиТаблицуЗначенийВМакет, ошибка: "+ОписаниеОшибки(),СтатусСообщения.Важное);
Возврат т;
КонецПопытки;
КонецФункции
// Помещает таблицу значений любого вида в запрос как временную с указанным именем-синонимом
Функция ПоместитьТаблицуЗначенийВоВременную(рЗапрос,тДанных,рСинонимВЗапросе) Экспорт
Попытка
Если ПустаяСтрока(рСинонимВЗапросе) Тогда Возврат Ложь КонецЕсли;
тз="ВЫБРАТЬ";
Для каждого кол Из тДанных.Колонки Цикл
рЕстьПодходящиеТипы=Ложь;
Для каждого рТипКолонки Из кол.ТипЗначения.Типы() Цикл
Если рТипКолонки=Null или рТипКолонки=Тип("Null") Тогда Продолжить КонецЕсли;
Если рТипКолонки=Тип("Массив") или рТипКолонки=Тип("СписокЗначений")
или рТипКолонки=Тип("ТаблицаЗначений") или рТипКолонки=Тип("ДеревоЗначений")
или рТипКолонки=Тип("ХранилищеЗначения") или рТипКолонки=Тип("ДвоичныеДанные")
или рТипКолонки=Тип("Неопределено") или рТипКолонки=Неопределено
Тогда Продолжить КонецЕсли;
рЕстьПодходящиеТипы=Истина; // остальные типы можно
КонецЦикла;
Если рЕстьПодходящиеТипы Тогда // эту колонку имеет смысл внести
тз=тз+"
| SourceTable."+СокрЛП(кол.Имя)+" КАК "+СокрЛП(кол.Имя)+",";
Иначе
// можно и сообщить, в принципе
КонецЕсли;
КонецЦикла;
Если СтрЧислоСтрок(тз)=1 Тогда
Сообщить("Во временную таблицу с именем """+СокрЛП(рСинонимВЗапросе)+""" не может быть внесено никаких данных! Пожалуйста, сообщите программисту 1С!",СтатусСообщения.Важное);
Возврат Ложь;
КонецЕсли;
Если Прав(тз,1)="," Тогда тз=Лев(тз,СтрДлина(тз)-1) КонецЕсли;
тз=тз+"
|ПОМЕСТИТЬ "+СокрЛП(рСинонимВЗапросе)+"
|ИЗ &УслТаблица КАК SourceTable";
рЗапрос.Текст=тз;
рЗапрос.УстановитьПараметр("УслТаблица",тДанных);
рЗапрос.Выполнить();
Возврат Истина;
Исключение
Сообщить("ПоместитьТаблицуЗначенийВоВременную: ошибка, "+ОписаниеОшибки(),СтатусСообщения.Важное);
Возврат Ложь;
КонецПопытки;
КонецФункции
#КонецОбласти
#Область РаботаССКД
// Возвращает булево - есть ли отборы СКД
Функция ЕстьОтборыСКД(рОткуда) Экспорт
Если ТипЗнч(рОткуда)=Тип("ОтборКомпоновкиДанных") или ТипЗнч(рОткуда)=Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
обрОткуда=рОткуда;
ИначеЕсли ТипЗнч(рОткуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрОткуда=рОткуда.Настройки.Отбор;
Иначе
Возврат Ложь;
КонецЕсли;
Для каждого отб Из обрОткуда.Элементы Цикл
Если отб.Использование Тогда Возврат Истина КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
// Вносит элемент отбора в отбор СКД и возвращает его
Функция ДобавитьЭлементОтбора(рКуда,рПоле,рЗначение=Неопределено,рВидСравнения=Неопределено,рИскатьИмеющийся=Ложь) Экспорт
Попытка
рПустышка=Неопределено;
Если не ЗначениеЗаполнено(рВидСравнения) Тогда
рВидСравнения=ВидСравненияКомпоновкиДанных.Равно;
КонецЕсли;
//
Если ТипЗнч(рПоле)=Тип("Строка") Тогда
обрПоле=Новый ПолеКомпоновкиДанных(СокрЛП(рПоле));
ИначеЕсли ТипЗнч(рПоле)=Тип("ПолеКомпоновкиДанных") Тогда
обрПоле=рПоле;
Иначе
Возврат рПустышка;
КонецЕсли;
//
Если ТипЗнч(рКуда)=Тип("ОтборКомпоновкиДанных") или ТипЗнч(рКуда)=Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
обрКуда=рКуда.Элементы;
ИначеЕсли ТипЗнч(рКуда)=Тип("НастройкиКомпоновкиДанных") Тогда
обрКуда=рКуда.Отбор.Элементы;
ИначеЕсли ТипЗнч(рКуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрКуда=рКуда.Настройки.Отбор.Элементы;
Иначе
Возврат рПустышка;
КонецЕсли;
эл=Неопределено;
Если рИскатьИмеющийся Тогда
эл=ПолучитьОтборСКД(обрКуда,обрПоле,Истина);
КонецЕсли;
Если эл=Неопределено Тогда
эл=обрКуда.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
эл.ЛевоеЗначение=обрПоле;
КонецЕсли;
эл.ВидСравнения=рВидСравнения;
эл.ПравоеЗначение=рЗначение;
эл.Использование=Истина;
//
Возврат эл;
Исключение
Сообщить("ДобавитьЭлементОтбора, ошибка: "+ОписаниеОшибки(),СтатусСообщения.Важное);
Возврат рПустышка;
КонецПопытки;
КонецФункции
// Ищет среди всей иерархии отборов Компоновщика элемент с ПолемСКД (ЛевоеЗначение), равным указанному, или
// ищет группу по её типу и имени (в этом случае рПолеСКДилиИмяТипГруппы это структура: ИмяГруппы, ТипГруппы)
// Если не нашёл, возвращает Неопределено.
Функция ПолучитьОтборСКД(рКомпоновщикИлиОтбор,рУсловие,рИскатьРекурсивно=Истина) Экспорт
Если ТипЗнч(рКомпоновщикИлиОтбор)=Тип("ОтборКомпоновкиДанных") или ТипЗнч(рКомпоновщикИлиОтбор)=Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
обрОткуда=рКомпоновщикИлиОтбор.Элементы;
ИначеЕсли ТипЗнч(рКомпоновщикИлиОтбор)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрОткуда=рКомпоновщикИлиОтбор.Настройки.Отбор.Элементы;
ИначеЕсли ТипЗнч(рКомпоновщикИлиОтбор)=Тип("КоллекцияЭлементовОтбораКомпоновкиДанных") Тогда
обрОткуда=рКомпоновщикИлиОтбор;
ИначеЕсли ТипЗнч(рКомпоновщикИлиОтбор)=Тип("ПользовательскиеНастройкиКомпоновкиДанных") Тогда
обрОткуда=рКомпоновщикИлиОтбор.Элементы;
Иначе
Возврат Неопределено;
КонецЕсли;
Если ТипЗнч(рУсловие)=Тип("ПолеКомпоновкиДанных") Тогда
рРежимПоиска="ЛевоеЗначение";
ИначеЕсли ТипЗнч(рУсловие)=Тип("Тип") Тогда
рРежимПоиска="ТипРавенТипу";
ИначеЕсли ТипЗнч(рУсловие)=Тип("ОписаниеТипов") Тогда
рРежимПоиска="ТипВОписанииТипов";
ИначеЕсли ТипЗнч(рУсловие)=Тип("Структура") Тогда
рРежимПоиска="Группа";
Иначе
Возврат Неопределено;
КонецЕсли;
//
Для каждого элотб Из обрОткуда Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
рТип=ТипЗнч(элотб);
Если рТип=Тип("ЭлементОтбораКомпоновкиДанных") Тогда
Если (рРежимПоиска="ЛевоеЗначение" и элотб.ЛевоеЗначение=рУсловие)
или (рРежимПоиска="ТипРавенТипу" и ТипЗнч(элотб.ПравоеЗначение)=рУсловие)
или (рРежимПоиска="ТипВОписанииТипов" и рУсловие.СодержитТип(ТипЗнч(элотб.ПравоеЗначение)))
Тогда // ПолеКомпоновки, или Тип нужного значения, или ОписаниеТипов нужного значения
Возврат элотб;
КонецЕсли;
ИначеЕсли рТип=Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
Если рРежимПоиска="Группа"
и СокрЛП(элотб.Представление)=СокрЛП(рУсловие.ИмяГруппы)
и элотб.ТипГруппы=рУсловие.ТипГруппы
Тогда
Возврат элотб;
КонецЕсли;
Если рИскатьРекурсивно Тогда // идём глубже
Возврат ПолучитьОтборСКД(элотб,рУсловие);
КонецЕсли;
КонецЕсли;
КонецЦикла;
//
Возврат Неопределено;
КонецФункции
// Получает отбор из пользовательских настроек
Функция ПолучитьПользовательскийОтбор(рКомпоновщик) Экспорт
Попытка
рОтбор=Неопределено;
Для каждого эл Из рКомпоновщик.ПользовательскиеНастройки.Элементы Цикл
Если ТипЗнч(эл)=Тип("ОтборКомпоновкиДанных") Тогда рОтбор=эл; Прервать КонецЕсли;
КонецЦикла;
Если рОтбор=Неопределено Тогда
рОтбор=рКомпоновщик.ПользовательскиеНастройки.Элементы.Добавить(Тип("ОтборКомпоновкиДанных"));
КонецЕсли;
Возврат рОтбор;
Исключение
Сообщить("ПолучитьПользовательскийОтбор, общая ошибка: "+ОписаниеОшибки(),СтатусСообщения.Важное);
Возврат Неопределено;
КонецПопытки;
КонецФункции
// Возвращает "красивое" и читабельное представление отбора одной строкой
Функция ПредставлениеОтбораСКД(отб) Экспорт
Попытка
Если ТипЗнч(отб)=Тип("ЭлементОтбораКомпоновкиДанных") Тогда
предст=СокрЛП(отб.Представление);
предст=предст+?(ПустаяСтрока(предст),""," (")+СокрЛП(отб.ЛевоеЗначение)+" "+СокрЛП(НРег(отб.ВидСравнения))+" "+СокрЛП(отб.ПравоеЗначение)+?(ПустаяСтрока(предст),""," )");
ИначеЕсли ТипЗнч(отб)=Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
предст=""""+СокрЛП(Строка(отб.ТипГруппы))+"""";
КонецЕсли;
предст=предст+?(ПустаяСтрока(предст),"("," (")+СокрЛП(отб.Применение)+")";
предст=?(отб.Использование,"[V] ","[ ] ")+предст;
Возврат предст;
Исключение
Сообщить("Ошибка при построении представления отбора СКД: "+ОписаниеОшибки(),СтатусСообщения.Внимание);
Возврат "<!!!>";
КонецПопытки;
КонецФункции
Процедура КопироватьОтборПостроителяВОтборСКД(рОткуда,рКуда,рТолькоИспользуемые=Ложь) Экспорт
Попытка
Если ТипЗнч(рОткуда)=Тип("ПостроительОтчета") или ТипЗнч(рОткуда)=Тип("ПостроительЗапроса") Тогда
рОтправитель=рОткуда.Отбор;
ИначеЕсли ТипЗнч(рОткуда)=Тип("Отбор") или ТипЗнч(рОткуда)=Тип("ТаблицаЗначений") Тогда
рОтправитель=рОткуда;
ИначеЕсли ТипЗнч(рОткуда)=Тип("Структура") Тогда
рОтправитель=Новый Массив;
рОтправитель.Добавить(рОткуда);
Иначе
Сообщить("КопироватьОтборПостроителяВОтборСКД: передан аргумент-источник недопустимого типа, отбор не копируется!",СтатусСообщения.Важное);
Возврат;
КонецЕсли;
Если ТипЗнч(рКуда)=Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
обрКуда=рКуда;
ИначеЕсли ТипЗнч(рКуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрКуда=рКуда.Настройки.Отбор;
Иначе
Сообщить("КопироватьОтборПостроителяВОтборСКД: передан аргумент-получатель недопустимого типа, отбор не копируется!",СтатусСообщения.Важное);
Возврат;
КонецЕсли;
//
Если рОтправитель.Количество()=0 Тогда
Сообщить("КопироватьОтборПостроителяВОтборСКД: отбор пуст и не копируется.",СтатусСообщения.Информация);
Возврат;
КонецЕсли;
//
соотСравнений=Новый Соответствие;
соотСравнений.Вставить(ВидСравнения.Больше,ВидСравненияКомпоновкиДанных.Больше);
соотСравнений.Вставить(ВидСравнения.БольшеИлиРавно,ВидСравненияКомпоновкиДанных.БольшеИлиРавно);
соотСравнений.Вставить(ВидСравнения.ВИерархии,ВидСравненияКомпоновкиДанных.ВИерархии);
соотСравнений.Вставить(ВидСравнения.ВСписке,ВидСравненияКомпоновкиДанных.ВСписке);
соотСравнений.Вставить(ВидСравнения.ВСпискеПоИерархии,ВидСравненияКомпоновкиДанных.ВСпискеПоИерархии);
соотСравнений.Вставить(ВидСравнения.Меньше,ВидСравненияКомпоновкиДанных.Меньше);
соотСравнений.Вставить(ВидСравнения.МеньшеИлиРавно,ВидСравненияКомпоновкиДанных.МеньшеИлиРавно);
соотСравнений.Вставить(ВидСравнения.НеВИерархии,ВидСравненияКомпоновкиДанных.НеВИерархии);
соотСравнений.Вставить(ВидСравнения.НеВСписке,ВидСравненияКомпоновкиДанных.НеВСписке);
соотСравнений.Вставить(ВидСравнения.НеВСпискеПоИерархии,ВидСравненияКомпоновкиДанных.НеВСпискеПоИерархии);
соотСравнений.Вставить(ВидСравнения.НеРавно,ВидСравненияКомпоновкиДанных.НеРавно);
соотСравнений.Вставить(ВидСравнения.НеСодержит,ВидСравненияКомпоновкиДанных.НеСодержит);
соотСравнений.Вставить(ВидСравнения.Равно,ВидСравненияКомпоновкиДанных.Равно);
соотСравнений.Вставить(ВидСравнения.Содержит,ВидСравненияКомпоновкиДанных.Содержит);
// копируем всё в одну группу "И" старшего уровня
рГруппа=обрКуда.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
рГруппа.ТипГруппы=ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;
рЕстьИспользуемые=Ложь;
Для каждого отб Из рОтправитель Цикл
Если рТолькоИспользуемые и не отб.Использование Тогда Продолжить КонецЕсли;
Если отб.ВидСравнения=ВидСравнения.Интервал
или отб.ВидСравнения=ВидСравнения.ИнтервалВключаяГраницы
или отб.ВидСравнения=ВидСравнения.ИнтервалВключаяНачало
или отб.ВидСравнения=ВидСравнения.ИнтервалВключаяОкончание
Тогда // надо задать диапазон
Если отб.ВидСравнения=ВидСравнения.Интервал Тогда
вс1=ВидСравненияКомпоновкиДанных.Больше;
вс2=ВидСравненияКомпоновкиДанных.Меньше;
ИначеЕсли отб.ВидСравнения=ВидСравнения.ИнтервалВключаяГраницы Тогда
вс1=ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
вс2=ВидСравненияКомпоновкиДанных.МеньшеИлиРавно;
ИначеЕсли отб.ВидСравнения=ВидСравнения.ИнтервалВключаяНачало Тогда
вс1=ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
вс2=ВидСравненияКомпоновкиДанных.Меньше;
ИначеЕсли отб.ВидСравнения=ВидСравнения.ИнтервалВключаяОкончание Тогда
вс1=ВидСравненияКомпоновкиДанных.Больше;
вс2=ВидСравненияКомпоновкиДанных.МеньшеИлиРавно;
КонецЕсли;
// для диапазона своя подгруппа
рПодгруппа=рГруппа.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
рПодгруппа.ТипГруппы=ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;
рПодгруппа.Использование=отб.Использование;
рПодгруппа.Представление=СокрЛП(Строка(отб.ВидСравнения))+" ("+СокрЛП(отб.ЗначениеС)+" "+ПревращениеИмениВНаименование(отб.ПутьКДанным)+" "+СокрЛП(отб.ЗначениеПо)+")";
новотб=рПодгруппа.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
новотб.Использование=отб.Использование;
новотб.ВидСравнения=вс1;
новотб.ЛевоеЗначение=Новый ПолеКомпоновкиДанных(СокрЛП(отб.ПутьКДанным));
новотб.ПравоеЗначение=отб.ЗначениеС;
новотб=рПодгруппа.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
новотб.Использование=отб.Использование;
новотб.ВидСравнения=вс2;
новотб.ЛевоеЗначение=Новый ПолеКомпоновкиДанных(СокрЛП(отб.ПутьКДанным));
новотб.ПравоеЗначение=отб.ЗначениеПо;
Иначе
// обычное значение, не диапазонное
вс=соотСравнений.Получить(отб.ВидСравнения);
Если вс=Неопределено Тогда
Сообщить("КопироватьОтборПостроителяВОтборСКД: для отбора """+СокрЛП(отб.Представление)+" не найдено соответствие вида сравнения """+Строка(отб.ВидСравнения)+""", элемент отбора не копируется!",СтатусСообщения.Внимание);
Продолжить;
КонецЕсли;
новотб=рГруппа.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
новотб.Использование=отб.Использование;
новотб.ВидСравнения=вс;
новотб.ЛевоеЗначение=Новый ПолеКомпоновкиДанных(СокрЛП(отб.ПутьКДанным));
новотб.Представление=ПревращениеИмениВНаименование(новотб.ЛевоеЗначение)+" "+СокрЛП(отб.ВидСравнения)+" """+СокрЛП(Строка(отб.Значение))+"""";
новотб.ПравоеЗначение=отб.Значение;
КонецЕсли;
Если отб.Использование Тогда рЕстьИспользуемые=Истина КонецЕсли;
КонецЦикла;
Если рЕстьИспользуемые Тогда // имеет смысл включить эту группу
рГруппа.Использование=Истина;
КонецЕсли;
Исключение
Сообщить("КопироватьОтборПостроителяВОтборСКД: ошибка: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
КонецПопытки;
КонецПроцедуры
Процедура КопироватьОтборСКД(рОткуда,рКуда,рТолькоИспользуемые=Ложь,рОбщийПуть="") Экспорт
Если ТипЗнч(рОткуда)=Тип("ОтборКомпоновкиДанных") или ТипЗнч(рОткуда)=Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
обрОткуда=рОткуда;
ИначеЕсли ТипЗнч(рОткуда)=Тип("НастройкиКомпоновкиДанных") Тогда
обрОткуда=рОткуда.Отбор;
ИначеЕсли ТипЗнч(рОткуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрОткуда=рОткуда.Настройки.Отбор;
Иначе
Возврат;
КонецЕсли;
Если ТипЗнч(рКуда)=Тип("ОтборКомпоновкиДанных") или ТипЗнч(рКуда)=Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
обрКуда=рКуда;
ИначеЕсли ТипЗнч(рКуда)=Тип("НастройкиКомпоновкиДанных") Тогда
обрКуда=рКуда.Отбор;
ИначеЕсли ТипЗнч(рКуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрКуда=рКуда.Настройки.Отбор;
Иначе
Возврат;
КонецЕсли;
// идём по энному уровню
Для каждого отб Из обрОткуда.Элементы Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
Если не отб.Использование и рТолькоИспользуемые Тогда
//сообщить("пропустили мимо "+представлениеотбораскд(отб));
Продолжить
КонецЕсли;
рТип=ТипЗнч(отб);
Попытка
новотб=обрКуда.Элементы.Добавить(рТип);
новотб.Представление=отб.Представление;
новотб.Применение=отб.Применение;
новотб.Использование=Истина;
Если рТип=Тип("ЭлементОтбораКомпоновкиДанных") Тогда
Если не ПустаяСтрока(рОбщийПуть) Тогда
новотб.ЛевоеЗначение=Новый ПолеКомпоновкиДанных(СокрЛП(рОбщийПуть)+СокрЛП(Строка(отб.ЛевоеЗначение)));
Иначе
новотб.ЛевоеЗначение=отб.ЛевоеЗначение;
КонецЕсли;
новотб.ВидСравнения=отб.ВидСравнения;
новотб.ПравоеЗначение=отб.ПравоеЗначение;
ИначеЕсли рТип=Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
новотб.ТипГруппы=отб.ТипГруппы;
КопироватьОтборСКД(отб,новотб,рТолькоИспользуемые);
КонецЕсли;
Исключение
Сообщить("Ошибка при копировании отбора "+ПредставлениеОтбораСКД(отб)+": "+ОписаниеОшибки(),СтатусСообщения.Важное);
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Процедура КопироватьПараметрыСКД(рОткуда,рКуда,рТолькоИспользуемые=Ложь) Экспорт
Если ТипЗнч(рОткуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрОткуда=рОткуда.Настройки.ПараметрыДанных.Элементы;
ИначеЕсли ТипЗнч(рОткуда)=Тип("НастройкиКомпоновкиДанных") Тогда
обрОткуда=рОткуда.ПараметрыДанных.Элементы;
ИначеЕсли ТипЗнч(рОткуда)=Тип("ЗначенияПараметровДанныхКомпоновкиДанных") Тогда
обрОткуда=рОткуда.Элементы;
Иначе
Возврат;
КонецЕсли;
Если обрОткуда.Количество()=0 Тогда Возврат КонецЕсли;
Если ТипЗнч(рКуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрКуда=рКуда.Настройки.ПараметрыДанных;
ИначеЕсли ТипЗнч(рКуда)=Тип("НастройкиКомпоновкиДанных") Тогда
обрКуда=рКуда.ПараметрыДанных;
ИначеЕсли ТипЗнч(рКуда)=Тип("ЗначенияПараметровДанныхКомпоновкиДанных") Тогда
обрКуда=рКуда;
Иначе
Возврат;
КонецЕсли;
//
Для каждого рПараметр Из обрОткуда Цикл
Если не рПараметр.Использование и рТолькоИспользуемые Тогда Продолжить КонецЕсли;
Попытка
обрКуда.УстановитьЗначениеПараметра(рПараметр.Параметр,рПараметр.Значение);
Исключение
//Сообщить("КопироватьПараметрыСКД, ошибка копирования параметра "+СокрЛП(рПараметр.Параметр)+": "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Процедура КопироватьПорядокСКД(рОткуда,рКуда,рТолькоИспользуемые=Ложь) Экспорт
Если ТипЗнч(рОткуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрОткуда=рОткуда.Настройки.Порядок.Элементы;
ИначеЕсли ТипЗнч(рОткуда)=Тип("НастройкиКомпоновкиДанных") Тогда
обрОткуда=рОткуда.Порядок.Элементы;
ИначеЕсли ТипЗнч(рОткуда)=Тип("ПорядокКомпоновкиДанных") Тогда
обрОткуда=рОткуда.Элементы;
Иначе
Возврат;
КонецЕсли;
Если обрОткуда.Количество()=0 Тогда Возврат КонецЕсли;
Если ТипЗнч(рКуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрКуда=рКуда.Настройки.Порядок.Элементы;
ИначеЕсли ТипЗнч(рКуда)=Тип("НастройкиКомпоновкиДанных") Тогда
обрКуда=рКуда.Порядок.Элементы;
ИначеЕсли ТипЗнч(рКуда)=Тип("ПорядокКомпоновкиДанных") Тогда
обрКуда=рКуда.Элементы;
Иначе
Возврат;
КонецЕсли;
//
Для каждого рПоле Из обрОткуда Цикл
Если не рПоле.Использование и рТолькоИспользуемые Тогда Продолжить КонецЕсли;
элпор=обрКуда.Добавить(ТипЗнч(рПоле));
ЗаполнитьЗначенияСвойств(элпор,рПоле);
КонецЦикла;
КонецПроцедуры
Процедура КопироватьУсловноеОформлениеСКД(рОткуда,рКуда,рТолькоИспользуемые=Ложь) Экспорт
Если ТипЗнч(рОткуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрОткуда=рОткуда.Настройки.УсловноеОформление.Элементы;
ИначеЕсли ТипЗнч(рОткуда)=Тип("УсловноеОформлениеКомпоновкиДанных") Тогда
обрОткуда=рОткуда.Элементы;
Иначе
Возврат;
КонецЕсли;
Если обрОткуда.Количество()=0 Тогда Возврат КонецЕсли;
Если ТипЗнч(рКуда)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
обрКуда=рКуда.Настройки.УсловноеОформление.Элементы;
ИначеЕсли ТипЗнч(рКуда)=Тип("УсловноеОформлениеКомпоновкиДанных") Тогда
обрКуда=рКуда.Элементы;
Иначе
Возврат;
КонецЕсли;
//
Для каждого рЭУ Из обрОткуда Цикл
Если не рЭУ.Использование и рТолькоИспользуемые Тогда Продолжить КонецЕсли;
новэу=обрКуда.Добавить();
ЗаполнитьЗначенияСвойств(новэу,рЭУ);
Для каждого эуо Из рЭУ.Оформление.Элементы Цикл
Если эуо.Использование Тогда
новэу.Оформление.УстановитьЗначениеПараметра(эуо.Параметр,эуо.Значение);
КонецЕсли;
КонецЦикла;
Для каждого пэу Из рЭУ.Поля.Элементы Цикл
Если пэу.Использование Тогда
ЗаполнитьЗначенияСвойств(новэу.Поля.Элементы.Добавить(),пэу);
КонецЕсли;
КонецЦикла;
КопироватьОтборСКД(рЭУ.Отбор,новэу.Отбор);
КонецЦикла;
КонецПроцедуры
// Получает значение параметра, установленное в интерфейсе (в т.ч. быстром выборе) пользовательских настроек
Функция ПолучитьПользовательскийПараметр(рКомпНастроекИлиНастройки,рИмя,рТолькоИспользуемые=Истина,рТипЗначения=Неопределено)
Попытка
Если ТипЗнч(рКомпНастроекИлиНастройки)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
рОткуда=рКомпНастроекИлиНастройки.ПользовательскиеНастройки;
ИначеЕсли ТипЗнч(рКомпНастроекИлиНастройки)=Тип("ПользовательскиеНастройкиКомпоновкиДанных") Тогда
рОткуда=рКомпНастроекИлиНастройки;
Иначе
Возврат Неопределено;
КонецЕсли;
//
рПараметр=Новый ПараметрКомпоновкиДанных(рИмя);
Для каждого эл Из рОткуда.Элементы Цикл
Если ТипЗнч(эл)=Тип("ЗначениеПараметраНастроекКомпоновкиДанных") и эл.Параметр=рПараметр Тогда
Если рТипЗначения<>Неопределено и ТипЗнч(эл.Значение)<>рТипЗначения Тогда Продолжить КонецЕсли;
Если рТолькоИспользуемые и не эл.Использование Тогда Продолжить КонецЕсли;
Возврат эл.Значение;
КонецЕсли;
КонецЦикла;
//
Возврат Неопределено;
Исключение
Сообщить("ПолучитьПользовательскийПараметр, ошибка: "+ОписаниеОшибки(),СтатусСообщения.Важное);
Возврат Неопределено;
КонецПопытки;
КонецФункции
Процедура УстановитьПараметрСКД(рКомпоновщикНастроек,рИмяПараметра,рЗначениеПараметра) Экспорт
Если ПустаяСтрока(рИмяПараметра) Тогда Возврат КонецЕсли;
Для каждого рПараметр Из рКомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы Цикл
Если СокрЛП(рПараметр.Параметр)<>СокрЛП(рИмяПараметра) Тогда Продолжить КонецЕсли;
рПараметр.Значение=рЗначениеПараметра;
рПараметр.Использование=Истина;
Прервать;
КонецЦикла;
КонецПроцедуры
// Собственно инициализирует схему СКД, заполняет источник, набор, структуру, возвращает СКД
Функция СоздатьСКД(рИсточник,рПоляНабора=Истина,рИмяОформления="",рАвтопредставлениеПолей=Истина,рИмяТЗ="",рАвтозаполнение=Истина) Экспорт
Попытка
рСКД=Новый СхемаКомпоновкиДанных;
//
рИсточникДанных=рСКД.ИсточникиДанных.Добавить();
рИсточникДанных.Имя="ОсновнойИсточник";
рИсточникДанных.ТипИсточникаДанных="Local";
//
Если ТипЗнч(рИсточник)=Тип("Строка") или ТипЗнч(рИсточник)=Тип("Запрос") Тогда
рНабор=рСКД.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
рНабор.Имя="ОсновнойНабор";
рНабор.Запрос=?(ТипЗнч(рИсточник)=Тип("Строка"),рИсточник,рИсточник.Текст);
рНабор.ИсточникДанных="ОсновнойИсточник";
режИсточника=1;
рНабор.АвтоЗаполнениеДоступныхПолей=рАвтозаполнение;
ИначеЕсли ТипЗнч(рИсточник)=Тип("ТаблицаЗначений") или ТипЗнч(рИсточник)=Тип("ДеревоЗначений") Тогда
рНабор=рСКД.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
рНабор.Имя="ОсновнойНабор";
рНабор.ИмяОбъекта=?(ПустаяСтрока(рИмяТЗ),"ТаблицаИсточник",СокрЛП(рИмяТЗ)); // связывание с внешними данными идёт именно по нему
рНабор.ИсточникДанных="ОсновнойИсточник";
режИсточника=2;
Иначе
Сообщить("В функцию создания СКД передан неверный источник типа "+ТипЗнч(рИсточник)+", СКД не создаётся!",СтатусСообщения.Важное);
Возврат Неопределено;
КонецЕсли;
//
рНастройка=рСКД.НастройкиПоУмолчанию;
// создадим группировку <детальных записей>
рГруппировкаКД=рНастройка.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
рГруппировкаКД.Использование=Истина;
// автовыбранные поля на уровень группировки детальных записей
рВыбПолеГр=рГруппировкаКД.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
рВыбПолеГр.Использование=Истина;
//
тКолонок=Новый ТаблицаЗначений;
тКолонок.Колонки.Добавить("Имя");
тКолонок.Колонки.Добавить("ТипЗначения");
тКолонок.Колонки.Добавить("Заголовок");
//
Если рПоляНабора Тогда // если надо вносить поля набора
Если режИсточника=1 Тогда // строка или запрос
Если рАвтозаполнение Тогда
постр=Новый ПостроительЗапроса;
Если ТипЗнч(рИсточник)=Тип("Строка") Тогда
постр.Текст=СокрЛП(рИсточник);
Иначе // запрос
постр.Текст=СокрЛП(рИсточник.Текст);
КонецЕсли;
постр.ЗаполнитьНастройки();
// есть определённая натяжка, что часть полей может оказаться недоступна для отбора, но пока делаем так
Для каждого рПоле Из постр.Отбор.ПолучитьДоступныеПоля() Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
строкол=тКолонок.Добавить();
строкол.Имя=рПоле.Имя;
строкол.ТипЗначения=рПоле.ТипЗначения;
строкол.Заголовок=СокрЛП(ПревращениеИмениВНаименование(рПоле.Имя)); // хотя можно и рПоле.Представление
КонецЦикла;
Иначе
схз=Новый СхемаЗапроса;
Если ТипЗнч(рИсточник)=Тип("Строка") Тогда
схз.УстановитьТекстЗапроса(СокрЛП(рИсточник));
Иначе // запрос
схз.УстановитьТекстЗапроса(СокрЛП(рИсточник.Текст));
КонецЕсли;
рПоследний=схз.ПакетЗапросов.Получить(схз.ПакетЗапросов.Количество()-1);
Для каждого рПоле Из рПоследний.Колонки Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
строкол=тКолонок.Добавить();
строкол.Имя=рПоле.Псевдоним;
строкол.ТипЗначения=рПоле.ТипЗначения;
строкол.Заголовок=СокрЛП(ПревращениеИмениВНаименование(рПоле.Псевдоним));
КонецЦикла;
КонецЕсли;
//
ИначеЕсли режИсточника=2 Тогда // таблица или дерево значений
Для каждого кол Из рИсточник.Колонки Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
строкол=тКолонок.Добавить();
строкол.Имя=кол.Имя;
строкол.ТипЗначения=кол.ТипЗначения;
Если рАвтопредставлениеПолей Тогда
строкол.Заголовок=СокрЛП(ПревращениеИмениВНаименование(кол.Имя));
Иначе
строкол.Заголовок=кол.Заголовок;
КонецЕсли;
КонецЦикла;
//
КонецЕсли;
КонецЕсли;
//
рТипПоляНабора=Тип("ПолеНабораДанныхСхемыКомпоновкиДанных");
рТипПоляНастройки=Тип("ВыбранноеПолеКомпоновкиДанных");
Для каждого строкол Из тКолонок Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
// вносим поля в набор, это обязательно
рПоле=рНабор.Поля.Добавить(рТипПоляНабора);
рПоле.Заголовок=СокрЛП(строкол.Заголовок);
рПоле.Поле=СокрЛП(строкол.Имя);
рПоле.ПутьКДанным=СокрЛП(строкол.Имя);
рПоле.ТипЗначения=ПолучитьОписаниеТипаБезПустых(строкол.ТипЗначения);
// выбранные поля добавляем на уровень самой настройки, т.е. группы "Отчёт"
рВыбПоле=рНастройка.Выбор.Элементы.Добавить(рТипПоляНастройки);
рВыбПоле.Заголовок=рПоле.Заголовок;
рВыбПоле.Поле=Новый ПолеКомпоновкиДанных(рПоле.ПутьКДанным);
рВыбПоле.Использование=Истина;
КонецЦикла;
// добавляем оформление, если надо
Если не ПустаяСтрока(рИмяОформления) Тогда
пар=рНастройка.ПараметрыВывода.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("МакетОформления"));
пар.Значение=рИмяОформления;
пар.Использование=Истина;
КонецЕсли;
//
Возврат рСКД;
Исключение
Сообщить("Ошибка при создании СКД: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
Возврат Неопределено;
КонецПопытки;
КонецФункции
// Вспомогательная к ИнициализироватьПроцессорКД, раскрывает набор-объединение рекурсивно
Процедура ПолучитьИменаОбъектовИзНаборов(рНабор,мИмён)
Если ТипЗнч(рНабор)=Тип("НаборДанныхОбъектСхемыКомпоновкиДанных") Тогда
Если мИмён.Найти(рНабор.ИмяОбъекта)=Неопределено Тогда мИмён.Добавить(рНабор.ИмяОбъекта) КонецЕсли;
ИначеЕсли ТипЗнч(рНабор)=Тип("НаборДанныхОбъединениеСхемыКомпоновкиДанных") Тогда
Для каждого рПоднабор Из рНабор.Элементы Цикл
ПолучитьИменаОбъектовИзНаборов(рПоднабор,мИмён);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
// Вспомогательная к "помещениям в"; возвращает успешность
Функция ИнициализироватьПроцессорКД(рПроцессорКД,Знач рНабор,рМакетКомпоновки,рИсточник,рРасшифровка,рВнешние=Истина)
Если ТипЗнч(рНабор)=Тип("НаборДанныхЗапросСхемыКомпоновкиДанных") Тогда
рПроцессорКД.Инициализировать(рМакетКомпоновки,,рРасшифровка,рВнешние);
//
ИначеЕсли ТипЗнч(рНабор)=Тип("НаборДанныхОбъектСхемыКомпоновкиДанных") Тогда
рИмяОбъекта=СокрЛП(рНабор.ИмяОбъекта);
Если ТипЗнч(рИсточник)=Тип("Структура") Тогда // передана структура, где имя объекта - ключ, а значение объекта - значение
// в этом случае ключи структуры должны совпадать с именами объектов, как они указаны в наборах
Попытка знчИсточник=рИсточник[рИмяОбъекта] Исключение знчИсточник=Неопределено КонецПопытки;
Если знчИсточник<>Неопределено Тогда
рПроцессорКД.Инициализировать(рМакетКомпоновки,Новый Структура(рИмяОбъекта,знчИсточник),рРасшифровка,рВнешние);
Иначе
Сообщить("ИнициализироватьПроцессорКД: для набора СКД типа ""Объект"" для имени """+рИмяОбъекта+""" не указаны или неверно указаны данные объекта-источника!",СтатусСообщения.Важное);
Возврат Ложь;
КонецЕсли;
Иначе // передан собственно источник (обычно таблица значений)
рПроцессорКД.Инициализировать(рМакетКомпоновки,Новый Структура(рИмяОбъекта,рИсточник),рРасшифровка,рВнешние);
КонецЕсли;
//
ИначеЕсли ТипЗнч(рНабор)=Тип("НаборДанныхОбъединениеСхемыКомпоновкиДанных") Тогда
// в этом случае источник может быть только структурой, чьи ключи должны совпадать с именами объектов, как они указаны в наборах
мИмён=Новый Массив;
ПолучитьИменаОбъектовИзНаборов(рНабор,мИмён);
Если мИмён.Количество()>0 Тогда // в составе этого набора-объединения есть поднаборы-объекты, их имена должны быть в структуре
Если ТипЗнч(рИсточник)=Тип("Структура") Тогда
рЕстьВсе=Истина;
Для каждого рИмя Из мИмён Цикл
Если не рИсточник.Свойство(рИмя) Тогда рЕстьВсе=Ложь; Прервать КонецЕсли;
КонецЦикла;
Если рЕстьВсе Тогда // и только тогда! передаём структуру всю как источник
рПроцессорКД.Инициализировать(рМакетКомпоновки,рИсточник,рРасшифровка,рВнешние);
Иначе
Сообщить("ИнициализироватьПроцессорКД: для набора СКД типа ""Объединение"" не для всех наборов-объектов указаны данные объекта-источника согласно их именам!",СтатусСообщения.Важное);
Возврат Ложь;
КонецЕсли;
Иначе
Сообщить("ИнициализироватьПроцессорКД: для набора СКД типа ""Объединение"", содержащего наборы-объекты, источник должен быть структурой, чьи ключи совпадают с именами объектов!",СтатусСообщения.Важное);
Возврат Ложь;
КонецЕсли;
КонецЕсли;
//
Иначе
Сообщить("ИнициализироватьПроцессорКД: неизвестный тип набора!",СтатусСообщения.Важное);
Возврат Ложь;
КонецЕсли;
Возврат Истина;
КонецФункции
// рИсточник - собственно объект-источник (обычно таблица значений, её имя определяется автоматически)
Функция ПоместитьРезультатСКДвДеревоЗначений(рСКД,рКомпНастроекИлиНастройки,рИсточник="",рРасшифровка="",рВнешние=Истина) Экспорт
Попытка
РезультатноеДерево=Новый ДеревоЗначений;
//
Если ТипЗнч(рРасшифровка)<>Тип("ДанныеРасшифровкиКомпоновкиДанных") Тогда
рРасшифровка=Новый ДанныеРасшифровкиКомпоновкиДанных;
КонецЕсли;
//
// исходя из типа источника
рНабор=рСКД.НаборыДанных.Получить(0); // основной набор
//
КомпоновщикМакета=Новый КомпоновщикМакетаКомпоновкиДанных;
рТипГенератора=Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений");
Если ТипЗнч(рКомпНастроекИлиНастройки)=Тип("НастройкиКомпоновкиДанных") Тогда
МакетКомпоновки=КомпоновщикМакета.Выполнить(рСКД,рКомпНастроекИлиНастройки,,,рТипГенератора);
ИначеЕсли ТипЗнч(рКомпНастроекИлиНастройки)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
МакетКомпоновки=КомпоновщикМакета.Выполнить(рСКД,рКомпНастроекИлиНастройки.Настройки,,,рТипГенератора);
КонецЕсли;
//
рПроцессорКД=Новый ПроцессорКомпоновкиДанных;
Если не ИнициализироватьПроцессорКД(рПроцессорКД,рНабор,МакетКомпоновки,рИсточник,рРасшифровка,рВнешние) Тогда
Возврат РезультатноеДерево;
КонецЕсли;
//
ПроцессорВывода=Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(РезультатноеДерево);
#Если Клиент Тогда
ПроцессорВывода.ОтображатьПроцентВывода=Истина;
#КонецЕсли
РезультатноеДерево=ПроцессорВывода.Вывести(рПроцессорКД,Истина);
Возврат РезультатноеДерево;
Исключение
Сообщить("ПоместитьРезультатСКДвДеревоЗначений: ошибка: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
Возврат РезультатноеДерево;
КонецПопытки;
КонецФункции
// рИсточник - собственно объект-источник (обычно таблица значений, её имя определяется автоматически)
Функция ПоместитьРезультатСКДвТаблицуЗначений(рСКД,рКомпНастроекИлиНастройки,рИсточник="",рРасшифровка="",рВнешние=Истина) Экспорт
Попытка
РезультатнаяТаблица=Новый ТаблицаЗначений;
//
Если ТипЗнч(рРасшифровка)<>Тип("ДанныеРасшифровкиКомпоновкиДанных") Тогда
рРасшифровка=Новый ДанныеРасшифровкиКомпоновкиДанных;
КонецЕсли;
//
// исходя из типа источника
Если рСКД.НаборыДанных.Количество()=0 Тогда Возврат РезультатнаяТаблица КонецЕсли;
рНабор=рСКД.НаборыДанных.Получить(0); // основной набор
//
КомпоновщикМакета=Новый КомпоновщикМакетаКомпоновкиДанных;
рТипГенератора=Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений");
Если ТипЗнч(рКомпНастроекИлиНастройки)=Тип("НастройкиКомпоновкиДанных") Тогда
МакетКомпоновки=КомпоновщикМакета.Выполнить(рСКД,рКомпНастроекИлиНастройки,,,рТипГенератора);
ИначеЕсли ТипЗнч(рКомпНастроекИлиНастройки)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
МакетКомпоновки=КомпоновщикМакета.Выполнить(рСКД,рКомпНастроекИлиНастройки.Настройки,,,рТипГенератора);
КонецЕсли;
//
рПроцессорКД=Новый ПроцессорКомпоновкиДанных;
Если не ИнициализироватьПроцессорКД(рПроцессорКД,рНабор,МакетКомпоновки,рИсточник,рРасшифровка,рВнешние) Тогда
Возврат РезультатнаяТаблица;
КонецЕсли;
//
ПроцессорВывода=Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(РезультатнаяТаблица);
#Если Клиент Тогда
ПроцессорВывода.ОтображатьПроцентВывода=Истина;
#КонецЕсли
РезультатнаяТаблица=ПроцессорВывода.Вывести(рПроцессорКД,Истина);
Возврат РезультатнаяТаблица;
Исключение
Сообщить("ПоместитьРезультатСКДвТаблицуЗначений: ошибка: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
Возврат РезультатнаяТаблица;
КонецПопытки;
КонецФункции
// рИсточник - собственно объект-источник (обычно таблица значений, её имя определяется автоматически)
Функция ПоместитьРезультатСКДвТабличныйДокумент(рСКД,рКомпНастроекИлиНастройки,рИсточник="",рРасшифровка="",рВнешние=Истина) Экспорт
Попытка
РезультатныйДокумент=Новый ТабличныйДокумент;
//
Если ТипЗнч(рРасшифровка)<>Тип("ДанныеРасшифровкиКомпоновкиДанных") Тогда
рРасшифровка=Новый ДанныеРасшифровкиКомпоновкиДанных;
КонецЕсли;
//
// исходя из типа источника
рНабор=рСКД.НаборыДанных.Получить(0); // основной набор
//
КомпоновщикМакета=Новый КомпоновщикМакетаКомпоновкиДанных;
рТипГенератора=Тип("ГенераторМакетаКомпоновкиДанных");
Если ТипЗнч(рКомпНастроекИлиНастройки)=Тип("НастройкиКомпоновкиДанных") Тогда
МакетКомпоновки=КомпоновщикМакета.Выполнить(рСКД,рКомпНастроекИлиНастройки,рРасшифровка,,рТипГенератора);
ИначеЕсли ТипЗнч(рКомпНастроекИлиНастройки)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
МакетКомпоновки=КомпоновщикМакета.Выполнить(рСКД,рКомпНастроекИлиНастройки.Настройки,рРасшифровка,,рТипГенератора);
КонецЕсли;
//
рПроцессорКД=Новый ПроцессорКомпоновкиДанных;
Если не ИнициализироватьПроцессорКД(рПроцессорКД,рНабор,МакетКомпоновки,рИсточник,рРасшифровка,рВнешние) Тогда
Возврат РезультатныйДокумент;
КонецЕсли;
//
рПроцессорВывода=Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
рПроцессорВывода.УстановитьДокумент(РезультатныйДокумент);
#Если Клиент Тогда
рПроцессорВывода.ОтображатьПроцентВывода=Истина;
#КонецЕсли
РезультатныйДокумент=рПроцессорВывода.Вывести(рПроцессорКД,Истина);
Возврат РезультатныйДокумент;
Исключение
Сообщить("ПоместитьРезультатСКДвТабличныйДокумент: ошибка: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
Возврат РезультатныйДокумент;
КонецПопытки;
КонецФункции
#КонецОбласти
В некоторых случаях надо очень внимательно следить за вызовом с клиента, могут попасться несериализуемые.
Если кому пригодится, будет хорошо. Если кто заметит косяки - пишите, плиз, буду исправлять.
Кусок из этого моего функционала также можно увидеть в плагиате: //infostart.ru/1c/articles/575659/ - означенный плагиат хорош только тем, что имена переменных более привычны для большинства.
Использовалось на 8.3.15.1565, но мало менялось со времён 8.3.6.