Как известно, в состав библиотеки стандартных подсистем (БСП) входит подсистема рассылки отчетов, позволяющая по заданному расписанию осуществлять рассылку отчетов получателям. Одним из режимов работы данного механизма является персонализированная рассылка, когда каждому из указанных получателей отправляется свой отчет, то есть отчет формируется с установкой отбора по получателю. В процедуре рассылки в цикле по каждому из возможных получателей формируется отчет с отбором по получателю и, если он не пустой, отправляется получателю на почту.
Проблема заключается в том, что по большинству получателей будут сформированы пустые отчеты, так как в качестве получателей указываются группы, включающие всех потенциальных получателей отчета (например, группа пользователей "Все пользователи"). В крупных системах количество пользователей в справочнике "Пользователи" может достигать нескольких тысяч, то есть при запуске такой рассылки мы получим огромное количество запросов в цикле, что приведет к избыточной нагрузке на систему.
Таким образом, есть необходимость каким-то способом предварительно отобрать получателей отчета, по которым будут сформированы не пустые отчеты. В данной разработке предлагается следующий подход к решению поставленной задачи.
- Создать в отчете новую схему компоновки данных ОтборПолучателейОтчетов для отбора получателей рассылки с учетом возможных установленных отборов/параметров в отчете (то есть продублировать состав параметров/отборов рассылаемого варианта отчета). В качестве альтернативы вместо добавления новой схемы для отбора получателей также можно просто добавить новый вариант отчета с выбором получателей.
- В модуль объекта отчета добавить экспортную функцию СформироватьСписокПолучателейРассылки(), возвращающую таблицу получателей отчета. Таблица получателей формируется по СКД ОтборПолучателейОтчетов с учетом переданных пользовательских настроек (параметров/отборов) формируемого отчета.
- В процедуру ПередФормированиемСпискаПолучателейРассылки() общего модуля РассылкаОтчетовПереопределяемый добавить вызов функции СформироватьСписокПолучателейРассылки() модуля отчета. Скорректировать список получателей отчета по полученной таблице получателей.
Код процедуры ПередФормированиемСпискаПолучателейРассылки() общего модуля РассылкаОтчетовПереопределяемый:
Процедура ПередФормированиемСпискаПолучателейРассылки(ПараметрыПолучателей, Запрос, СтандартнаяОбработка, Результат)
Персонализирована = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ПараметрыПолучателей.Ссылка, "Персонализирована");
Если Персонализирована Тогда
лЗапрос = Новый Запрос("ВЫБРАТЬ
| РассылкиОтчетовОтчеты.Отчет КАК ВариантОтчета,
| РассылкиОтчетовОтчеты.Настройки КАК Настройки
|ИЗ
| Справочник.РассылкиОтчетов.Отчеты КАК РассылкиОтчетовОтчеты
|ГДЕ
| РассылкиОтчетовОтчеты.Ссылка = &Ссылка
| И РассылкиОтчетовОтчеты.Отчет.Отчет В(&МассивОтчетов)");
// массив отчетов с переопределением списка получателей для персонализированных рассылок
МассивОтчетовСписокПолучателей = Новый Массив;
МассивОтчетовСписокПолучателей.Добавить(ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Отчет._ДемоФайлы"));
лЗапрос.УстановитьПараметр("Ссылка", ПараметрыПолучателей.Ссылка);
лЗапрос.УстановитьПараметр("МассивОтчетов", МассивОтчетовСписокПолучателей);
Выборка = лЗапрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ВариантОтчета = Выборка.ВариантОтчета;
Настройки = Выборка.Настройки.Получить();
Параметры = Новый Структура("СсылкаВарианта, ПользовательскиеНастройкиКД", ВариантОтчета, Настройки);
Подключение = ВариантыОтчетов.ПодключитьОтчетИЗагрузитьНастройки(Параметры);
тзПолучателей = Подключение.Объект.СформироватьСписокПолучателейРассылки();
ТекстЗапроса =
"ВЫБРАТЬ
| ТаблицаПолучателейОтчета.Получатель
|ПОМЕСТИТЬ ТаблицаПолучателейОтчета
|ИЗ
| &ТаблицаПолучателейОтчета КАК ТаблицаПолучателейОтчета
|;
|
|////////////////////////////////////////////////////////////////////////////////
|" + Запрос.Текст;
Схема = Новый СхемаЗапроса;
Схема.УстановитьТекстЗапроса(ТекстЗапроса);
Пакет = Схема.ПакетЗапросов[Схема.ПакетЗапросов.Количество()-1];
Оператор = Пакет.Операторы.Получить(0);
Источник = Оператор.Источники.Добавить("ТаблицаПолучателейОтчета", "ТаблицаПолучателейОтчета");
ТипПолучателей = ПараметрыПолучателей.ТипПолучателейРассылки.КлючОбъектаМетаданных.Получить();
Если ТипПолучателей = Тип("СправочникСсылка.Пользователи") Тогда
Источник.Соединения.Добавить("Получатели", "Получатели.Получатель = ТаблицаПолучателейОтчета.Получатель");
Иначе
Источник.Соединения.Добавить("Получатели", "Получатели.Ссылка = ТаблицаПолучателейОтчета.Получатель");
КонецЕсли;
Источник.Соединения[0].ТипСоединения = ТипСоединенияСхемыЗапроса.Внутреннее;
Запрос.Текст = Схема.ПолучитьТекстЗапроса();
Запрос.УстановитьПараметр("ТаблицаПолучателейОтчета", тзПолучателей);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Код функции СформироватьСписокПолучателейРассылки() модуля объекта отчета:
Функция СформироватьСписокПолучателейРассылки() Экспорт
СхемаСКД = ПолучитьМакет("ОтборПолучателейРассылки");
КомпоновщикНастроекДанныхОтчета = Новый КомпоновщикНастроекКомпоновкиДанных;
КомпоновщикНастроекДанныхОтчета.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаСКД));
КомпоновщикНастроекДанныхОтчета.ЗагрузитьНастройки(СхемаСКД.НастройкиПоУмолчанию);
НастройкиПараметрыДанных = КомпоновщикНастроекДанныхОтчета.Настройки.ПараметрыДанных;
НастройкиОтбор = КомпоновщикНастроекДанныхОтчета.Настройки.Отбор;
НастройкиОтбораПолучателей = КомпоновщикНастроек.ПользовательскиеНастройки;
// переносим пользовательские настройки формируемого отчета в настройки СКД ОтборПолучателейРассылки
Для каждого ЭлементНастройки из НастройкиОтбораПолучателей.Элементы Цикл
Если ТипЗнч(ЭлементНастройки)=Тип("ЗначениеПараметраНастроекКомпоновкиДанных") тогда
Для каждого ЭлементТекущейНастройки из НастройкиПараметрыДанных.Элементы цикл
Если СокрЛП(ЭлементНастройки.Параметр)=СокрЛП(ЭлементТекущейНастройки.Параметр) тогда
ЭлементТекущейНастройки.Использование = ЭлементНастройки.Использование;
ЭлементТекущейНастройки.Значение = ЭлементНастройки.Значение;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если ТипЗнч(ЭлементНастройки)=Тип("ЭлементОтбораКомпоновкиДанных") тогда
ЭлементОтбораКД = ОтчетыКлиентСервер.ПолучитьОбъектПоПользовательскомуИдентификатору(КомпоновщикНастроек.Настройки, ЭлементНастройки.ИдентификаторПользовательскойНастройки);
Для каждого ЭлементОтбора из НастройкиОтбор.Элементы Цикл
Если СокрЛП(ЭлементОтбора.ЛевоеЗначение) = СокрЛП(ЭлементОтбораКД.ЛевоеЗначение) Тогда
ЭлементОтбора.Использование = ЭлементНастройки.Использование;
ЭлементОтбора.ВидСравнения = ЭлементНастройки.ВидСравнения;
ЭлементОтбора.ПравоеЗначение = ЭлементНастройки.ПравоеЗначение;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = КомпоновщикМакета.Выполнить(СхемаСКД, КомпоновщикНастроекДанныхОтчета.ПолучитьНастройки(),,,Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(Макет);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
тзПолучателей = Новый ТаблицаЗначений;
ПроцессорВывода.УстановитьОбъект(тзПолучателей);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Возврат тзПолучателей;
КонецФункции
В качестве примера к публикации прикладывается расширение, реализующее описанный механизм для отчета _ДемоФайлы из демонстрационной базы БСП.
До подключения расширения список получателей рассылки выглядел таким образом (выводятся все пользователи):
После подключения расширения выводятся только пользователи, по которым будут сформированы не пустые отчеты:
Дополнительная информация
Тестирование подсистемы проводилось на версии платформы 8.3.21.1302 (режим совместимости конфигурации 8.3.14). При разработке использовалась Библиотека стандартных подсистем версии 3.1.7.