Вы можете создавать собственные отчеты для приложения 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 и т.д.