BILLmanager содержит наиболее типовые и широко используемые отчёты, однако этого может быть недостаточно. Данная статья рассматривает создание собственного отчёта.
Для этого вам понадобятся знание SQL, а так же понимание структуры базы данных BILLmanager. Если отчёт сложный и не строится одним запросом в базу данных, вам понадобятся навыки программирования на любом знакомом вам языке.
Простейший отчёт
Разработка отчёта состоит из следующих пунктов:
- Подключение отчёта в основное меню или в список отчётов.
- Описание формы для ввода параметров, если требуется.
- Описание внешнего вида отчёта.
- Построение SQL запроса для получения данных.
Описание отчёта, как и любого другого плагина, делается с помощью xml файла /usr/local/mgr5/etc/xml/<mgr>_mod_<name>.xml, где <mgr> имя продукта, а <name> имя плагина. Например, плагин для BILLmanager и называется myreport
, тогда файл должен иметь имя /usr/local/mgr5/etc/xml/billmgr_mod_myreport.xml.
Пример добавления ссылки на отчёт в раздел Статистика в левом меню. В самом отчёте выведен список компаний провайдера.
<mgrdata>
<mainmenu level="29">
<node name="stat">
<node name="myreport"/>
</node>
</mainmenu>
<metadata name="myreport" type="report">
<band name="company">
<query>select id, name from profile where account=1</query>
<col name="name" type="data"/>
</band>
</metadata>
<lang name="ru">
<messages name="desktop">
<msg name="menu_myreport">Мой первый отчёт</msg>
</messages>
<messages name="myreport">
<msg name="title">Заголовок моего первого отчёта</msg>
</messages>
</lang>
</mgrdata>
Вложенные данные
Чтобы вывести в отчёте список методов оплаты, которые принимает каждая компания, добавьте в описание вложенный band:
<metadata name="myreport" type="report">
<band name="company">
<query>select id, name from profile where account=1</query>
<col name="name" type="data"/>
<band name="paymethod">
<query>select p.name_ru as paymethod from paymethod2company pc left join paymethod p on pc.paymethod=p.id where pc.company=[[company.id]]</query>
<col name="paymethod" type="data"/>
</band>
</band>
</metadata>
Форма ввода параметров для построения отчёта
Например, в отчёте нужно вывести только методы оплаты, минимальная сумма платежа у которых более определённого значения. Для этого добавьте форму и параметр в SQL-запрос. Чтобы отчёт не выполнялся автоматически с неопределёнными параметрами, предотвратите его построение до заполнения формы: добавьте атрибут firstrun="no"
.
Обратите внимание, что текст внутри XML нужно экранировать. Например:
select p.name_ru as paymethod, minamount from paymethod2company pc left join paymethod p on pc.paymethod=p.id where pc.company=[[company.id]] and p.minamount>=[[minamount]]
нужно записать так:
select p.name_ru as paymethod, minamount from paymethod2company pc left join paymethod p on pc.paymethod=p.id where pc.company=[[company.id]] and p.minamount>=[[minamount]]
<metadata name="myreport" type="report" firstrun="no">
<form>
<field name="minamount">
<input type="text" name="minamount" save="yes" required="yes" check="int"/>
</field>
</form>
<band name="company">
<query>select id, name from profile where account=1</query>
<col name="name" type="data"/>
<band name="paymethod">
<query>select p.name_ru as paymethod, minamount from paymethod2company pc left join paymethod p on pc.paymethod=p.id where pc.company=[[company.id]] and p.minamount>=[[minamount]]</query>
<col name="paymethod" type="data"/>
<col name="minamount" type="data" sort="digit"/>
</band>
</band>
</metadata>
Переход из отчётов в другие модули
Чтобы переходить от отчёта на форму редактирования метода оплаты,
Предположим, нужна возможность из отчёта попадать в форму редактирования метода оплаты, измените описание отчёта:
Добавьте колонку id метода оплаты с атрибутом nestedreport="paymethod.edit"
. Атрибут "nestedreport="paymethod.edit"
отвечает за создание ссылки, при нажатии на которую будет открыта новая вкладка с функцией paymethod.edit. Функции в качестве ключа будут переданы:
- значение id метода оплаты;
- все поля формы.
Так как функция paymethod.edit имеет свой параметр minamount
, для предотвращения его подмены параметром из нашей формы, переименуйте параметр на форме в repminamount
.
<metadata name="myreport" type="report" firstrun="no">
<form>
<field name="repminamount">
<input type="text" name="repminamount" save="yes" required="yes" check="int"/>
</field>
</form>
<band name="company">
<query>select id, name from profile where account=1</query>
<col name="name" type="data"/>
<band name="paymethod">
<query>select p.id, p.name_ru as paymethod, minamount from paymethod2company pc left join paymethod p on pc.paymethod=p.id where pc.company=[[company.id]] and p.minamount>=[[repminamount]]</query>
<col name="id" type="data" nestedreport="paymethod.edit"/>
<col name="paymethod" type="data"/>
<col name="minamount" type="data" sort="digit"/>
</band>
</band>
</metadata>
Переход в связанный отчёт
Чтобы добавить переход в связанный отчёт, укажите в качестве атрибута nestedreport
имя отчёта, в который вы хотите перейти.
Пример: создайте отчёт, который выводит статистику платежей в различных статусах по определённому методу оплаты. Для этого:
-
В имеющемся отчёте измените описание колонки со ссылкой:
<col name="id" type="data" nestedreport="myreport.detail"/>
-
Добавьте описание нового отчёта:
<metadata name="myreport.detail" type="report"> <band name="payments"> <query>select status, sum(paymethodamount) as amount, count(*) as cnt from payment where paymethod=[[elid]] group by status</query> <col name="status" type="msg"/> <col name="amount" type="data" convert="money" sort="digit" total="sum"/> <col name="cnt" type="data" sort="digit" total="sum"/> </band> </metadata>
-
Добавьте секцию сообщений для нового отчёта:
<messages name="myreport.detail"> <msg name="title">Статистика метода оплаты</msg> <msg name="status_1">Новый</msg> <msg name="status_4">Зачислен</msg> <msg name="status">Состояние</msg> <msg name="cnt">Количество</msg> </messages>
Обратите внимание, коды статусов были превращены в их название.
Добавление диаграмм и графиков
Чтобы вывести в отчёте диаграмму, добавьте в band
строку:
<diagram name="statuspie" label="status" data="amount" type="pie"/>
Формирование данных скриптом
Не все отчёты можно строить с помощью только XML-описания.
Основные причины почему приходится писать скрипты обработчики:
- Построение отчёта по данным, хранящимся не в базе данных. Например, список файлов, вывод каких-то внешних сервисов и т.д.
- Динамическое формирование SQL на основе входных параметров.
- Динамическое построение структуры отчёта, набора колонок, дополнительных строк статистики и т.д.
- Сложная структура данных, которую тяжело извлечь одним запросом.
Структура выходных данных, которые должен сформировать обработчик:
Данные должны содержать тег reportdata
, далее по вложенности идет тег имени band
(в нашем примере это company
). В одном отчёте можно расположить несколько band-ов один за другим. В каждом band отдельная строка данных оформляется тегом elem
, в котором каждой колонке соответствует тег с именем колонки. В примере скрипта из статьи это id, name и т.д.
Для каждого вложенного band
данные добавляются аналогичным образом, т.е. имя band
, строки (elem
), колонки. Можно использовать любое количество вложенных band
, но не рекомендуем использовать больше трёх, так как отчёты становятся трудными для понимания.
<doc>
<reportdata>
<company>
<elem>
<id>1</id>
<name>company 1</name>
<paymethod>
<elem>
<id>1</id>
<paymethod>Банковский перевод company 1</paymethod>
<minamount>100.0000</minamount>
</elem>
<elem>
<id>2</id>
<paymethod>WebMoney (WMR)</paymethod>
<minamount>0.0000</minamount>
</elem>
</paymethod>
</elem>
<elem>
<id>2</id>
<name>company 2</name>
<paymethod>
<elem>
<id>2</id>
<paymethod>WebMoney (WMR)</paymethod>
<minamount>0.0000</minamount>
</elem>
</paymethod>
</elem>
</company>
</reportdata>
</doc>
Текстовые описания
Чтобы сделать отчёт более понятным, рекомендуем снабжать его описанием и подписывать различные его блоки. Для этого используйте текстовые сообщения (теги msg
из messages
) с предопределёнными именами:
report_info
— описание к отчёту;table_[BANDNAME]
— описание к таблице с данными;diagram_[DIAGRAMNAME]
— описание к графику.
Встройка отчёта в стандартный список отчётов
Чтобы добавить собственные отчёты в раздел левого меню "Отчёты", соблюдайте условия:
- имя отчёта должно начинаться с префикса "
report.
"; - тег metadata должен содержать атрибут "group".
<metadata name="report.myreport" type="report" firstrun="no" group="mygroup">
Вы можете для имени группы использовать собственное название, либо добавить отчёт к одной из имеющихся:
- finance;
- account;
- item;
- marketing;
- support.
Вы можете локализовать сообщения:
<messages name="reportlist">
<msg name="report_mygroup">Мои отчёты</msg>
<msg name="report_myreport">Мой первый отчёт</msg>
</messages>
Права доступа
По умолчанию все авторизовавшиеся пользователи могут выполнять любые плагины. Даже если плагина нет в меню интерфейса, он доступен через API.
Чтобы отчёт был доступен только пользователям с правами администратора, добавьте атрибут level
к тегу metadata
:
<metadata name="report.myreport" type="report" firstrun="no" group="mygroup" level="admin+">
Теперь отчёт доступен только администраторам с полными правами, а так же пользователю root. Для всех остальных сотрудников или отделов можно разрешить доступ через стандартный интерфейс назначения прав.
Плагин отчёта
Плагин, который встроен в левое меню отдельным пунктом и не имеет ограничений в правах доступа:
<mgrdata>
<mainmenu level="29">
<node name="stat">
<node name="myreport"/>
</node>
</mainmenu>
<metadata name="myreport" type="report" firstrun="no">
<form>
<field name="repminamount">
<input type="text" name="repminamount" save="yes" required="yes" check="int"/>
</field>
</form>
<band name="company">
<query>select id, name from profile where account=1</query>
<col name="name" type="data"/>
<band name="paymethod">
<query>select p.id, p.name_ru as paymethod, minamount from paymethod2company pc left join paymethod p on pc.paymethod=p.id where pc.company=[[company.id]] and p.minamount>=[[repminamount]]</query>
<col name="id" type="data" nestedreport="myreport.detail"/>
<col name="paymethod" type="data"/>
<col name="minamount" type="data" sort="digit"/>
</band>
</band>
</metadata>
<metadata name="myreport.detail" type="report">
<band name="payments">
<diagram name="statuspie" label="status" data="amount" type="pie"/>
<query>select status, sum(paymethodamount) as amount, count(*) as cnt from payment where paymethod=[[elid]] group by status</query>
<col name="status" type="msg"/>
<col name="amount" type="data" convert="money" sort="digit" total="sum"/>
<col name="cnt" type="data" sort="digit" total="sum"/>
</band>
</metadata>
<lang name="ru">
<messages name="desktop">
<msg name="menu_myreport">Мой первый отчёт</msg>
</messages>
<messages name="myreport">
<msg name="title">Заголовок моего первого отчёта</msg>
<msg name="paymethod">Метод оплаты</msg>
<msg name="repminamount">Минимальный платеж</msg>
<msg name="hint_repminamount">Показывать только те способы оплаты где минимальный платеж больше указанного значения</msg>
</messages>
<messages name="myreport.detail">
<msg name="title">Статистика метода оплаты</msg>
<msg name="status_1">Новый</msg>
<msg name="status_4">Зачислен</msg>
<msg name="status">Состояние</msg>
<msg name="cnt">Количество</msg>
</messages>
</lang>
</mgrdata>
Плагин с учётом переименования отчёта и переноса его из основного меню в список отчётов:
<mgrdata>
<metadata name="report.myreport" type="report" firstrun="no" group="mygroup" level="admin+">
<form>
<field name="repminamount">
<input type="text" name="repminamount" save="yes" required="yes" check="int"/>
</field>
</form>
<band name="company">
<query>select id, name from profile where account=1</query>
<col name="name" type="data"/>
<band name="paymethod">
<query>select p.id, p.name_ru as paymethod, minamount from paymethod2company pc left join paymethod p on pc.paymethod=p.id where pc.company=[[company.id]] and p.minamount>=[[repminamount]]</query>
<col name="id" type="data" nestedreport="myreport.detail"/>
<col name="paymethod" type="data"/>
<col name="minamount" type="data" sort="digit"/>
</band>
</band>
</metadata>
<metadata name="myreport.detail" type="report" level="admin+">
<band name="payments">
<diagram name="d1" label="status" data="amount" type="pie"/>
<query>select status, sum(paymethodamount) as amount, count(*) as cnt from payment where paymethod=[[elid]] group by status</query>
<col name="status" type="msg"/>
<col name="amount" type="data" convert="money" sort="digit" total="sum"/>
<col name="cnt" type="data" sort="digit" total="sum"/>
</band>
</metadata>
<lang name="ru">
<messages name="reportlist">
<msg name="report_mygroup">Мои отчёты</msg>
<msg name="report_myreport">Мой первый отчёт</msg>
</messages>
<messages name="report.myreport">
<msg name="title">Заголовок моего первого отчёта</msg>
<msg name="paymethod">Метод оплаты</msg>
<msg name="repminamount">Минимальный платеж</msg>
<msg name="hint_repminamount">Показывать только те способы оплаты где минимальный платёж больше указанного значения</msg>
</messages>
<messages name="myreport.detail">
<msg name="title">Статистика метода оплаты</msg>
<msg name="status_1">Новый</msg>
<msg name="status_4">Зачислен</msg>
<msg name="status">Состояние</msg>
<msg name="cnt">Количество</msg>
</messages>
</lang>
</mgrdata>
Может быть полезно
- Отчёты
- Описание отчётов
- XML-описание интерфейсов
- Описание отчётов
- Описание форм
- Пример отчёта о работе отдела технической поддержки
- Разработка дополнительных модулей