Собственные отчеты.

Вы можете создавать собственные отчеты для приложения BGBilling Top Reports. Для этого создайте дин. класс потомок от MobileReport

В методе getReportType вам нужно передать параметры отчета по которым пользователь сможет производить выборку. В getData вам нужно вернуть данные для построения отчета. В getTypeGraf вам нужно вернуть тип графика который будет строиться по вашим данным(гистограмма, линейный график, круговой график или табличный отчет ). В методе getOptions можно вернуть дополнительные данные которые будут отображаться при построении графика или указывать способ отображения. Ниже примеры отчетов.

Круговой отчет

Код
import java.awt.Color; import
import java.awt.Color;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import ru.bitel.bgbilling.common.BGIllegalArgumentException;
import bitel.billing.server.reports.mobile.MobileParamType;
import bitel.billing.server.reports.mobile.MobileReport;
import bitel.billing.server.reports.mobile.MobileReportType;
import bitel.billing.server.reports.mobile.Slice;
 
public class Test2 extends MobileReport
{
@Override
public MobileReportType getReportType( Connection con )
{
List<MobileParamType> list = new ArrayList<>();
// тут нам необходимо добавить параметры, по которым пользователь сможет регулировать выборку данных.
// расмотрим способ и типы параметров ниже
list.add( new MobileParamType( "Date1", MobileParamType.DateType, "От даты", "11.12.2010" ) );
list.add( new MobileParamType( "Date2", MobileParamType.DateType, "До даты", "03.03.2014" ) );
list.add( new MobileParamType( "flag1", MobileParamType.BooleanType, "По дням", "false" ) );
return new MobileReportType( "Test2", list );
}
 
@Override
public List<Object> getData()
throws BGIllegalArgumentException
{
ArrayList<Object> list = new ArrayList<>();
// Добавление в список значений. Для кругового и гистограммного отчета использовать класс Slice.
// Параметры: 1- Название, 2 - Цвет, 3 - Кол-во.
list.add( new Slice( "Приходы", new Color( 101, 214, 86 ), 23 ) );//цвет можно создать свой
list.add( new Slice( "Расходы", getColor(), 34 ) );// или вытягивать по порядку предопределенные
list.add( new Slice( "Наработка", getColor(2), 45 ) );// или по номеру
grafType = PieChartType;// задание типа графика (PieChartType,HistogramChartType,LinearChartType,TableType)
return list;
}
 
@Override
public Map<String, Object> getOptions()
{
return null;// Для круговых пока не предусмотрено особых опций.
}
}

Гистограммный отчет.

Код
public class Test1 extends MobileReport
{
@Override
public MobileReportType getReportType( Connection con )
{
List<MobileParamType> list = new ArrayList<>();
list.add( new MobileParamType( "flag1", MobileParamType.BooleanType, "По дням", "false" ) );
list.add( new MobileParamType( "Date1", MobileParamType.DateType, "От даты", "01.09.2014" ) );
list.add( new MobileParamType( "Date2", MobileParamType.DateType, "До даты", "07.09.2014" ) );
return new MobileReportType( "Приходы( гистограмма )", list );
}
 
@Override
public List<Object> getData() throws BGIllegalArgumentException
{
grafType = HistogramChartType;
try
{
boolean flag1 = getBooleanParameter( "flag1", false );
Date date1 = getDateParameter( "Date1", new Date() );// получение данных выбранных пользователем.
Date date2 = getDateParameter( "Date2", new Date() );// в первый раз передаются дефолтные значения
if( date1 == null || date2 == null && TimeUtils.dateBefore( date1, date2 ) )
{
throw new BGIllegalArgumentException();
}
StringBuilder query = new StringBuilder( "SELECT SUM(summa), DATE_FORMAT(dt, '" );
String periodParam = getParameter( "period", "w" );
if( periodParam != null)
{
String format = "";
Calendar time = Calendar.getInstance();
flag1 = true;
switch ( periodParam )
{
case "w":
time.add( Calendar.DAY_OF_YEAR, -7 );
format = "%d.%m";
break;
case "m":
time.add( Calendar.MONTH, -1 );
format = "%d.%m.%y";
break;
case "q":
time.add( Calendar.MONTH, -3 );
format = "%d.%m.%y";
break;
case "y":
flag1 = false;
time.add( Calendar.YEAR, -1 );
format = "%m.%Y";
break;
}
query.append( format );
date1 = time.getTime();
date2 = new Date();
}
else
{
query.append( flag1 ? "%d.%m" : "%m %Y" );// если по дням, то года не выдаем.
}
query.append( "'), COUNT(id) FROM contract_payment WHERE dt>=? AND dt<? GROUP BY YEAR(dt),MONTH(dt)" );
query.append( flag1 ? ",DAY(dt)" : "" );
query.append( " ORDER BY dt ASC" );
PreparedStatement ps = con.prepareStatement( query.toString() );// коннекшен просто берете и используете.
 
ps.setDate( 1, TimeUtils.convertDateToSqlDate( date1 ) );
ps.setDate( 2, TimeUtils.convertDateToSqlDate( date2 ) );
ArrayList<Object> dataList = new ArrayList<>();
ResultSet rs = ps.executeQuery();
int count = 1;
while( rs.next() )
{
dataList.add( new Slice( rs.getString( 2 ), getColor(), rs.getDouble( 1 ) ) );
}
return dataList;
}
catch( SQLException e )
{
e.printStackTrace();
}
return null;
}
 
@Override
public Map<String, Object> getOptions()
{
// Для гистограммного отчета есть возможность выставить панель быстрого вызова ниже графика.
// Для этого создаем мап для опций и мап для панели. Мап панели должен иметь значения для ключей id,values и titles.
// Где id - это ид по которому вы будет получать значения( как это было сделано выше - getParameter( "period", "w" ) ).
// values - код/значение которое пользователь может выбрать, и которое вы получите если он это сделает.
// titles - пользовательское описание кнопок панели.
HashMap<String, Object> map = new HashMap<>(), dateMap = new HashMap<>();
dateMap.put( "id", "period" );
dateMap.put( "values", "w,m,q,y" );
dateMap.put( "titles", "Неделя,Месяц,Квартал,Год" );
// Далее кладём мап панели в мам опций с ключом dataToolbar.
map.put( "dataToolbar", dateMap );
// С помощью ключа changeGrafHide, можно запретить возможность пользователю переключаться на круговой график.
// map.put( "changeGrafHide", "1" );
return map;
}
}

Линейный график.

Код
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import ru.bitel.bgbilling.common.BGIllegalArgumentException;
import bitel.billing.common.TimeUtils;
import bitel.billing.server.reports.mobile.MobileParamType;
import bitel.billing.server.reports.mobile.MobileReport;
import bitel.billing.server.reports.mobile.MobileReportType;
 
public class PaymentsMobileReport extends MobileReport
{
private ArrayList<String> descriptionList = null;
private ArrayList<String> titleList = null;
@Override
public MobileReportType getReportType( Connection con )
{
List<MobileParamType> list = new ArrayList<>();
list.add( new MobileParamType( "Date1", MobileParamType.DateType, "От даты", "11.12.2010" ) );
list.add( new MobileParamType( "Date2", MobileParamType.DateType, "До даты", "03.03.2014" ) );
list.add( new MobileParamType( "flag1", MobileParamType.BooleanType, "По дням", "false" ) );
return new MobileReportType( "Приходы( линейный )", list );
}
@Override
public List<Object> getData() throws BGIllegalArgumentException
{
// Линейный график должен вернуть в качестве данных список double значений. Каждое значение это точка на графике.
grafType = LinearChartType;
try
{
boolean flag1 = getBooleanParameter( "flag1", false );
StringBuilder query = new StringBuilder( "SELECT SUM(summa), DATE_FORMAT(dt, '" );
query.append( flag1 ? "%d.%m" : "%m %Y" );// если по дням, то года не выдаем.
query.append( "'), COUNT(id) FROM contract_payment WHERE dt>=? AND dt<? GROUP BY YEAR(dt),MONTH(dt)" );
query.append( flag1 ? ",DAY(dt)" : "" );
query.append( " ORDER BY dt ASC" );
PreparedStatement ps = con.prepareStatement( query.toString() );
Date date1 = getDateParameter( "Date1", new Date() );
Date date2 = getDateParameter( "Date2", new Date() );
if( date1 == null || date2 == null && TimeUtils.dateBefore( date1, date2 ) )
{
throw new BGIllegalArgumentException();
}
ps.setDate( 1, TimeUtils.convertDateToSqlDate( date1 ) );
ps.setDate( 2, TimeUtils.convertDateToSqlDate( date2 ) );
ArrayList<Object> dataList = new ArrayList<>();
titleList = new ArrayList<>();
descriptionList = new ArrayList<>();
ResultSet rs = ps.executeQuery();
while( rs.next() )
{
dataList.add( rs.getDouble( 1 ) );
titleList.add( rs.getString( 2 ) );// то что будет отображаться по оси абсцисс
descriptionList.add( "кол-во платежей: " + rs.getInt( 3 ) );// для доп. описания
}
return dataList;
}
catch( SQLException e )
{
e.printStackTrace();
}
return null;
}
@Override
public Map>String, Object> getOptions()
{
HashMap<String, Object> map = new HashMap<>();
// Для линейного графика можно помимо точек передать описание каждой точки
if( descriptionList != null && descriptionList.size() > 0 )
map.put( "description", descriptionList );
// и заголовки с ключами description и titles соответственно.
if( titleList != null && titleList.size() > 0 )
map.put( "titles", titleList );
return map.size() > 0 ? map : null;
}
}

Табличный отчет.

Код
@Override
public List<Object> getData() throws BGIllegalArgumentException
{
// Табличный отчет должен вернуть список содержащий список значений ячеек.
// Изменение размерности запрещено, если у вас первая строка содержала 3 столбца, то и остальные должны содержать 3.
grafType = TableType;
ArrayList<Object> list = new ArrayList<>();
ArrayList<String> rowList1 = new ArrayList<>();
ArrayList<String> rowList2 = new ArrayList<>();
rowList1.add("Столбец 1 строка 1");
rowList1.add("Столбец 2 строка 1");
rowList1.add("Столбец 3 строка 1");
rowList2.add("Столбец 1 строка 2");
rowList2.add("Столбец 2 строка 2");
rowList2.add("Столбец 3 строка 2");
list.add(rowList1);
list.add(rowList2);
return list;
}
@Override
public Map<String, Object> getOptions()
{
// С ключом titles передаем название столбцов
HashMap<String, Object> map = new HashMap<>();
ArrayList<String> titles = new ArrayList<>();
titles.add("Название 1 колонки");
titles.add("Название 2 колонки");
titles.add("Название 3 колонки");
map.put( "titles", titles );
return map;
}

Рассмотрим параметры отчетов, по которым пользователь может регулировать выборку данных. Существует 5 типов параметров: Дата(DateType), Список(ListType), Число(NumberType), Список с возможностью выбрать несколько значений(MultiSelectListType), Логический(BooleanType).Ниже приведены примеры их создания в методе getReportType.

Код
List<MobileParamType> list = new ArrayList<>();
// Дата
Calendar calendar = Calendar.getInstance();
list.add( new MobileParamType( "d1", MobileParamType.DateType, "От даты", TimeUtils.format( calendar, TimeUtils.DATE_FORMAT_PATTERN_DDMMYYYY ) ) );
// Список
LinkedHashMap<Integer, String> map = new LinkedHashMap<>();
map.put( 1, "10" );
map.put( 2, "100" );
map.put( 3, "1000" );
list.add( new MobileParamType( "limit", MobileParamType.ListType, "Макс. размер табл.", "3", map ) );
// Число
list.add( new MobileParamType( "Num1", MobileParamType.NumberType, "Отсекать меньше", "50" ) );
// Список с возможностью выбрать несколько значений
LinkedHashMap<Integer, String> fields = new LinkedHashMap<>();
fields.put( 1, "Договор" );
fields.put( 2, "Комментарий" );
fields.put( 3, "Пользователь" );
fields.put( 4, "Сумма" );
fields.put( 5, "Дата" );
fields.put( 6, "Тип платежа" );
fields.put( 7, "Примечание" );
list.add( new MobileParamType( "fields", MobileParamType.MultiSelectListType, "Поля", "1,2,3,4,5,6", fields ) );
// Логический
list.add( new MobileParamType( "flag1", MobileParamType.BooleanType, "По дням", "false" ) );

После создания класса отчета вам необходимо прописать ваш класс в настройках вашего модуля.

reports.mobile.dinamic.1.title=Мои отчеты
reports.mobile.dinamic.1.classes=mobileReports.Test2,mobileReports.Test1

В параметре reports.mobile.dinamic.1.title должно содержаться название категории отчетов, а в reports.mobile.dinamic.1.classes через запятую полное название ваших классов. Если вы решите добавить еще одну категорию, то измените 1 на 2 и т.д.