Розробка модуля звітів для 1С-Бітрікс
Стандартні звіти 1С-Бітрікс охоплюють базові потреби: продажі за періодами, залишки на складі, активність користувачів. Але щойно з'являється завдання «покажи конверсію по лійці в розбивці за менеджерами за квартал з фільтрацією за регіоном» — стандартні інструменти вичерпуються. Тут потрібен модуль з власною логікою агрегації.
Проблема з вбудованими звітами
У Бітрікс звіти розкидані по модулях: CRM (crm), інтернет-магазин (sale), склад (catalog). Дані не агрегуються між модулями. Немає конструктора кросс-модульних звітів. Немає можливості зберігати довільні вибірки та розписувати їх доставку.
Структура модуля
Модуль vendor.reports реєструється через стандартний інсталятор. Основні сутності:
-
ReportTable (
b_vendor_report) — реєстр звітів: id, name, type, config (JSON з параметрами вибірки), created_by, access_groups -
ReportScheduleTable (
b_vendor_report_schedule) — розклад автоматичної генерації: report_id, cron, format, recipients, last_run -
ReportSnapshotTable (
b_vendor_report_snapshot) — кеш згенерованих даних: report_id, data (jsonb/text), generated_at, expires_at -
ReportColumnTable (
b_vendor_report_column) — конфігурація колонок: report_id, alias, source, aggregation, format
Джерела даних
Кожне джерело реалізує DataSourceInterface:
interface DataSourceInterface
{
public function getFields(): array;
public function fetchData(array $filter, array $select, array $group): array;
}
Вбудовані джерела:
-
SaleOrderSource— дані зb_sale_order,b_sale_order_props,b_sale_basket -
CrmLeadSource— зb_crm_lead,b_crm_lead_field_multi -
CrmDealSource— зb_crm_deal,b_crm_deal_stage -
CatalogProductSource— зb_iblock_element,b_catalog_price,b_catalog_store_product -
UserActivitySource— зb_user,b_user_auth_log,b_stat_adv_back
Джерела можна комбінувати через JOIN-стратегію:
$builder = new ReportQueryBuilder();
$builder
->from('SaleOrderSource', 'o')
->join('CrmDealSource', 'd', 'o.UF_CRM_DEAL = d.ID')
->select(['o.DATE_INSERT', 'o.PRICE', 'd.STAGE_ID', 'd.ASSIGNED_BY'])
->filter(['>=o.DATE_INSERT' => $dateFrom, '<=o.DATE_INSERT' => $dateTo])
->groupBy(['d.ASSIGNED_BY', 'd.STAGE_ID']);
Агрегації та обчислювані поля
Модуль підтримує стандартні агрегати: COUNT, SUM, AVG, MIN, MAX. Обчислювані поля описуються виразами:
// Конверсія лід → угода у відсотках
'conversion' => [
'expression' => 'ROUND(COUNT(deals.ID) * 100.0 / COUNT(leads.ID), 2)',
'label' => 'Конверсія, %',
'type' => 'percent',
]
Результуючий SQL формується через QueryBuilder з прив'язкою параметрів — немає прямої конкатенації рядків.
Візуалізація
Дані надсилаються на фронтенд у форматі JSON через AJAX-кінцевої точки:
GET /bitrix/components/vendor/reports.view/ajax.php?report_id=12&date_from=2024-01-01&date_to=2024-03-31
На боці браузера — Chart.js або Highcharts (залежно від ліцензії проекту). Підтримані типи: лінійний графік, стовпчикова діаграма, кругова діаграма, таблиця з сортуванням і пагінацією.
Таблиці виводяться через стандартний CAdminList в адміністративному розділі або через кастомний компонент на фронтенді сайту.
Експорт
Згенерований звіт експортується у:
-
Excel (
.xlsx) через бібліотекуPhpSpreadsheet— встановлюється в/local/vendor/ - CSV з вибором розділювача та кодування
-
PDF через
mPDFабоTCPDF— для звітів з фіксованою вёрсткою
$exporter = ReportExporterFactory::create('xlsx');
$exporter->setData($reportData)->setColumns($columns)->download('report_' . date('Y-m-d') . '.xlsx');
Розклад та доставка
Агент \Vendor\Reports\Agent\ScheduleAgent::run() запускається щогодини, перевіряє b_vendor_report_schedule на записи з next_run <= NOW(). Генерує звіт, зберігає снапшот у b_vendor_report_snapshot, відправляє отримувачам лист з вкладенням через \Bitrix\Main\Mail\Event::send().
Формат cron-виразу сумісний зі стандартом: 0 8 * * 1 — кожен понеділок о 8:00.
Контроль доступу
Доступ до звітів управляється через групи користувачів Бітрікс. Поле access_groups у b_vendor_report зберігає JSON-масив ID груп. Перевірка:
$userGroups = $USER->GetUserGroupArray();
$reportGroups = json_decode($report['ACCESS_GROUPS'], true);
if (!array_intersect($userGroups, $reportGroups) && !$USER->IsAdmin()) {
throw new AccessDeniedException('Немає доступу до звіту');
}
Кешування
Важкі звіти (дані за рік, мільйони рядків) кешуються в b_vendor_report_snapshot. Час життя кеша встановлюється в параметрах кожного звіту. При запиті спочатку перевіряється снапшот з expires_at > NOW(); якщо є — повертається з кеша. Примусовий скидання — через кнопку в адміністративному інтерфейсі або при зміні даних (OnAfterSaleOrderUpdate).
Терміни розробки
| Етап | Тривалість |
|---|---|
| Архітектура, ORM-таблиці, інсталятор | 2 дні |
| Джерела даних (3-4 модулі Бітрікс) | 3 дні |
| QueryBuilder, агрегації, обчислювані поля | 2 дні |
| Візуалізація (Chart.js + таблиця) | 2 дні |
| Експорт Excel/CSV | 1 день |
| Розклад та доставка по email | 1 день |
| Контроль доступу, кешування | 1 день |
| Адміністративний інтерфейс, тестування | 2 дні |
Усього: 14 робочих днів. Складні кросс-модульні звіти з нестандартними джерелами оцінюються окремо після аналізу структури даних.







