Внимание! Всё это написано во времена 8.1 и до появления настоящей БСП и многих современных инструментов!
Просто собрание процедур и функций, которые я использую в работе с построителями запросов и СКД. Позволяют сэкономить время при разработке, являются эдакой "маленькой БСП". Рассчитаны на серверное исполнение и серверный вызов (там, где это допустимо по контексту).
Общие действия
#Область ОбщиеДействия
// превращает строку вида "Моя хорошая строка" в вид "МояХорошаяСтрока"
Функция ПревращениеНаименованияВИмя(рСтрока,рУбиратьЗапрещённые=Истина) Экспорт
Если рУбиратьЗапрещённые Тогда
стро=УбратьЗапрещённыеСимволы(рСтрока);
Иначе
стро=рСтрока;
КонецЕсли;
резстро=""; СледующаяЗаглавная=Ложь;
Для й=1 По СтрДлина(стро) Цикл
сим=Сред(стро,й,1);
Если сим=" " Тогда
СледующаяЗаглавная=Истина;
Иначе
Если СледующаяЗаглавная или й=1 Тогда
сим=ВРег(сим);
КонецЕсли;
резстро=резстро+сим;
СледующаяЗаглавная=Ложь;
КонецЕсли;
КонецЦикла;
Возврат резстро;
КонецФункции
// превращает строку вида "МояХорошаяСтрока" в вид "Моя хорошая строка"
Функция ПревращениеИмениВНаименование(рСтрока) Экспорт
Если СтрДлина(рСтрока)<=1 Тогда Возврат рСтрока КонецЕсли;
сим=Сред(рСтрока,1,1);
рПредВерхний=(ВРег(сим)=сим);
резстро=сим;
Для й=2 По СтрДлина(рСтрока) Цикл
сим=Сред(рСтрока,й,1);
Если сим="_" Тогда сим="." КонецЕсли;
рТекВерхний=(ВРег(сим)=сим);
Если рТекВерхний и не рПредВерхний Тогда
резстро=резстро+" "+НРег(сим);
Иначе
резстро=резстро+сим;
КонецЕсли;
рПредВерхний=рТекВерхний;
КонецЦикла;
Возврат резстро;
КонецФункции
// оставляет в строке только символы, допустимые в наименованиях согласно нотации 1С
Функция УбратьЗапрещённыеСимволы(Знач рСтрока,рЗапретные="",рНаЧтоЗаменять=Неопределено,рБезЛидирующего=Ложь) Экспорт
стрзнч=СокрЛП(Строка(рСтрока));
Если ПустаяСтрока(рЗапретные) Тогда // по умолчанию считаем таковыми:
рЗапретные="?,=|:;&""@#$#k8SjZc9Dxk!~`'[]{}№+-/*%()<>"+Символы.ВК+Символы.ВТаб+Символы.НПП+Символы.ПС+Символы.ПФ+Символы.Таб;
КонецЕсли;
рез="";
Для й=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); // основной набор
//
КомпоновщикМакета=Новый КомпоновщикМакетаКомпоновкиДанных;
рТипГенератора=Тип("ГенераторМакетаКомпоновкиДанных");
Если ТипЗнч(рКомпНастроекИлиНастройки)=Тип("НастройкиКомпоновкиДанных") Тогда
МакетКомпоновки=КомпоновщикМакета.Выполнить(рСКД,рКомпНастроекИлиНастройки,рРасшифровка,,рТипГенератора);
ИначеЕсли ТипЗнч(рКомпНастроекИлиНастройки)=Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
МакетКомпоновки=КомпоновщикМакета.Выполнить(рСКД,рКомпНастроекИлиНастройки.Настройки,рРасшифровка,,рТипГенератора);
КонецЕсли;
//
рПроцессорКД=Новый ПроцессорКомпоновкиДанных;
Если не ИнициализироватьПроцессорКД(рПроцессорКД,рНабор,МакетКомпоновки,рИсточник,рРасшифровка,рВнешние) Тогда
Возврат РезультатныйДокумент;
КонецЕсли;
//
рПроцессорВывода=Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
рПроцессорВывода.УстановитьДокумент(РезультатныйДокумент);
#Если Клиент Тогда
рПроцессорВывода.ОтображатьПроцентВывода=Истина;
#КонецЕсли
РезультатныйДокумент=рПроцессорВывода.Вывести(рПроцессорКД,Истина);
Возврат РезультатныйДокумент;
Исключение
Сообщить("ПоместитьРезультатСКДвТабличныйДокумент: ошибка: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
Возврат РезультатныйДокумент;
КонецПопытки;
КонецФункции
#КонецОбласти
В некоторых случаях надо очень внимательно следить за вызовом с клиента, могут попасться несериализуемые.
Если кому пригодится, будет хорошо. Если кто заметит косяки — пишите, плиз, буду исправлять.
Использовалось на 8.3.15.1565, но мало менялось со времён 8.3.6.
Related Posts
Получение логина и пароля техподдержки 1С из базы
Класс для вывода отчета в Excel
Счет-фактура для УПП
Библиотека классов для создания внешней компоненты 1С на C#
Акт об оказании услуг (со скидками) — внешняя печатная форма для Управление торговлей 11.1.10.86
Прайс-лист с артикулом в отдельной колонке
Да это же Яков Коган, который очень любит писать в комментариях к публикациям, что они баяны. Никогда не приводя доказательств.
Я уже не буду повторяться, что есть стандарт именования функций. Я понимаю, что такому великому спецу стандарты не писаны.
Вопрос тогда тебе автор, следующий: такой супер профессионал не знает про функцию ТРег() или просто любит писать велосипеды?
Ну и набор функций по работе с построителем кому выложил? Думаешь, что построитель еще кто-нибудь использует?
(1) конечно используют, мы, например, в УТ 10
пробежал код по диагонали и возникла ассоциации, что меня пригласили в чебуречную и
вместо шкварчащего, со свеже капающим жиром чебуречика, мне предлагают какой-то холодный тухляк.
Жуть какая то. Зачем ты эти префиксы переменным ставишь? семерочник то ле?
Автор из тех кто пишет «прив», «норм»?
(6) у него свое авторское клеймо.
тут уже обсуждали.
Вот
Но кому-то нравится такой стиль, судя по плюсам
(1) Баян безусловно. Хошь, в тексте статьи жирным шрифтом напишу?
Видал я в гробу эти стандарты, равно как и «соблюдение» их писателями типовых конфигов. Вопрос о соломинке в чужом глазу.
Некоторые части этого кода родились до появления ТРег.
Юзают ещё как)
(7) Во-первых, повторюсь, ТРег появилась не сразу, во-вторых, БСП меняется хз как, а свой код — он всегда под контролем, не будете же вы при каждом обновлении БСП лихорадочно актуализировать все знания о ней; в третьих, код этот родился задолго до современных БСП)
(10) 1) При обновлении БСП, конечно, надо проверять, а стоит ли игра свеч. Нужен анализ, что изменилось и что это влечёт за собой. Как правило, в новых версиях появляются и новые возможности, поэтому надо взвешивать: «мы получим это, но надо будет переписывать такие-то вызовы».
2) Отказ в использовании БСП ничуть не умаляет её функциональности. Загляните хотя бы в модуль ОбщегоНазчения в раздел «Процедуры и функции для работы с типами, объектами метаданных и их строковыми представлениями». Там найдутся более красивые и оптимальные реализации ваших процедур. Также будет полезно изучить ОтчетыКлиентСервер для работы с СКД.
Контраргумент «БСП меняется хз как» не мешает мне поддерживать самописные, отраслевые и типовые конфы уже много лет. Поэтому не вижу смысла изобретать велосипед.
(11) Изобретать велосипед имеет смысл тому, кто его изобрёл первым. Примерно 2/3 того, что есть в БСП, я сделал в виде том же, по сути, и с той же целью. Только немножечко раньше, чем фирма 1С. Так что да, скажите фирме 1С, пусть не изобретает велосипед, я-то свою механику ещё в 2006-м сделал)
А что касается «красивых и оптимальных» — спасибо, посмеялся. Громоздкие, избыточные, чудовищно накрученные механизмы… Или мы о разных БСП.
(7)Есть отшельники ))). Если вы поддерживаете нескольких клиентов (как допустим франч), у кого-то БП 3, у кого-то УТ 10.3, БП может быть 5-и разных релизов из-за доработки, то свой «БСП-независимый» код, может оказаться куда полезней, чем использование постоянно меняющейся БСП. Ну и код написаный под маленький функционал, может быть куда быстрее и проще, чем процедура «швейцарский нож» рассчитаная на широкий круг применения.
(13) Я во франче отработал более 10 лет и мне как-то не особо затратно удавалось поддерживать все конфы клиентов, ориентируясь на БСП, а не дублирующие механизмы. Это проще, чем городить своё.
Считаю, что если ты хочешь пилить что-то своё, то пили, но знать БСП обязан. Потому что в 90% случаев пилятся велосипеды. Причём, колхозные, реализация которых намного менее оптимальная, чем аналоги БСП. Возьми процедуру из БСП, выкуси лишнее, если вдруг оно там есть, и используй как «бсп-независимый код». Хотя это как-то нелепо.
(2) А подскажи, зачем? Ведь ваша платформа давно позволяет работать с СКД.
Как минимум, отчёт ДиаграммаСостоянияЭДО использует СКД.
(14) Очень хочется посмотреть на код использования БСП в 10.3. Код написанный для универсального использования почти всегда будет менее оптимален, чем написанный для конкретного случая. Допустим нам надо получить доп реквизит у 10 000 объектов, а в БСП( к примеру), есть получение свойства 1 объекта, так вот 10 000 вызовов универсальной функции будут в РАЗЫ не оптимальней чем получение этого свойства через запрос. Я конечно сильно в БСП не погружался, но насколько я видел это какой-то трындец когда все что можно сделать в 1 функции распихано по 10 модулям, с вызовами через 10-20 функций, для отладки тихий ужас, да и по производительности такой каскад вызовов, я думаю может играть плохую роль, учитывая что 1С — это компилятор, а каждый вызов функции — передача управления с использованием стека. Ну и достаточно посмотреть как работают стандартные конфигурации, у нас на серваке в файловом режиме работает 2 пользователя, база копеешная, и она конечно не висит, но жутко не комфортно работать.
(16) ОбщегоНазначения.ЗначениеРеквизитаОбъектов(МассивСсылок, ИмяРеквизита, ВыбратьРазрешенные = Ложь)
Это не 10000 вызовов, а одним запросом. При этом есть возможность получения не только одного реквизита а нескольких, и как одного объекта, так и нескольких. С учётом или без RLS. Мне это решение кажется априори выигрышным, что бы вы там ни попытались изобрести. Я видел код и не считаю его неоптимальным.
В своё время я поливал грязью УТ10.2 и платформу 8.0 и говорил, что она сырая и глючная. Потом пришёл конкурент к клиенту и перевёл их с ТиС 7.7 на «восьмёрку», а я остался ни с чем. Это ещё раз научило меня, что те, кто хаит, в большинстве своём не разбираются в предмете. Если бы топикстартер разбирался в БСП, мы бы видели более оптимальные процедуры и функции, чем в БСП, т.к. иначе он бы сам заметил, что его три страницы кода явно менее оптимальны, чем 15-20 строк БСП. Однако, выше мы видим колхоз.
Оправдание топикстартера по поводу ТРег не клеится с «Использовалось на 8.3.15.1565, но мало менялось со времён 8.3.6.»
Я нашёл упоминания ТРег в октябре 2015го. Как минимум, 4 года этой функции и тогда как раз была 8.3.6. Вот вам и наглядный пример пародирования даже не БСП, а целой даже платформы.
(17) вместо того, чтобы поливать грязью, возьмите отпуск, съездите отдохнуть в Турцию или Тайланд, познакомьтесь на отдыхе с программистами Сап или аксапты, порыбачьте вместе, выпейте чего нибудь.. а потом пригласите их к себе на внедрение и будет всем счастье.
(18) А, да, забыл отметить, что последние N месяцев на ИСе засилье каких-то странных программеров, которые или не знают про существование документаhttps://its.1c.ru/db/v8std или им приходится доказывать целесообразность его соблюдения. То же и с БСП. Это напоминает засилье школоты в WoT. Удручающая ситуация и с плюсами обсуждаемой статье.
(19) Люди которые написали этот документ, создали решение типа УТ 11, в результате, по крайней мере в нашем городе, автоматизация торговли мелкими конторами на УТ — сейчас практически отсуствует в силу ее минусов, с 1С слезли такие конторы как dns, и еще пару штук серьезных встречал, поэтому у меня большие сомнения в оптимальности БСП и методики программирования.
, ну если вы считаете что такая супер пупер мега процедура будет оптимальней запроса, я думаю, что это вы плохо разбираетесь в программировании.
(19) Последние N лет в типовых конфигурациях 1С засилье такого безграмотного кода, не лезущего ни в какие стандарты, что мне, автору успешных внедрённых тиражных решений, вы можете не напоминать про стандарты, а вот им — напомните. Адресок 1С-центральной дать, или знаете?))
Я очень рад, что вы в 2015 году обнаружили ТРег. А вот в 2007-м её как-то не наблюдалось. Так что да, платформописатели и писатели БСП — это таки с их стороны колхоз. Обрадуйте их, что всего через 5-7 лет после того, как функционал становится всем нужен, они его добавляют. Так было с «ЗначениеЗаполнено», с поиском в массиве, со строковыми вроде СтрРазделить. На тему которой тут, кстати, не столь давно тоже ломали копья.
Так что, товарисч, боритесь за соблюдение стандартов где-нибудь в районе Новослободской и Тимирязевской. Там оно нужнее. Ну и расскажите писателям платформы, что вообще желательно реализовывать механику, когда она нужна, а не когда с тех пор пять лет минуло.
Подход «возьми из БСП и выкуси» выдаёт явное отсутствие практики. Вы пробовали из этой, пардон, кастрюли с остывшей вермишелью «вытащить часть» или «выкусить лишнее»? Попробуйте. Вместо пары реально нужных процедур — 10 модулей с кучей барахла, жрущего ресурсы. Ну ничего, с опытом придёт)
(19) А вот насчёт засилья школоты — согласен. Последние пару лет на ИС не продохнуть от статей, чей уровень ниже плинтуса, однако они восторженно плюсуются и, значит, кому-то нужны. Я неоднократно в таких статьях выражал своё недоумение. А ваших комментов там что-то не припомню)
(14) Вот не обижайтесь, но виден франчевский подход. Да, поддержка с маленькими доработками — действительно наводит на мысль, что БСП лучше. Но только если поддержка многих и почти типовых. А если нужен серьёзный шаг в сторону, крупная доработка, если нужна оптимизация производительности итд., словом, если речь о крупном оригинальном решении — то даже вспоминать о БСП смешно и дико. Ну может самые базовые моменты, вроде работы с файлами или там строками-коллекциями, да и то слишком наворочено и избыточно. Поэтому я, как автор специальных решений, привык полагаться на свой, менее распиаренный, зато надёжный и простой код. Мне вот не улыбается сдать проект на эн лямов и через месяц прочитать, что в какой-то процедуре в глубинах БСП найдена и исправлена грубая ошибка, и понять, что этот контур БСП задействован в проекте.
«Знать БСП» нельзя. Я в своё время сделал глупость, потратил 2 месяца на доскональное её изучение. А тут раз, два, бац, и нате вам БСП следующей версии, «принципиально переработанную». Франч может тратить время на освоение, а я, извините, ведущий разработчик и архитектор, для меня это нереально отслеживать, тем более что комментарии в коде и документация ни в зуб копытом.
Опыт общения по серьёзным проектным решениям говорит: нигде в них от БСП более 10-20% не брали. Писали «под задачу и по месту».
Так что всякой задаче своё решение, не стоит быть столь категоричным)
(20)
Посмотрите код этой процедуры сначала? И если будет желание упираться дальше, сделайте замеры производительности.
Про DNS сложная ситуация. Пару недель назад наоборот читал интервью с кем-то из тамошних топов и он там рассказывал как успешно у них переписаны обмены данными и всё летает при переоценке. Конечно, на 1С. Если интересно, где-то на ИСе оно и мелькало.
Рекомендую не говорить за всех франчей города своё личное мнение. И, возвращаясь к истокам: готов дальше дискутировать только при предоставлении более оптимальных процедур, чем в БСП. Функциональность — тоже часть оптимальности.
(21) Мне тоже побить себя пяткой в грудь и потрясти регалиями? Мне не интересны ваши достижения, когда я вижу код и он откровенно плох. Качество кода — это и соответствие стандартам на его оформление. Отсюда следует и простота его поддержки.
Позволю напомнить, что платформа 8.3.6 вышла 25.03.16, что даже позже, чем октябрь 2015го и значит ТРег там изначально был. Однако, вы пишете целую функцию, которая делает то же самое, что платформенная.
Если тиражные решения (а это любая обработка, проданная хотя бы два раза) содержат такого же уровня код, я рад, что не сталкивался с ними.
(23) А я и не обижаюсь. У меня кроме 10 лет франча ещё больше стажа работы матрасником в штатке. 🙂
Все новые конфигурации я начинаю с выдёргивания нужных подсистем из БСП по регламентированной 1С схеме. Получаю заготовку нужной мне конфигурации и допиливаю свои подсистемы. Пока не встречал проблем с этим.
Кроме того, на текущей работе есть решение с «родной» версией БСП 2.1 на обычных формах, куда потом кто-то допиливал обмен с ДО и втащил туда подсистемы БСП версии 2.4. Сейчас в эту конфигурацию мной интегрировано 10-15 подсистем БСП 3.0.1 с заменой 2.4 на управляемых формах, конечно. Интегрировано успешно и проверено на проде. Не могу сказать, что это было особо сложно. Наверное, самым сложным было разобраться в механизме инициализации параметров сеанса. 🙂
И при этом я, конечно, далёк от знания БСП. Просто почти ежедневно вижу выгоду от использования архитектурно грамотных подсистем БСП, на реализацию которых в конфигурации я потратил несоизмеримо меньше времени, чем если бы писал с нуля.
Подытоживая дискуссию, ваш код, коли уж вы хотите поддерживать свои конфы независимо от БСП, обязан быть оптимальнее кода БСП. А для этого надо как минимум знать аналогичные механизмы БСП и платформы.
(24)Вы как-то странно читаете мои сообщения:
1. Я не собираюсь смотреть код, я вам говорю про концепцию, вы меня отсылаете к конкретным процедурам.
2. Где я говорил за всех франчей?
3. Про ДНС, я не знаю про что он говорил, но розница, конкретно в нашем магазине у них не на 1С, а раньше была на 1С, и это не одна контора
4. Функциональность и оптимальность процедуры — вещи совершенно разные, и это никак не ее часть.
(27)
Как-то читал статью про оптимальность кода, может, и на ИСе. Там среди прочих критериев упоминались и функциональность, что логично, и простота понимания и простота поддержки (например, модификация другим спецом спустя год). Именно ту статью найти не смог, ночто-то подобное рассказано тут . Пожалуй, это единственный ваш аргумент, который мне интересно обсуждать.
(28)Видимо потому что кроме как «БСП — наше все, все кто его не используют — простачки» и «1С — наш отец и мать» у вас как-то с аргументами больше не сложилось… в общем-то хорошо, я так понимаю, чем больше людей с вашим мышлением, тем больше работы у таких «костылеписателей» как я. Удачи
(29) Возможно, вам это недоступно, но я уже аргументировал в другом посте этой ветки, что если уж ты взялся делать что-то БСП-независимое, то твой код должен быть более оптимальным, чем БСП. Иначе это колхоз или, как говорят, велосипед. Глядя на такие «бсп-независимые» реализации иногда слёзы текут. Сколько я за свою практику в бытность франча переделал таких мега-изобретений на типовые механизмы…
И раз вы упоминали УТ10.3, то, конечно, ваши разработки должны по максимуму использовать типовые механизмы УТ или быть даже оптимальнее их.
Мысль проста и мне непонятно, зачем вы с ней спорили.
В связи с развязавшейся дискуссией про БСП вставлю свои 5 копеек.
В своей профессиональной деятельнсти я заметил 3 четких этапа, характеризующиеся способами разработки:
1)Колхоз как получится
2)Использование встроенной функциональности конфы по максимуму, мимикрия под стиль конфы
3)Колхоз со стажем
и переход от 2го этапа к 3му был вызван вполне ощутимыми и неприятными трудозатратами на сопровождение работ сделанных в течение этапа 2. Ну 100500 печатных форм поправить после обновления только потому что я ответственных лиц получал встроенной в конфу функцией, например.
(31) Присоединяюсь. Чуть не каждое обновление любой минимально модифицированной (расширениями, конечно, мы же блюдём рекомендации!) типовой ЗУП — это кровь из глаз, биение головой об стол и так далее. Ладно бы реально содержательные изменения, так нет — перенесли процедуру из модуля в модуль. Может, на супер-пупер-нагруженных системах это дало рост производительности процедуры на треть процента, не спорю; но, блин, почему занимаются этим, а не косяком, не позволяющим рассчитывать больничный поверх отсутствия? А у меня из-за этого переноса расширение отваливается. И хорошо, если отваливается с простой и понятной ошибкой, если мне повезло и вызов прямой… а бывает, что на раскоп, где какой параметр стал обязательным, уходят часы.
И ведь не угадаешь. А с БСП так и вообще полсистемы рухнуть может при обновлении, причём незаметно — любой синтакс-контроль пропустит, выборочный тест функциональности не налетит, а пользователи с утречка всей Россией колом встанут…
(26) Бесспорно, что БСП меняется, иногда сильно и непредсказуемо. Бесспорно, что она недостаточно документирована. И вот вопрос — вы сможете тратить время на изучение механики БСП, когда в быстром темпе пишется отдельный проект? Тратить время на адаптацию, обрезку ненужного, допиливание под задачу? Я — нет. Я хочу хотя бы иногда спать.
(31) Согласен. Единственно что, грамотная организация кода в любом случае позволяет избежать правки 100500 форм, и неважно, ваш это код с нуля или заимствованный, или вообще сама БСП.
Не далее как позавчера перенёс свою подсистему из БСХП в БП 3.0. В БСХП при этом как раз и интегрировал ранее БСП 3.0.1 (писал выше). Так вот, перенёс регистры, перечисления, документы, отчёты просто по сравнению/объединению. Документы проводятся после переноса, хотя исходная версия БСП у БСХП была 2.1, я даже не знаю, где они такую взяли.
Это я к чему… Пишите своё, если вам интересно. Я писал чётко на механизмах БСП и перенос всей подсистемы прошёл за пару часов адаптации. Задействованы подсистемы БСП: отчёты, печать, подключаемые команды, структура подчинённости, базовая функциональность, доп.свойства.
Уже несколько авторов выше пытаются избежать прямого сравнения своего кода и кода БСП. А ведь это немаловажно. Если вы уже решили отказаться от готовых механизмов и повысили риски ошибок и рефакторинга из-за разработки своими силами, то добавьте хотя бы гарантию качества, что ваш код действительно лучше БСП’шного, от которого вы отказались — сравните свой и БСП’шный.
Пример: процедура в обсуждаемой статье вместо ТРег. Уже даже поймал автора на том, что когда он её писал, ТРег существовал, но нет, исправлений в тексте статьи нет. Да даже если бы и не было в то время ТРег, зачем этот код нам сейчас, когда ТРег давно есть?
Из своей практики скажу, что не встречал альтернативных БСП’шным колхозных решений частных умельцев лучше, чем в БСП. Но у вас есть шанс, удачи.
(33) Ниже конкретный пример переноса подсистемы. Благодаря БСП у вас 50% разных конфигураций одинаковы и перенос выполняется намного проще. Так где меньше трудозатрат, например, при реализации механизма доп.реквизитов и сведений? Когда делаешь сам с нуля или готовая подсистема от БСП?
Вероятно, вы путаете программирование специфической для задачи логики и разработку дублирующего механизмы БСП колхоза.
(36) Если механизм совсем отчётливо дублирует, тогда, конечно, колхозить смысла нет. Но гораздо чаще появляются такие милые нюансы, которые делают заимствование бессмысленным, по времени и трудозатратам. Я много раз видел системы, перепиленные до полной неузнаваемости из типовых, которые в итоге тормозили и висли на унаследованных местах, и в 70% случаев после анализа становилось ясно, что правильнее-то было бы писать «под ключ» своё. Чем я иногда и занимался. Конечно, сначала их авторам казалось, что доработка-то маленькая, брали из БСП, а потом начиналось дальше в лес и толще партизаны. И однажды наступало понимание, что своё тянуть легче.
Насчёт доп.реквизитов — а вы имели дело с допиливанием их визуализации на упр.формах? Это ж покурочить вдвое сложнее, чем своё накатать.
Не спорю, бывает. Но бывает гораздо реже, чем кажется оптимистам. У меня один такой сотрудничек потратил неделю на рест-запросы там, где мне хватило часа. Потому что дёргал из БСП, натащил 6 лишних общих модулей, кучу вспомогательной хрени, и всё ради получения данных контрагента по ИНН. А моя одна маленькая процедура делала то же самое, но ни в чём не нуждалась. Выводы?
(35) Поймали автора? Уважаемый, вы читайте внимательнее, ага. Этот код появился в 2008-09 годах. А что касается «зачем», так встречный вам вопрос — вы никогда не наблюдали, как код отказывается компилиться на новых платформах, если в нём есть «новинки» вроде СтрРазделить? Или вам в скайпе на примере показать? Не у всех супер-новые релизы конфигураций и платформ. Множество внедрений работают на 8.2 и совершенно никто не горит переходить на 8.3
Я в БСП видел такую жесть, которую и кодом-то назвать совестно. Руки поотрывать и поувольнять за профнепригодность. Механика подключения внешек, работа с периферийным оборудованием и ещё кое-какие подсистемы. Не то чтоб стандарты какие, а кромешная жуть. Вас не смущает запрос вида «Выбрать Различные спр.Ссылка Из Справочник.Пользователи»? А проверка «Если не СокрЛП(спрСсылка)=»» Тогда // ссылка пуста»?
Из своей практики скажу, что не встречал заимствования из БСП, которые были бы толковы, минималистичны, быстродействующи, просты, понятны и гибки. Но у вас есть шанс. Удачи)
Да, что ещё скажу. У 1С прямо даже в платформе есть и перепроведение документов, и поиск ссылок, и удаление помеченных, и управление итогами. Ответьте мне, поклонники творчества 1С-Центральной, зачем же тогда на ИС и других ресурсах такое колоссальное количество обработок на эту тему? Колхоз ведь!
1С написала КИП с ЦУПом. Супер, почему тогда многие, с Гилёва начиная, юзают и свои наработки? Колхоз же!
Давайте будем применять только инструменты, предложенные вендором, они самые лучшие! Так, да?)))
(39) Если перестать слепо беситься от вопроса «зачем нам этот колхоз 10 лет спустя», потому что он не в бровь, а в глаз, то становится очевидно, что выше был сформулирован минимум два раза постулат:
(35)
Очевидно, что консоли запросов пишутся пачками потому, что штатная чем-то не устраивает. Например, тем, что нет конструктора в тонком клиенте. Т.е. расширяется функциональность механизма.
(40) Так вот мой код — лучше)) А кому не нравится — не кушайте)
Ужас-то на самом деле в другом. Ужас в том, что подобные публикации плюсят. Радостно накидываются на любой халявный исходник, копипастят и юзают.
(35) Расскажите авторуhttps://infostart.ru/public/1134548/ что лучше БСП, её подписок, её переопределяемых модулей итд, ничего нет) А то человек колхозит, мучается… Ну или что подождать надо пару лет, 1С одуплится и какой-нибудь крутой инструмент забацает)
(35) Гляньте, какой колхоз-то жуткийhttps://infostart.ru/public/1137019/ , видать автор не знает, что история теперь в платформу вшита! Срочно проповедуйте ему благодать БСП!
(43) Перестаньте паясничать. Статья дубль, в коде ошибки, но т.о. автор решает вопрос о внесении модификаций без обновления конфигурации. Я давно не работал со старыми формами, не могу прокомментировать оптимальность решения.
(36)PLAstic, возможно Вы правы. Возможно нет. Все зависит от ваших целей. Если Вы желаете наштамповать как можно больше продуктов, не заморачиваясь оптимальными программными решениями направленными на удобство пользователей — то правы. Если же в ваших приоритетах создание качественных продуктов с ориентиром на конечных пользователей — то нет. Потому как БСП — система функций неоптимальных и избыточных в очень высокой степени и их использование по «настоятельным рекомендациям» редко улучшает работу программы.