Варианты использования Окна фильтрации в Отчете.Передача параметров в Датасет
Всем добрый день, делаю первые шаги в написании отчетов. Раньше работал с проектом, где встроенный был FastReport 2.5 и использовались "родные" визуальные компоненты... поэтому вопросов куча, попробую поточнее сформулировать на примере.
Версия TS XRM 3.3.0.49, MS SQL Server 2008 R2 Express
Задача: визуализировать запрос, который выбирает небольшую статистику по сотрудникам из раздела задачи.
Пример Запроса, который я написал в MS SQL Management Stadio
(SELECT COUNT(t1.ID) FROM dbo.tbl_Task AS t1 WHERE c.ID=t1.OwnerID
AND t1.TypeID = 'CED7CC70-81CB-4AB1-A9F2-521998B14723'/*Тип задачи - Звонок*/
AND t1.StartDate >= '01.03.2011'
AND t1.StartDate = '31.03.2011'
AND t1.StatusID = 'F598ECDB-4EEF-4FA8-9E69-A36B053501E5'/*Выполнена*/
AND t1.ProjectID IS NULL AND t1.OpportunityID IS NULL ) AS Q_TaskOfCall
FROM dbo.tbl_Contact AS c
WHERE EXISTS(SELECT t.ID FROM dbo.tbl_Task AS t WHERE c.ID=t.OwnerID
AND t.StartDate >= '01.03.2011'
AND t.StartDate = '31.03.2011')
ORDER BY c.Name
Хотелось бы при вводе первоначальных данных иметь возможность задать
- Интервал дат для фильтра по дате начала задачи
- Сотрудника в т.ч. по нескольким из списка.
Сервисы типа sq_StatisticByTask и ds_StatisticByTask я сделал.
В сервисе sq_StatisticByTask я добавил два параметра "BDATE"- Начальная дата периода, Конечная дата периода "EDATE" с типом Дата/Время, для отладки поставил туда значения явно.
Подзапросы оформил в виде объекта "Колонка с текстом SQL"
FROM dbo.tbl_Task AS t1
WHERE tbl_Contact.ID=t1.OwnerID
AND t1.TypeID = 'CED7CC70-81CB-4AB1-A9F2-521998B14723'/*Тип задачи - Звонок*/
AND t1.StartDate >= :BDATE
AND t1.StartDate = :EDATE
AND t1.StatusID = 'F598ECDB-4EEF-4FA8-9E69-A36B053501E5'/*Выполнена*/
AND t1.ProjectID IS NULL AND t1.OpportunityID IS NULL)
Судя по работе в предпросмотре, в подзапрос параметры передаются.
Начал делать сервис fr_StatisticByTask подключил датасет, хотел использовать стандартное окно фильтрации, НО в поля фильтра можно добавить только поля, которые явно заданы в датасете, или я ошибаюсь? Соответственно вопрос: можно ли передать из стандартного окна фильтрации даты, которых нет в запросе датасета явно? Или вариант писать только свое окно фильтрации?
Нравится
Посмотрите, пожалуйста, вот эту тему. Объяснения в ней помогут Вам понять где и как передавать параметры фильтрации.
Спасибо, за топик, я его уже читал раньше... а так же основательно порылся поиском, однако, проблемы остались.
Сделал собственное окно фильтрации предварительных данных.
Положил компоненты: два DateTimeControl'а для задания начала и конца периода отчета и LookUpControl для выбора списка сотрудников.
Пытаюсь наладить передачу параметров EADTE и BDATE в датасет отчета перед его открытием на событии OnClic кнопки ОК в собственном окне фильтрации, - пусто. Ставлю в запросе даты явно - отчет формируется, убираю- пусто. Эти же переменные я передаю в отчет, и они туда попадают благополучно и отображаются.
function btnOkOnClick(Control) { //TODO var ReportPreviewer = Self.Attributes('ReportPreviewer'); var ReportWork = Services.GetNewItemByUSI('fr_StatisticByTask'); //var ReportPrevWork = Services.GetNewItemByUSI('wnd_BaseFastReportPreview'); //----------------------- //var ReportPreviewerComponent = ReportPrevWork.Attributes('ReportPreviewer'); //SetAttribute(ReportPrevWork, 'Report', ReportWork); //----------------------- var FromDate = DateEdit1.Value; var ToDate = DateEdit2.Value; var ActsDS = Services.GetNewItemByUSI('ds_StatisticByTask'); var Param = ActsDS.SelectQuery.Parameters; Param.ItemsByName('BDATE').Value = FromDate; Param.ItemsByName('EDATE').Value = ToDate; ActsDS.Open(); //SetAttribute(ReportWork, 'StartDate', DateEdit1.Value); //SetAttribute(ReportWork, 'FinishDate', DateEdit2.Value); //ReportPrevWork.Build(); //ReportPrevWork.Prepare(); ReportPreviewer.DatasetByComponentName('ds_StatisticByTask') = ActsDS; ReportPreviewer.Report.Attributes('StartDate') = FromDate; ReportPreviewer.Report.Attributes('FinishDate') = ToDate; SendNotify(Self, MSG_OK); }
Где я накосячил?
Руслан, вот фрагмент из скрипта окна фильтрации wnd_ReportOpportunitiesDateFilterScript. Этот фрагмент выполняется по нажатию на ОК.
var Dataset = dlData.Dataset; var FromDate = Dataset.Values('From'); var ToDate = Dataset.Values('To'); var FromDateFilterEnabled = (FromDate != null); var ToDateFilterEnabled = (ToDate != null); var DatasetUSIList = ReportPreviewer.Report.Attributes('DatasetUSIList'); for (var i = 0; i < DatasetUSIList.length; i++) { var ReportDatasetUSI = DatasetUSIList[i]; var ReportDataset = ReportPreviewer.DatasetByUSI(ReportDatasetUSI); ApplyDatasetFilter(ReportDataset, 'FromDate', FromDate, FromDateFilterEnabled); ApplyDatasetFilter(ReportDataset, 'ToDate', ToDate, ToDateFilterEnabled); } ReportPreviewer.Report.Attributes('FromDate') = FromDate; ReportPreviewer.Report.Attributes('ToDate') = ToDate;
Ваша ошибка, видимо, была в том, что Вы не фильтровали датасет отчета, а пытались его получить, отфильтровать и присвоить отчету. Нужно наоборот: получить ReportPreviewer.DatasetByUSI(...) и отфильтровать через ApplyDatasetFilter, предварительно считав параметры из окна фильтрации.
Ну совсем простенький текст :-), учитывая, что там еще функция, которая присваивает массив значениям кодов датасетов и т.д. А нельзя в базовой конфигурации, сделать пару вариантов отчетов - с окном фильтрации с датой, с lookUpControl multi&singl окном выбора предварительных параметров с подробно комментированным кодом? Это наверно аццкий труд коментровать свой код для двух отчетов? Или разместите руководство по созданию отчета с стандартным и собственным окном фильтрации... Я конечно понимаю, а типа бесплатно, так ройте пацаны рогами форум...НО тех поддержка то давно не бесплатна, и идет в "обязы" с любыми продуктами...
Я готов объяснить по коду, если указанный фрагмент вызвал у Вас затруднения.
"Черных Руслан" написал:А нельзя в базовой конфигурации, сделать пару вариантов отчетов - с окном фильтрации с датой, с lookUpControl multi&singl окном выбора предварительных параметров с подробно комментированным кодом? Это наверно аццкий труд коментровать свой код для двух отчетов?
Совсем программисты разленились)) Кнопка С с контролом затыкана до дыр, наверное ? ;)
"Доленко Юрий" написал:Кнопка С с контролом затыкана до дыр, наверное ? ;)
Да, и пальцы стерты вместе с кнопками, и "отладчик" уже не запускается.... говорит - "хочу в отпуск"... ;-)
"Стоян Виталий" написал:Я готов объяснить по коду, если указанный фрагмент вызвал у Вас затруднения.
Спасибо за намек :-), я уже разобрался, проблема была действительно в том что я пытался не получить Датасет отчета, а присвоить ему другой датасет. Исправил и все заработало, сделал также и в своем окне LookUpControl с MultiSelect Window для выбора сотрудника(ов) в принципе все работает. Есть еще мелкие вопросы, если не разберусь спрошу.Как все отлажу - положу в этот топик свои труды может кому пригодяться :-)
Продолжу этот топик, так как есть предистория. При запуске отчета с правами пользователя возникает ошибка:
Оригинальное сообщение об ошибке: Запрещено разрешение "SELECT" на объект "tbl_Task" базы данных "TSDistr", схемы "dbo"
Ошибка открытия источника данных "ds_StatisticByTask".
Запрос в датасете сутью тот, что я дал в первом сообщении топика, там есть обращение к таблице tbl_Task в подзапросе фильтра.
Я понимаю, что права на чтение на таблицу tbl_Task даны только администраторам БД(явно неназначены), соответственно выборку по идее надо делать из представления vw_Task, НО смотрю на отчет "Список задач", где в датасете тоже выбирается ТАБЛИЦА, а не ПРЕДСТАВЛЕНИЕ и этот отчет с теми же правами пользователя нормально формируется. Я облазил весь датасет, просмотрел и события датасета и скрипт и события отчета... нигде явно запрос не подменяется, почему тогда работает(там тоже в запросе датасета явное чтение из tbl_Task)?
И второй вопрос, если в принципе в системе постоянно подменяется выборка из таблицы на соответствующую выборку из представления, где можно пример посмотреть в отчетах?
Проблема с подзапросом, который выполняется, как SQL-текст.
Рекомендую переписать подзапрос с Custom SQL колонки на обычный подзапрос в администраторе. После этого ошибка должна устраниться.
Другой вариант -- на OnBeforeOpen датасета подменять в запросе на выборку таблицу на представление, например такой функцией:
function ReplaceTableOnViewInColumnSQLIfNeed(SelectQuery, ColumnName,TableName, ViewName) { //Example: //ReplaceTableOnViewInColumnSQLIfNeed(SelectQuery, 'CustomSQLColumn',/\[tbl_Document\] AS/gi, '[vw_Document] AS'); //TableName = /\[tbl_Document\] AS/gi if (CurrentUser.IsAdmin||CurrentUser.IsSysAdmin) { return; } var Select; var Column; if (IsUndefined(ViewName)) { var ViewName = TableName.Replace(/tbl_/i,'vw_'); } for (var i = 0; i < SelectQuery.Count; i++) { Select = SelectQuery.Items(i); Column = Select.Columns.ItemsByAlias(ColumnName); Column.SQLText = Column.SQLText.replace(TableName,ViewName); } }
Спасибо, за верное направление...
1. Код
if (IsUndefined(ViewName)) { var ViewName = TableName.Replace(/tbl_/i,'vw_'); }
не работает - Object doesn't support this property or method. В принципе логично Replace такого метода в jscript нет, есть replace. После замены результат тот же, я думаю, что - TableName это регулярное выражение, а не просто текст и видимо к нему на прямую не применяется метод replace. Как это обойти я не придумал. Поэтому остановился на явном вводе при вызове функции имени представления -ViewName.
2. Подстановка по аналогии с TableName = /\[tbl_Document\] AS/
gi
TableName = /\[tbl_Task\] AS/gi
не дала результата, ошибка о запрете чтения из таблицы tbl_Task возникала все равно. Столкнулся с еще одной проблемой - Профайлере я не как не мог увидеть запрос...это потому что фактически он не выполнялся? Т.е. профайлер отображает только успешно завершенные запросы, а вариант нарушения прав доступа там нельзя посмотреть в тексте запроса или это особенность при вызове предпросмотра Фаст Репорта? Честно не понял зачем такая сложная строка на поиск вхождения /\[tbl_Document\] AS/
gi заменил на /tbl_Task AS/gi и все поехало...
Руслан, если второй вариант не решает проблему (остается ошибка с правами), то попробуйте первый -- перепишите подзапрос с Custom SQL на стандартный подзапрос.
Да, в общем я разобрался, просто регулярное выражение упростил, посмотрел на переменную Column.SQLText вывел ее в лог, т.к. не смог добиться от профайлера этого запроса :-(, по этому поводу и был вопрос.