Шаблон типового отчета (СКД) в привилегированном режиме




Шаблон типового отчета СКД (https://its.1c.ru/db/metod8dev#content:3048:hdoc), формирование отчета перенесено в привилегированный модуль. Для конфигураций, где есть общий модуль ТиповыеОтчеты.

Появилось несколько задач сделать внешние отчеты без ограничения прав, обычные формы, клиент- сервер, УПП 1.3.

Дано: пользователь с ролями "Пользователь ", "Вывод информации", надо сделать для него отчет, например, по Основным средствам.

При этом:

1. Роли добавить пользователю нельзя;

2. УстановитьПривилегированныйРежим(Истина) — во внешних отчетах на обычных формах не работает;

3. Сделать отчет на управляемых формах и встроить отчет в конфигурацию — заказчик против, т.к. у него уже настроен доступ ко внешним отчетам и обработкам через RLS.

в остается формирование отчета в привилегированном модуле.

За основу взят "Шаблон типового отчета СКД" https://its.1c.ru/db/metod8dev#content:3048:hdoc, формирование результата вынесено в привилегированный модуль.

Реализация такая:

1. В конфигурацию добавляем общий модуль ДоработкиПривилегированный с галками Сервер, Вызов сервера, Привилегированный, в который помещаем функцию формирования отчета, см.код ниже.

2. В отчете, как обычно, в основной схеме компоновки добавляем набор данных — Запрос, делаем настройки. При запуске отчета создается программно еще одна схема — но с набором данных — Объект. Копируются все поля, параметры и ресурсы. Эта схема используется в отчете для инициализации компоновщика настроек и пользователь может настроить структуру без красных крестиков на полях.

Настройки, которые установил пользователь передаются на сервер, загружаются в настройки компоновщика основной схемы

Отчет по основной схеме формируется на сервере в общем модуле ДоработкиПривилегированный, возвращается назад уже готовый результат — Табличный документ.

Расшифровку полностью победить не удалось, оставила только одно действие — ОткрытьЗначение. Если  у пользователя есть права на объект — при двойном клике по объекту — откроется значение, если прав нет, выводится стандартное сообщение "У пользователя недостаточно прав для исполнение операции над базой данных".

Очень важно!!! В основной схеме компоновки данных в наборах данных обязательно должны быть указаны типы значений полей.

Функция СформироватьОтчет из модуля отчета:

Функция СформироватьОтчет(Результат = Неопределено, ДанныеРасшифровки = Неопределено, ВыводВФормуОтчета = Истина) Экспорт

//ЗначениеПанелипользователя = ТиповыеОтчеты.ПолучитьЗначенияНастроекПанелиПользователяОбъекта(ЭтотОбъект);
НастрокаПоУмолчанию        = КомпоновщикНастроек.ПолучитьНастройки();
ТиповыеОтчеты.ПолучитьПримененуюНастройку(ЭтотОбъект);

//++начало
Результат.Очистить();

ТабличныйДокумент = Новый ТабличныйДокумент;

ТиповыеОтчеты.ДоработатьТиповойОтчетПередВыводом(ЭтотОбъект);
ТиповыеОтчеты.ВыводЗаголовкаТиповогоОтчета(ЭтотОбъект, ТабличныйДокумент);

ДоработатьКомпоновщикПередВыводом();

СтруктураОтчета = Новый Структура("Схема, ДанныеРасшифровки, НастройкиКомпоновщика, ТабличныйДокумент", ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных"), ДанныеРасшифровки, Новый ХранилищеЗначения(КомпоновщикНастроек.Настройки), ТабличныйДокумент);
АдресСтруктураОтчета = ПоместитьВоВременноеХранилище(СтруктураОтчета, Новый УникальныйИдентификатор);

АдресРезультат = ДоработкиПривилегированный.СформироватьОтчетПривРежТабличныйДокумент(АдресСтруктураОтчета);
РезультатСтруктура = ПолучитьИзВременногоХранилища(АдресРезультат);

РезультатТабличныйДокумент = РезультатСтруктура.ТабличныйДокумент;
ДанныеРасшифровки = РезультатСтруктура.ДанныеРасшифровки;
ДанныеРасшифровки.Настройки = КомпоновщикНастроек.Настройки;

Результат.Вывести(РезультатТабличныйДокумент);

Результат.ФиксацияСверху    = РезультатТабличныйДокумент.ФиксацияСверху;

Результат.Показать();

УдалитьИзВременногоХранилища(АдресСтруктураОтчета);
УдалитьИзВременногоХранилища(АдресРезультат);
//--конец

//ТиповыеОтчеты.СформироватьТиповойОтчет(ЭтотОбъект, Результат, ДанныеРасшифровки, ВыводВФормуОтчета);
КомпоновщикНастроек.ЗагрузитьНастройки(НастрокаПоУмолчанию);

КонецФункции

Функция из модуля отчета, которая создает схему с набором данных Объект:

Функция ПолучитьСхемуДляНастройки()

//Схема для настройки
Схема = Новый СхемаКомпоновкиДанных;
ИД = Схема.ИсточникиДанных.Добавить();
ИД.Имя = "ИсточникДанных";
ИД.ТипИсточникаДанных = "Local";

НаборДанныхДляНастройки = Схема.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
НаборДанныхДляНастройки.Имя = "ВнешниеДанные";
НаборДанныхДляНастройки.ИмяОбъекта = "ВнешниеДанные";
НаборДанныхДляНастройки.ИсточникДанных = "ИсточникДанных";

//поля
Для каждого НаборДанных из СхемаКомпоновкиДанных.НаборыДанных Цикл
Для каждого Поле из НаборДанных.Поля Цикл

Если НаборДанныхДляНастройки.Поля.Найти(Поле) = Неопределено Тогда

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

КонецЕсли;

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

//параметры
Для каждого Параметр из СхемаКомпоновкиДанных.Параметры Цикл

Если Схема.Параметры.Найти(Параметр) = Неопределено Тогда

ПараметрДляНастройки = Схема.Параметры.Добавить();
ЗаполнитьЗначенияСвойств(ПараметрДляНастройки, Параметр);

КонецЕсли;

КонецЦикла;

//выч поля
Для каждого ВычПоле из СхемаКомпоновкиДанных.ВычисляемыеПоля Цикл

Если Схема.ВычисляемыеПоля.Найти(ВычПоле) = Неопределено Тогда

ВычПолеДляНастройки = Схема.ВычисляемыеПоля.Добавить();
ЗаполнитьЗначенияСвойств(ВычПолеДляНастройки, ВычПоле);

КонецЕсли;

КонецЦикла;

//ресурсы
Для каждого Ресурс из СхемаКомпоновкиДанных.ПоляИтога Цикл

Если Схема.ПоляИтога.Найти(Ресурс) = Неопределено Тогда

РесурсДляНастройки = Схема.ПоляИтога.Добавить();
ЗаполнитьЗначенияСвойств(РесурсДляНастройки, Ресурс);

КонецЕсли;

КонецЦикла;

ТиповыеОтчеты.СкопироватьНастройкиКомпоновкиДанных(Схема.НастройкиПоУмолчанию, СхемаКомпоновкиДанных.НастройкиПоУмолчанию);

Возврат Схема;

КонецФункции

В процедуре ПрименитьНастройку модуля отчета:

Процедура ПрименитьНастройку() Экспорт

//СхемаДляНастройки = ТиповыеОтчеты.ПолучитьСхемуКомпоновкиОбъекта(ЭтотОбъект);
//++начало
Схема = ПолучитьСхемуДляНастройки();
//--конец

// Считываение структуры настроек отчета
Если Не СохраненнаяНастройка.Пустая() Тогда

СтруктураНастроек = СохраненнаяНастройка.ХранилищеНастроек.Получить();
Если Не СтруктураНастроек = Неопределено Тогда
КомпоновщикНастроек.ЗагрузитьНастройки(СтруктураНастроек.НастройкиКомпоновщика);
ЗаполнитьЗначенияСвойств(ЭтотОбъект, СтруктураНастроек);
Иначе
КомпоновщикНастроек.ЗагрузитьНастройки(Схема.НастройкиПоУмолчанию);
КонецЕсли;

Иначе
КомпоновщикНастроек.ЗагрузитьНастройки(Схема.НастройкиПоУмолчанию);
КонецЕсли;

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

В модуле отчета основную схему компоновки данных подменяем на созданную нами схему:

СхемаКомпоновкиДанных = ПолучитьСхемуДляНастройки();

Функция в общем модуле ДоработкиПривилегированный (почти копия ТиповыеОтчеты.УниверсальныйМеханизмФормированияОтчета)

Функция СформироватьОтчетПривРежТабличныйДокумент(АдресСтруктураОтчета) Экспорт

КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;

СтруктураОтчета = ПолучитьИзВременногоХранилища(АдресСтруктураОтчета);

Схема      = СтруктураОтчета.Схема;
ДанныеРасшифровки   = СтруктураОтчета.ДанныеРасшифровки;
НастройкиКомпоновщика  = СтруктураОтчета.НастройкиКомпоновщика.Получить();
ТабличныйДокумент  = СтруктураОтчета.ТабличныйДокумент;

ВнешниеНаборыДанных = Неопределено;

Если СтруктураОтчета.Свойство("ВнешниеНаборыДанных") Тогда
ВнешниеНаборыДанных = СтруктураОтчета.ВнешниеНаборыДанных;
КонецЕсли;

КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;

КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(Схема));
КомпоновщикНастроек.ЗагрузитьНастройки(НастройкиКомпоновщика);

МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, НастройкиКомпоновщика, ДанныеРасшифровки);
ТиповыеОтчеты.ДополнитьМакетыМакетаКомпоновкиРасшифровкойРесурсов(МакетКомпоновки, КомпоновщикНастроек);

//Создадим и инициализируем процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
Если ВнешниеНаборыДанных = Неопределено Тогда
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
Иначе
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);
КонецЕсли;

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабличныйДокумент);

//Обозначим начало вывода
ПроцессорВывода.НачатьВывод();
ТаблицаЗафиксирована = Ложь;

ТабличныйДокумент.ФиксацияСверху = 0;

//определим нужна ли фиксация в отчете. Если элементов структуры больше 2-х
КолВоВключеныхЭлементов = 0;
Для каждого ЭлементСтруктуры из НастройкиКомпоновщика.Структура Цикл
Если ЭлементСтруктуры.Использование тогда
КолВоВключеныхЭлементов = КолВоВключеныхЭлементов + 1;
КонецЕсли;

Если КолВоВключеныхЭлементов > 1 тогда
ТаблицаЗафиксирована = истина;
КонецЕсли;
КонецЦикла;

//Основной цикл вывода отчета
Пока Истина Цикл

//Получим следующий элемент результата компоновки
ЭлементРезультата = ПроцессорКомпоновки.Следующий();

Если ЭлементРезультата = Неопределено Тогда
//Следующий элемент не получен - заканчиваем цикл вывода
Прервать;

Иначе

Если  Не ТаблицаЗафиксирована
И ЭлементРезультата.ЗначенияПараметров.Количество() > 0
И ТипЗнч(НастройкиКомпоновщика.Структура[0]) <> Тип("ДиаграммаКомпоновкиДанных") Тогда

ТаблицаЗафиксирована = Истина;
ТабличныйДокумент.ФиксацияСверху = ТабличныйДокумент.ВысотаТаблицы;
ОбластьШапки = ТабличныйДокумент.Область(3, ,ТабличныйДокумент.ВысотаТаблицы, );
ТабличныйДокумент.ПовторятьПриПечатиСтроки = ОбластьШапки;

КонецЕсли;

//Элемент получен - выведем его при помощи процессора вывода
ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);

КонецЕсли;

КонецЦикла;

//Обозначем завершение вывода
ПроцессорВывода.ЗакончитьВывод();

РезультатОтчета = Новый Структура("ТабличныйДокумент, ДанныеРасшифровки", ТабличныйДокумент, ДанныеРасшифровки);
Возврат ПоместитьВоВременноеХранилище(РезультатОтчета, Новый УникальныйИдентификатор);

КонецФункции

В архиве внешний отчет и текст для общего модуля. Тестировался на Управление производственным предприятием, редакция 1.3 (1.3.82.1). Не проверяла на сложных схемах с произвольными макетами, вложенными схемами.

12 Comments

  1. NoRazum

    Если отчет встраивать в конфу нельзя. То почему общие модули можно?

    За код спасибо. Но полезность сомнительна.

    Reply
  2. user660938_zerkalo242

    Спасибо автору. Только такой подход сработал. Много времени потратил на поиск решения проблемы в интернет.

    Reply
  3. sergathome

    вызываемые функции будут всёравно в безопасном режиме вызываться, интересно, или нет ?

    Reply
  4. Lusha_28

    (3) У всех пользователей, которые пользуются этими отчетами стоит галка «Защита от опасных действий», на ошибки никто не жалуется.

    Reply
  5. sergathome

    (4) а это фиолетово. все внешние функции, вызываемые при компоновке, ранее вызывались в безопасном режиме несмотря вообще ни на что, даже если они располагались в модуле прив. режима… если можете проверить — проверьте, очень интересно.

    Reply
  6. Student1C

    Подскажите, этот шаблон поможет при ошибке

    {(5, 53)}: Поле не найдено «ОсновныеНачисленияРаботниковОрганизации.ВидРасчета.Наименование»
    ОсновныеНачисленияРаботниковОрганизации.ВидРасчета.<<?>>Наименование КАК ИмяВидаРасчета,

    при открытии отчета под пользователем без полных прав.

    Reply
  7. Lusha_28

    Reply
  8. Lusha_28

    (6)не знаю, должно помочь, проверьте сами.

    Reply
  9. Student1C

    (8)Спасибо, работает, только не рассчитывается пару параметров, которые зависят от НачалоПериода и КонецПериода. Из-за чего это может быть?

    Reply
  10. Lusha_28

    (9)Я думаю надо из оригинального отчета перенести код процедуры ДоработатьКомпоновщикПередВыводом. Обычно там устанавливаются дополнительные параметры.

    Reply
  11. Student1C

    (10)

    ДоработатьКомпоновщикПередВыводом

    , не, в типовом тоже пустая процедура… Я примерно так и подумал что в этой процедуре надо что-то доработать…

    Reply
  12. Student1C

    (11) все дело в премудростях СКД, указал в запросе в параметрах в таком виде {(&КонецПериодОС)}, и все появилось )

    Я так понимаю СКД не видел это параметр без {}…

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *