Добавление собственных отчетов

Материал из ISPWiki

Перейти к: навигация, поиск

Для того чтобы добавить собственный отчет достаточно создать xml-документ с описанием: элементов интерфейса отчета, sql-запроса и текстовыми сообщениями на разных языках. Структуру отчетов, которые уже есть в биллинге, Вы можете посмотреть в файле etc/billmgr.xml. Наименование метадаты, описывающей отчет, начинается с префикса "report2.".

Содержание

Пример отчета

Ниже приведены 2 примера отчета, который показывает, какой доход приносит каждый сервер.

Для того, чтобы отчет появился в интерфейсе биллинга, необходимо создать файл /usr/local/ispmgr/etc/billmgr_mod_report2incomeserver.xml со следующем содержанием:

Пример для версии Standard, Advanced:

<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
	<metadata name="report2.incomeserver" type="report" level="7" group="mygroup" firstrun="no">
	<text name="title"/>
	<form>
		<period/>
	</form>
	<band name="project" headcolor="#f4d0bc" psort="date">
		<query>select s.id as id, s.name as name, sum(e.amount) as amount from server s left join item i on s.id=i.server left join item ia on i.id = ia.parent or 
ia.id=i.id left join expense e on e.item = ia.id  where e.cdate between '[[periodstart]]' and '[[periodend]]' group by s.id</query>
		<diagram label="name" data="amount" type="line"/>
			<col name="id" type="data" total="count" sort="digit"/>
			<col name="name" type="data" sort="alpha"/>
			<col name="amount" type="data" total="sum" sort="digit" sorted="desc"/>
	</band>
	</metadata>
	<lang name="ru">
		<messages name="report2.incomeserver">
			<msg name="amount">Доход</msg>
			<msg name="title">Отчет по доходу с сервера</msg>
			<msg name="id">Код</msg>
			<msg name="name">Наименование</msg>
		</messages>
		<messages name="reportlist">
			<msg name="name_incomeserver">Доход с сервера</msg>
			<msg name="name_mygroup">Мои отчеты</msg>
		</messages>
	</lang>
</mgrdata>

Пример для версии Corporate:

<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
	<metadata name="report2.incomeserver" type="report" level="6 7" group="mygroup" firstrun="no">
	<text name="title"/>
	<form>
		<period/>
	</form>
	<band dist="3" name="project" headcolor="#f4d0bc" psort="date">
	  		<query>select id, name from project where account=[[ses.account]]<nowiki></query>
 	  		<col name="name" type="data"/>
 	  		<band name="income" headcolor="#333333">
 		  		<query>select s.id as id, s.name as name, ifnull(sum((select sum(e.amount) from expense e where e.item=ia.id and e.cdate between 
 '<nowiki>[[periodstart]]' and '[[periodend]]')), 0) as amount from server s, item i, item ia, pricelist pl where (i.id = ia.parent or ia.id=i.id) and s.id=i.server and 
pl.id=i.price and pl.project=[[project.id]] group by s.id order by amount desc</query>
				<diagram label="name" data="amount" type="histogram"/>
				<col name="id" type="data" total="count" sort="digit"/>
				<col name="name" type="data" sort="alpha"/>
				<col name="amount" type="data" total="sum" sort="digit" sorted="desc"/>
			</band>
	  </band>
	</metadata>
	<lang name="ru">
		<messages name="report2.incomeserver">
			<msg name="amount">Доход</msg>
			<msg name="title">Отчет по доходу с сервера</msg>
			<msg name="id">Код</msg>
			<msg name="name">Наименование</msg>
		</messages>
		<messages name="reportlist">
			<msg name="name_incomeserver">Доход с сервера</msg>
			<msg name="name_mygroup">Мои отчеты</msg>
		</messages>
	</lang>
</mgrdata>

Далее необходимо перезапустить биллинг (killall billmgr).

Структура XML

Атрибуты тэга metadata

name - наименование, всегда должно начинаться с префикса report2.
type - обязательный параметр, всегда равен 'report'.
level - уровень доступа, который должен иметь пользователь, чтобы увидеть этот отчет. Перечисляется через пробел: '6 7'
group - группа, в которой будет отображаться отчет. Существующие группы: finance, marketing, promotion, support. Можно указать свою группу.
firstrun - отчет не будет выполняться при первом открытии. Опция полезна, если формирование отчета происходит долго, и необходимо сначала выбрать параметры, по которым будет сформирован отчет.

<text name="title"/> - Выводит заголовок отчета

Тэг form

Описывает поля формы.

Для того, чтобы на форме отображался диапазон дат, необходимо добавить тэг <period/>.
Если вам нужны дополнительные поля, то существует два элемента формы: input, select

Элемент input

Атрибуты:
name - наименование параметра, используется в sql запросе.
type - возможные значения: text, checkbox.
date - если задано, к полю будет прикреплена кнопка вызова календаря. Только для type="text".
default - значение по умолчанию. Только для type="text".

Элемент select

Атрибуты:
name - наименование параметра, используется в sql запросе элемента query.
query - sql запрос, заполняющий текущий элемент значениями: Например: "select u.id, u.name from user u where isgroup=1 and account=[[ses.account]]" - выборка всех отделов.
any - добавление дополнительного значения: "Любой".
values - список значений текущего элемента, через запятую. Например: "today,currentmonth,currentyear,lastday,lastmonth,lastyear,other,nodate".
default - значение по умолчанию.

В элементе select можно использовать тэг if, который позволяет скрывать определенные поля при определенном значение этого элемента.
Например:

<select name="period"  values="today,currentmonth,currentyear,lastday,lastmonth,lastyear,other,nodate" default="lastday">
	<if value="other" show="'startd','endd'"/>
</select>
<input type="text" name="periodstart" date="yes" id="startd"/>
<input type="text" name="periodend" date="yes" id="endd"/>

Элемент if

Атрибуты:

value - если значение элемента select равно этому значению, то будут показаны элементы, перечисленные в атрибуте show
show - список id элементов, которые необходимо отобразить
hide - список id элементов, которые необходимо спрятать

Элемент band

Интерфейс вывода данных описывается с помощью элемента band. Структура XML band:

<band>
	<query/>
	<diagram/>
	<col/>
	[[<band>]]
</band>

Как видно из структуры, элемент band может быть вложен в другой band. Из вложенного band можно обращаться к данным родителя, в sql запросе. Более наглядно разберем на примере ниже.

Атрибуты:

name - наименование, используется в sql запросе.
headcolor - цвет заголовка
handrep - модуль обработки, используется, если невозможно с помощью sql запроса вычислить нужные данные. Скрипт должен лежать в папке /usr/local/ispmgr/sbin.

Элемент query

Содержит sql-запрос, по которому выводится информация. В запросе необходимо использовать псевдонимы для столбцов, чтобы привязать их к элементу col. Например, "s.name as name" будет привязан к столбцу "<col name="name" ...".

В sql запросе можно использовать параметры с формы отчета, а так же если query расположен во вложенном band, значения band, расположенном на уровень выше. Имена параметров должны стоять в двойных квадратных скобках. Например:

.....
<form>
	<input name="testinput" type="text"/>
</form>
<band name="project">
	<query>select id , name from project where account = [[ses.account]]</query>
	<col name="name" type="data"/>
	<band name="testdata">
		<query>
			select .... from ... where param=[[testinput]] and project=[[project.id]]
		</query>
.....

Элемент diagram

атрибут type

Тип графика. Возможные значения: line, histogram, pie.

атрибут data

Из какой колонки взять данные для круговой диаграммы (только для type="pie").

атрибут label

Из какой колонки взять подпись к значениям.

элемент line

Один или несколько таких элементов описывают данные, которые должны быть отображены на графике.

атрибут data

Содержит имя колонки, из которой необходимо брать значения для графика.

Например:

<diagram label="cname" type="histogram">
	<line data="amount"/>
	<line data="icnt"/>
</diagram>

Элемент col

атрибут name

Имя колонки. Должно иметь уникальное значение в пределах одного metadata. Необходимо для привязки к столбцам запроса из элемента query.

атрибут type

Тип данных в колонке. Может принимать значения data (данные от sql запроса), msg (показ сообщения, соответствующего переданному значению от запроса).

атрибут sort

Задаёт тип сортировки данных в колонке. Возможные значения: alpha (алфавитная сортировка), digit (сортировка в порядке числового возрастания)

атрибут sorted

если sorted="yes", таблица по умолчанию отсортирована по этой колонке. sorted="desc" отсортировано в обратном порядке.

атрибут total

Считает итоговое значение. Возможные значения: sum - сумма; count - количество строк; avg - среднее значение.

handrep

Как говорилось выше скрипт должен располагаться в каталоге /usr/local/ispmgr/sbin/ и иметь имя вида repXXX. Часть XXX указывается в качестве атрибута handrep в XML. Скрипт принимает на вход XML с параметрами отчета и исходными данными, а на выход должен отдать XML с данными отчета.

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

XML описание отчета: <?xml version="1.0" encoding="UTF-8"?>

<mgrdata>
       <metadata name="report2.repadmin" type="report" level="7" group="mygroup" firstrun="no">
               <text name="title"/>
               <form>
                       <select name="groupadm" query="select u.id, u.name from user u where isgroup=1 and account=[[ses.account]]" any="yes"/>
                       <period/>
               </form>
               <band name="project" type="parent" headcolor="#f4d0bc">
                       <query>select id, name from project where account=[[ses.account]]</query>
                       <col name="name" type="data"/>
                       <band name="admins" headcolor="#f4d0bc" psort="date" handrep="admin.php">
                               <col name="realname" type="data" sort="alpha" total="count"/>
                               <col name="age" type="data" sort="digit" total="count"/>
                       </band>
               </band>
       </metadata>
       <lang name="ru">
               <messages name="report2.repadmin">
                       <msg name="title">Список сотрудников</msg>
                       <msg name="realname">Имя</msg>
                       <msg name="groupadm">Отдел</msg>
                       <msg name="any">Любой</msg>
                       <msg name="admins">Сотрудники</msg>
                       <msg name="age">Возраст</msg>
               </messages>
               <messages name="reportlist">
                       <msg name="name_repadmin">Список сотрудников</msg>
                       <msg name="name_mygroup">Мои отчеты</msg>
               </messages>
       </lang>
</mgrdata>

Данный XML задает описание простого отчета, который для заполнения данных будет вызывать файл /usr/local/ispmgr/sbin/repadmin.php. Примерные данные, которые получает на вход скрипт выглядят следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
 <param name="bandname">project</param>
 <param name="groupadm">any</param>
 <param name="name">repadmin</param>
 <param name="nodroprows">off</param>
 <param name="ok">Ok</param>
 <param name="period"/>
 <param name="periodend">2013-04-18</param>
 <param name="periodstart">2013-04-18</param>
 <param name="ses.account">1</param>
 <param name="ses.user.email"/>
 <param name="ses.user.lang">ru</param>
 <param name="ses.user.name">admin</param>
 <param name="ses.user.prefix_lang">_ru</param>
 <param name="ses.user.realname">John Smith</param>
</doc

В соответствии с полученными данными скрипт отбирает и возвращает какие-либо значения. В нашем случае скрипт будет добавлять в список три элемента, без анализа входных данных.

Пример скрипта:

#!/usr/bin/php
<?php
       $LOG_FILE = fopen("/usr/local/ispmgr/var/repadmin.log", "a");

       function Debug($log_str) {
               fwrite($GLOBALS["LOG_FILE"], date("M d H:i:s")." [".posix_getpid()."] ".$log_str."\n");
       }

       function defErrorHandler($errno, $errstr, $errfile, $errline) {
               if (!(error_reporting() & $errno)) {
                       return;
               }
               Debug($errfile.":".$errline." Error: ".$errno.", error message: ".$errstr);
               return true;
       }

       set_error_handler("defErrorHandler");

       $in_data = file_get_contents("php://stdin"); 
       Debug("input: ".$in_data);

       $rep_param = new SimpleXMLElement($in_data);
       $doc = new DOMDocument('1.0');
       $doc->formatOutput = true;
       $root = $doc->createElement('doc');
       $root = $doc->appendChild($root);
       $admins = $doc->createElement('admins');
       $admins = $root->appendChild($admins);
       $realname = $doc->createElement('realname');
       $realname = $admins->appendChild($realname);
       $realname_value = $doc->createTextNode('First user');
       $realname_value = $realname->appendChild($realname_value);

       $age = $doc->createElement('age');
       $age = $admins->appendChild($age);
       $age_value = $doc->createTextNode('21');
       $age_value = $realname->appendChild($age_value);

       Debug("output: ".$doc->saveXML());

       echo $doc->saveXML();
?>
Была ли эта информация полезной? Да | Нет
Личные инструменты