Полезняшки по СКД и построителям. Просто код
Внимание! Всё это написано во времена 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.
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
См. также
Инструментарий разработчика Роли и права Запросы СКД Разработчик Руководитель проекта 1С:Предприятие 8 Платные (руб)
Инструменты для разработчиков 1С 8.3 и 8.5: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.
16500 руб.
02.09.2020 285708 1606 423
СКД Разработчик 1С:Предприятие 8 Бесплатно (free)
Как решить проблему с отборами по полям СКД, когда с одинаковым отбором Отчет показывает одно, а Консоль запросов другое.
16.06.2026 6380 sapervodichka 45
Инструментарий разработчика СКД Разработчик 1С 8.3 Бесплатно (free)
В этой статье представлен ПовелительОтчетов — общий модуль-обёртка над объектной моделью СКД, который сокращает код в 3-4 раза и делает его читаемым.
29.01.2026 9449 455 shapa_pro 31
СКД Разработчик 1С:Предприятие 8 Бесплатно (free)
Статья написана по результатам проведенного внутреннего обучающего вебинара для разработчиков ГК «СофтБаланс». Если осилить 25 000 знаков - задача для вас непосильная, где-то на бескрайних просторах интернета видео есть (или будет). Но здесь информация точнее. Разберем, чем запрос для СКД принципиально отличается от обычного запроса и как модифицируется в зависимости от настроек. Изучим «базовый рецепт» написания запроса для СКД, сформируем чек-лист. Полезно будет всем – от стажеров до тех. лидов. Всем, кто не снимает галку «автозаполнение» и пишет запросы для отчетов в консоли запросов – читать (вдумчиво) обязательно.
29.10.2025 27058 ovetgana 112
СКД Разработчик 1С:Предприятие 8 Бесплатно (free)
Описан способ заполнения списка доступных значений для полей наборов данных и параметров в схеме компоновки данных для любых конфигураций (с использованием БСП или без).
01.07.2025 15799 krasnoshchekovpavel 7
СКД Разработчик Стажер 1С:Предприятие 8 Россия Бесплатно (free)
Несколько способов управления формами выбора параметров и отборов СКД.
10.04.2025 15214 Neti 0
СКД Разработчик 1С:Предприятие 8 Бесплатно (free)
Хорошая отчетная форма - сродни искусству. Есть какое-то невероятное эстетическое удовольствие в том, чтобы разобраться в логике учета и анализируемых показателях, спроектировать архитектуру хранения данных так, чтобы оптимально собрать эти показатели вместе с аналитическими разрезами в запросе, а затем настроить отображение так, чтобы, глядя на результат, сразу было понятно, что это за отчет и какие задачи он призван решать. Система компоновки данных - это моя первая, главная и, наверное, единственная "рабочая" любовь. Ее я использую везде, где только можно и где нельзя тоже. Хочу поделиться с вами некоторыми практическими приемами в работе с отчетами на СКД, которые, надеюсь, будут полезны.
27.02.2025 19850 ovetgana 50
СКД Разработчик 1С:Предприятие 8 Бесплатно (free)
СКД – инструмент, на базе которого в современных конфигурациях реализованы практически все отчеты. СКД используется в динамических списках, печатных формах и универсальных механизмах. Если построить простейший отчет может каждый разработчик, то с нюансами знакомы далеко не все. Расскажем о неочевидных на первый взгляд приемах, способных значительно повысить качество отчетов.
24.12.2024 17766 Akcium 17
Я уже не буду повторяться, что есть стандарт именования функций. Я понимаю, что такому великому спецу стандарты не писаны.
Вопрос тогда тебе автор, следующий: такой супер профессионал не знает про функцию ТРег() или просто любит писать велосипеды?
Ну и набор функций по работе с построителем кому выложил? Думаешь, что построитель еще кто-нибудь использует?
Видал я в гробу эти стандарты, равно как и "соблюдение" их писателями типовых конфигов. Вопрос о соломинке в чужом глазу.
Некоторые части этого кода родились до появления ТРег.
Юзают ещё как)
Результат = СтрЗаменить(ТРег(ИсходнаяСтрока), " ", "");И вообще, я думал, отшельников, которые до сих пор пишут в отрыве от БСП, больше не осталось. Это же банальная логика: зачем колхозить то, что уже написано и написано лучше?
2) Отказ в использовании БСП ничуть не умаляет её функциональности. Загляните хотя бы в модуль ОбщегоНазчения в раздел "Процедуры и функции для работы с типами, объектами метаданных и их строковыми представлениями". Там найдутся более красивые и оптимальные реализации ваших процедур. Также будет полезно изучить ОтчетыКлиентСервер для работы с СКД.
Контраргумент "БСП меняется хз как" не мешает мне поддерживать самописные, отраслевые и типовые конфы уже много лет. Поэтому не вижу смысла изобретать велосипед.
А что касается "красивых и оптимальных" - спасибо, посмеялся. Громоздкие, избыточные, чудовищно накрученные механизмы... Или мы о разных БСП.
Считаю, что если ты хочешь пилить что-то своё, то пили, но знать БСП обязан. Потому что в 90% случаев пилятся велосипеды. Причём, колхозные, реализация которых намного менее оптимальная, чем аналоги БСП. Возьми процедуру из БСП, выкуси лишнее, если вдруг оно там есть, и используй как "бсп-независимый код". Хотя это как-то нелепо.
Это не 10000 вызовов, а одним запросом. При этом есть возможность получения не только одного реквизита а нескольких, и как одного объекта, так и нескольких. С учётом или без RLS. Мне это решение кажется априори выигрышным, что бы вы там ни попытались изобрести. Я видел код и не считаю его неоптимальным.
В своё время я поливал грязью УТ10.2 и платформу 8.0 и говорил, что она сырая и глючная. Потом пришёл конкурент к клиенту и перевёл их с ТиС 7.7 на "восьмёрку", а я остался ни с чем. Это ещё раз научило меня, что те, кто хаит, в большинстве своём не разбираются в предмете. Если бы топикстартер разбирался в БСП, мы бы видели более оптимальные процедуры и функции, чем в БСП, т.к. иначе он бы сам заметил, что его три страницы кода явно менее оптимальны, чем 15-20 строк БСП. Однако, выше мы видим колхоз.
Оправдание топикстартера по поводу ТРег не клеится с "Использовалось на 8.3.15.1565, но мало менялось со времён 8.3.6."
Я нашёл упоминания ТРег в октябре 2015го. Как минимум, 4 года этой функции и тогда как раз была 8.3.6. Вот вам и наглядный пример пародирования даже не БСП, а целой даже платформы.
Посмотрите код этой процедуры сначала? И если будет желание упираться дальше, сделайте замеры производительности.
Про DNS сложная ситуация. Пару недель назад наоборот читал интервью с кем-то из тамошних топов и он там рассказывал как успешно у них переписаны обмены данными и всё летает при переоценке. Конечно, на 1С. Если интересно, где-то на ИСе оно и мелькало.
Рекомендую не говорить за всех франчей города своё личное мнение. И, возвращаясь к истокам: готов дальше дискутировать только при предоставлении более оптимальных процедур, чем в БСП. Функциональность - тоже часть оптимальности.
1. Я не собираюсь смотреть код, я вам говорю про концепцию, вы меня отсылаете к конкретным процедурам.
2. Где я говорил за всех франчей?
3. Про ДНС, я не знаю про что он говорил, но розница, конкретно в нашем магазине у них не на 1С, а раньше была на 1С, и это не одна контора
4. Функциональность и оптимальность процедуры - вещи совершенно разные, и это никак не ее часть.
И раз вы упоминали УТ10.3, то, конечно, ваши разработки должны по максимуму использовать типовые механизмы УТ или быть даже оптимальнее их.
Мысль проста и мне непонятно, зачем вы с ней спорили.
Я очень рад, что вы в 2015 году обнаружили ТРег. А вот в 2007-м её как-то не наблюдалось. Так что да, платформописатели и писатели БСП - это таки с их стороны колхоз. Обрадуйте их, что всего через 5-7 лет после того, как функционал становится всем нужен, они его добавляют. Так было с "ЗначениеЗаполнено", с поиском в массиве, со строковыми вроде СтрРазделить. На тему которой тут, кстати, не столь давно тоже ломали копья.
Так что, товарисч, боритесь за соблюдение стандартов где-нибудь в районе Новослободской и Тимирязевской. Там оно нужнее. Ну и расскажите писателям платформы, что вообще желательно реализовывать механику, когда она нужна, а не когда с тех пор пять лет минуло.
Подход "возьми из БСП и выкуси" выдаёт явное отсутствие практики. Вы пробовали из этой, пардон, кастрюли с остывшей вермишелью "вытащить часть" или "выкусить лишнее"? Попробуйте. Вместо пары реально нужных процедур - 10 модулей с кучей барахла, жрущего ресурсы. Ну ничего, с опытом придёт)
Позволю напомнить, что платформа 8.3.6 вышла 25.03.16, что даже позже, чем октябрь 2015го и значит ТРег там изначально был. Однако, вы пишете целую функцию, которая делает то же самое, что платформенная.
Если тиражные решения (а это любая обработка, проданная хотя бы два раза) содержат такого же уровня код, я рад, что не сталкивался с ними.
"Знать БСП" нельзя. Я в своё время сделал глупость, потратил 2 месяца на доскональное её изучение. А тут раз, два, бац, и нате вам БСП следующей версии, "принципиально переработанную". Франч может тратить время на освоение, а я, извините, ведущий разработчик и архитектор, для меня это нереально отслеживать, тем более что комментарии в коде и документация ни в зуб копытом.
Опыт общения по серьёзным проектным решениям говорит: нигде в них от БСП более 10-20% не брали. Писали "под задачу и по месту".
Так что всякой задаче своё решение, не стоит быть столь категоричным)
Все новые конфигурации я начинаю с выдёргивания нужных подсистем из БСП по регламентированной 1С схеме. Получаю заготовку нужной мне конфигурации и допиливаю свои подсистемы. Пока не встречал проблем с этим.
Кроме того, на текущей работе есть решение с "родной" версией БСП 2.1 на обычных формах, куда потом кто-то допиливал обмен с ДО и втащил туда подсистемы БСП версии 2.4. Сейчас в эту конфигурацию мной интегрировано 10-15 подсистем БСП 3.0.1 с заменой 2.4 на управляемых формах, конечно. Интегрировано успешно и проверено на проде. Не могу сказать, что это было особо сложно. Наверное, самым сложным было разобраться в механизме инициализации параметров сеанса. :)
И при этом я, конечно, далёк от знания БСП. Просто почти ежедневно вижу выгоду от использования архитектурно грамотных подсистем БСП, на реализацию которых в конфигурации я потратил несоизмеримо меньше времени, чем если бы писал с нуля.
Подытоживая дискуссию, ваш код, коли уж вы хотите поддерживать свои конфы независимо от БСП, обязан быть оптимальнее кода БСП. А для этого надо как минимум знать аналогичные механизмы БСП и платформы.
Вероятно, вы путаете программирование специфической для задачи логики и разработку дублирующего механизмы БСП колхоза.
Насчёт доп.реквизитов - а вы имели дело с допиливанием их визуализации на упр.формах? Это ж покурочить вдвое сложнее, чем своё накатать.
Не спорю, бывает. Но бывает гораздо реже, чем кажется оптимистам. У меня один такой сотрудничек потратил неделю на рест-запросы там, где мне хватило часа. Потому что дёргал из БСП, натащил 6 лишних общих модулей, кучу вспомогательной хрени, и всё ради получения данных контрагента по ИНН. А моя одна маленькая процедура делала то же самое, но ни в чём не нуждалась. Выводы?
В своей профессиональной деятельнсти я заметил 3 четких этапа, характеризующиеся способами разработки:
1)Колхоз как получится
2)Использование встроенной функциональности конфы по максимуму, мимикрия под стиль конфы
3)Колхоз со стажем
и переход от 2го этапа к 3му был вызван вполне ощутимыми и неприятными трудозатратами на сопровождение работ сделанных в течение этапа 2. Ну 100500 печатных форм поправить после обновления только потому что я ответственных лиц получал встроенной в конфу функцией, например.
И ведь не угадаешь. А с БСП так и вообще полсистемы рухнуть может при обновлении, причём незаметно - любой синтакс-контроль пропустит, выборочный тест функциональности не налетит, а пользователи с утречка всей Россией колом встанут...
Это я к чему... Пишите своё, если вам интересно. Я писал чётко на механизмах БСП и перенос всей подсистемы прошёл за пару часов адаптации. Задействованы подсистемы БСП: отчёты, печать, подключаемые команды, структура подчинённости, базовая функциональность, доп.свойства.
Уже несколько авторов выше пытаются избежать прямого сравнения своего кода и кода БСП. А ведь это немаловажно. Если вы уже решили отказаться от готовых механизмов и повысили риски ошибок и рефакторинга из-за разработки своими силами, то добавьте хотя бы гарантию качества, что ваш код действительно лучше БСП'шного, от которого вы отказались - сравните свой и БСП'шный.
Пример: процедура в обсуждаемой статье вместо ТРег. Уже даже поймал автора на том, что когда он её писал, ТРег существовал, но нет, исправлений в тексте статьи нет. Да даже если бы и не было в то время ТРег, зачем этот код нам сейчас, когда ТРег давно есть?
Из своей практики скажу, что не встречал альтернативных БСП'шным колхозных решений частных умельцев лучше, чем в БСП. Но у вас есть шанс, удачи.
Я в БСП видел такую жесть, которую и кодом-то назвать совестно. Руки поотрывать и поувольнять за профнепригодность. Механика подключения внешек, работа с периферийным оборудованием и ещё кое-какие подсистемы. Не то чтоб стандарты какие, а кромешная жуть. Вас не смущает запрос вида "Выбрать Различные спр.Ссылка Из Справочник.Пользователи"? А проверка "Если не СокрЛП(спрСсылка)="" Тогда // ссылка пуста"?
Из своей практики скажу, что не встречал заимствования из БСП, которые были бы толковы, минималистичны, быстродействующи, просты, понятны и гибки. Но у вас есть шанс. Удачи)
1С написала КИП с ЦУПом. Супер, почему тогда многие, с Гилёва начиная, юзают и свои наработки? Колхоз же!
Давайте будем применять только инструменты, предложенные вендором, они самые лучшие! Так, да?)))
(35)
Очевидно, что консоли запросов пишутся пачками потому, что штатная чем-то не устраивает. Например, тем, что нет конструктора в тонком клиенте. Т.е. расширяется функциональность механизма.
несколько раз замечал в типовой бухгалтерии вызов процедур БСП в цикле, внутри процедуры выполнение запроса, для мелких компаний это не заметно, а для крупных компаний думаю не всегда БСП выгодно в плане оптимальности.
Вы можете заказать платную консультацию или разработку у автора. Будет создан приватный заказ на «Бирже заказов» для автора.
№ 1133780
Создание 10.10.19 22:10
Обновление 29.04.21 09:51
Просмотры 19339
Загрузки 0
Рейтинг
66
Комментарии 47
Код открыт Да
Рубрики СКД
Кому Разработчик
Тип файла Нет файла
Платформа 1С:Предприятие 8
Конфигурация Универсальные
Операционная система Не имеет значения
Страна Не имеет значения
Отрасль Не имеет значения
Налоги Не имеет значения
Вид учета Не имеет значения
Доступ к файлу Бесплатно (free)