Мы постарались включить в 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
Создадим очень простое XML- описание
<?xml version="1.0" encoding="UTF-8"?> <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>
Переход из отчетов в другие модули
Предположим мы хотим иметь возможность, прямо из отчета попадать в форму редактирования метода оплаты, для этого изменим наше описание отчета следующим образом
<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>
Я добавил колонку id метода оплаты с атрибутом nestedreport="paymethod.edit", который говорит о том, что нужно сделать ссылку, при нажатии на которую открывать новую вкладку с функцией paymethod.edit которой в качестве ключа будет передано значение колонки. Кроме того в вызываемую функцию будут переданы все поля формы, и поскольку функция paymethod.edit имеет свой параметр minamount, для того чтоб предотвратить его подмену параметром из нашей формы, я переименовал параметр на форме в repminamount.
Переход в другой, связанный отчет
Точно таким же образом можно переходить не в модули, а в другие связанные отчеты, указывая в качестве атрибута 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 version="1.0" encoding="UTF-8"?> <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>
За более широкой, дополнительной информацией по построению отчетов обращайтесь к соответствующий документации
Формирование данных скриптом
Конечно, очень удобно строить отчеты используя лишь XML-описание, однако не все можно сделать таким простым способом.
Основные причины почему приходится писать скрипты обработчики
- Построение отчета по данным хранящимся не в базе данных, например список файлов, вывод каких-то внешних сервисов и т.д.
- Динамическое формирование SQL на основе входных параметров
- Динамическое построение структуры отчеты, набор колонок, дополнительные строки статистики и т.д.
- Сложная структура данных, которую тяжело извлечь одним запросом
В данной статье я не буду подробно останавливаться на том как писать свои обработчики, поскольку это хорошо описано в других разделах документации, ссылки на которые будут приведены в конце статьи, остановлюсь лишь на структуре выходных данных которые должен сформировать обработчик.
В примере из данной статьи данные выглядят следующим образом
<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>
Если кратко, то данные должны содержать тэг "reportdata", далее по вложенности идет тэг имени бэнда (в нашим примере это "company"), кстати можно расположить несколько бэндов в одном отчете, один за другим.
В каждом бэнде отдельная строка данных оформляется тэгом "elem", в котором каждой колонке соответсвует тэг с именем колонки (в нашем примере это id, name и т.д.).
Для каждого вложенного бэнда данные добавляются аналогичным образом, т.е. имя бэнда, строки (elem), колонки. Можно использовать любое кол-во вложенных бэндов, однако на практике больше 3х использовать смылса нет, отчеты становятся трудными для понимания.
Текстовые описания
Чтобы сделать отчет более понятным, мы рекомендуем снабжать его описанием, а так же подписывать различные его блоки, в этом вам помогут текстовые сообщения (тэги msg из messages) с предопределенными именами
- Описание к отчету - report_info
- Описание к таблице с данными - table_[BANDNAME]
- Описание к графику - diagram_[DIAGRAMNAME]
Встройка отчета в стандартный список отчетов
Поскольку в BILLmanager, большое кол-во отчетов, не разумно добавлять их все в основное меню, они собраны все в одном месте, меню "Отчеты".
Для того что бы ваш отчет добавить в этот список, необходимо соблюсти 2 условия
- имя отчета должно начинаться с префикса "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. Для всех остальных сотрудников или отделов можно разрешить доступ через стандартный интерфейс назначения прав.
Финальный вариант плагина, с учетом переименования отчета и переноса его из основного меню в список отчетов, выглядит таким образом
<?xml version="1.0" encoding="UTF-8"?> <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>
Полезные ссылки на другие статьи