Закажите бесплатную презентацию продуктов РосБизнесСофт прямо сейчас!
Отчет представляет собой особый тип «Формы», называемый «Индивидуальная форма редактирования». Это форма редактирования, привязанная к конкретному «Объекту» (id), а не «Типу объекта». Т.е. у каждого объекта есть своя «Индивидуальная форма редактирования».
Для создания нового отчета необходимо зайти в “Справочники” — “Настройки” — “Отчеты” (/settings/references/reports).
При создании нового отчета заполнить поля:

Затем необходимо зайти в “Конфигуратор” — “Отчеты” (references.reports) /configurator/references.reports/, создать новую «Форму», выбрать тип формы «Инд. форма редактирования», заполнить поля:

Созданный отчет будет отображаться в разделе “Отчеты” (/olap/) и будет доступен по ссылке /olap/budgets/.
Любой отчет должен наследоваться от \Kernel\Actions\Reports\Base и должен содержать следующие методы:
Предустановленные фильтры отчета addFilters():
protected function addFilters()
{
...
}Фильтры представляет собой объекты Http\Elements\Input и предоставляют интерфейс для работы со значениями.

Для установки значения в поле фильтр по умолчанию используется метод setDefault():
$this->filters->add("engineer", "Select", $this->Data->{'references.employees'}, true)->setDefault($this->User->getEmployee()->id);В разделе «Фильтры» в поле «Инженер» подставится текущий пользователь.
Все условия, запрос к базе и вывод таблицы прописываются в методе buildReport():
protected function buildReport()
{
...
}
Для работы с базой данных необходимо подключить класс:
use Kernel\Database\Database as DB;
Для выборки используется метод select().
Чтобы указать алиас, необходимо указать поле как массив и вторым параметром указать алиас.
$this->DB->{"documents.orders"} // название структуры, откуда берем данные
->select(
DB::Field('number', 'documents.orders'), // номер счета
[DB::Field('name', 'references.employees'), 'responsible'] // имя ответственного менеджера за счет
)
Условие «РАВНО (=)»
Пример: Поле «Номер» в документе «Счете» = «10»
$where = DB::_equal(DB::Field('responsible', 'documents.orders'), 10);Условие “БОЛЬШЕ (>)”
Пример: Поле «Номер» в документе «Счете» > «4»
$where = DB::_more(DB::Field(number, 'documents.orders'), 4);
Условие “МЕНЬШЕ (<)”
Пример: Поле «Номер» в документе «Счете» < «100»
$where = DB::_less(DB::Field('responsible', 'documents.orders'), 100);Условие “И”
Пример: Добавить еще одно условие к существующему, например «Статус» = «1»
$where = DB::_and($where, DB::_equal(DB::Field('status', 'documents.orders'), 2))Условие “ИЛИ”
Пример: Добавить условие ИЛИ к существующему условию
$whereOr = DB::_or(
DB::Field(DB::Field('status', 'documents.orders'), 2)),
DB::Field(DB::Field('status', 'documents.orders'), 4))
);
$where = DB::_and($where, $whereOr);Для этого используется DBFunction.
Пример: добавим функцию «SUM»
$this->DB->{"documents.orders"}
->select(
[DB::DBFunction('SUM', DB::Field('total', 'documents.orders')), 'total']
)
Пример:
$this->DB->{"documents.orders"}
->select(
[DB::DBFunction('SUM', DB::Field('total', 'documents.orders')), 'total']
)
->leftJoin('references.companies', DB::_equal(DB::Field('id', 'references.companies'), DB::Field('owner', 'references.companies')))
Метод вызывается в самом конце запроса.
->group(DB::Field('owner', 'documents.orders'))Сортировка записей. По умолчанию идет ASC.
Пример:
->order(DB::Field('owner', 'documents.orders'))
// или DESC
->order([DB::Field('owner', 'documents.orders'), DESС])Ограничение количества записей на вывод.
->limit(100)
Пример: вывести список сгруппированных счетов с суммой больше 4000
->having(DB::_more(DB::DBFunction('SUM', DB::Field('total', 'documents.orders')), 4000))Для вывода данных в шаблон используется метод fillFromArray().
fillFromArray($data, $mapping, $afterFunc = null)
Где:
Пример:
$this->tables->report->fillFromArray($data, [
"supplier_order" => function($row){
return "<a href='/supplier_order/". $row['supplierOrderId'] ."' target='_blank'>№ ". $row['supplierOrderId'] ." от ". date('d.m.Y', strtotime($row['supplierOrderDate'])) ."</a>";
},
"contract" => function($row){
return "<a href='/contracts/". $row['contractId'] ."' target='_blank'>№ ". $row['contractNumber'] ." от ". date('d.m.Y', strtotime($row['contractDate'])) ."</a>";
},
"product" => function($row){
return "<a href='/products/". $row['productId'] ."' target='_blank'>". $row['productName'] ."</a>";
},
"number" => function($row){
return $row['productNumber'];
},
"status" => function($row){
return "";
},
],
function($row, $id) { // Используется для группировки, см. ниже.
$row->correspondId = $id;
}
)->printExport($this->page);
Для вывода группировки в таблицу используется метод titleGroup(). Функция группирует таблицу по полю и может подсчитывать суммы по набору полей для поля.
titleGroup(array $data, Table $table, array $fieldPairs, array $sumFields, array $map, [Function $afterFunc])
Где:
Важно! Метод ожидает уже отсортированных данных и не будет переупорядочить их. Он не может изменить входные данные. Он только добавляет поля в таблицу.
Такой подход позволяет последовательно применять метод по нескольку раз. Например, нужно сгруппировать вывод по товару, а для каждого товара подсчитать сумму по менеджерам. Просто примените метод два раза подряд, передав разные поля вторым аргументом.
Если требуется группировка по менеджерам, а затем по товарам, то порядок вызовов метода неважен, важно то, как отсортированы входные данные. Измените запрос к БД (или к ORM) для достижения целей.
Пример:
$this->titleGroup($data, $this->tables->report, ["productId" => "product"], ["number"], [
"product" => function($row)
{
return $row["productName"];
},
"number" => function($row)
{
// выведет сумму по полю number
return abs($row["number"]);
},
],function($row)
{
$row->params = "class='sumRow'";
});
Где:

Важно! Чтобы работал группировка, необходимо в метод fillFromArray() добавить в конец параметров анонимную функцию:
function($row, $id) { $row->correspondId = $id; }См. полный пример выше.
Для суммирования используется функция sumData(). Она добавляет строку в конец отчёта.
$this->sumData($data, $this->tables->report, ["number", "total", "profit"],
[
"number",
"total" => function($row) {
return Text::money($row["total"]);
},
"profit" => function($row) {
return Text::money($row["profit"]);
}
],
"company"
);
Где:
Добавление графика в отчетДля построения графиков используется сторонняя графическая библиотека.
С примерами построения отчетов можно ознакомиться по ссылкам:
/configurator/references.reports/?formname=reports/top10/edit /configurator/references.reports/?formname=olap/funnel_sales/edit


<?php
namespace Applications\Reports\Debts;
// Импортируем модули
use Kernel\Database\Database as DB;
...
use Kernel\Framework\Format;
// Создаем класс отчета (обратите внимание на наследование)
class Edit extends \Kernel\Actions\Reports\Base {
// Добавление фильтров (см. выше)
protected function addFilters() {
// Метод setDefault работает так же, как и для полей
filters->add("dateMin", "Date")->setDefault(time());
...
// Третий аргумент для поля выбора — структура значений. Четвертый — значение пустого поля
//(если не задано, выбор поля обязателен).
$this->filters->add("manager", "Select", $this->Data->References->Employees, true);
..
}
// Обратите внимание, названия составляющих шаблонного метода немного отличаются.
protected function buildReport() {
// Опережающее определение полей позволяет экспорту работать корректно.
$this->tables->report->defineColumns("num",
..
, "manager");
// Условие для поиска по БД.
$condition = DB::_and(
...
);
// С учетом фильтра
if ($this->filters->manager->get())
...
// Строим запрос к базе
$data = $this->DB->{"documents.orders"}->select(
[DB::Field("name", "references.employees"), "manager"],
...
)->
where($condition)->
join(
...
)->
// Обратите внимание на передачу константы для поиска по именам структуры.
execute(DATA_NAMES)->result();
...
// Для начала, наполняем таблицу
$this->tables->report->fillFromArray($data,
...
);
// Добавляем суммирование полей (см. выше)
$this->sumData($data, $this->tables->report, ["sum", "dsum", "prepay"],
...
);
// Эта переменная означает количество полей, "без данных" (в данном случае одно, для суммы).
$this->maxRow = 1;
}
// Заканчиваем обычным для такого дела определением абстрактных методов базового класса.
protected function onPlay() { }
protected function onChange() { }
protected function onSave() { }
}
?>
Подробнее про методы класса DataBase можно ознакомиться по ссылке.