Внимание! Всё это написано во времена 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 Тогда
Сообщить("Во временную таблицу с именем """+СокрЛ Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.