Разработка отчетов по продажам 1С-Битрикс
Штатная аналитика модуля sale в 1С-Битрикс выдаёт плоскую таблицу заказов с минимальной группировкой. Для управления продажами этого мало: нужна сегментация по менеджерам с учётом возвратов, разбивка по категориям товаров, динамика среднего чека, анализ повторных покупок. Готовые отчёты не умеют связывать данные из разных таблиц — заказы, корзину, оплаты, свойства заказов — в единую аналитическую выборку.
Кастомные отчёты по продажам — это набор SQL/ORM-запросов, визуализация в админке и экспорт в Excel для передачи руководству или финансовому отделу.
Архитектура данных: откуда берём цифры
Все данные о продажах распределены по нескольким таблицам модуля sale:
| Таблица / ORM-класс | Что хранит | Ключевые поля |
|---|---|---|
b_sale_order / OrderTable |
Заказы | ID, DATE_INSERT, PRICE, CURRENCY, STATUS_ID, USER_ID, RESPONSIBLE_ID |
b_sale_basket / BasketTable |
Позиции корзины | ORDER_ID, PRODUCT_ID, QUANTITY, PRICE, DISCOUNT_PRICE, NAME |
b_sale_payment / PaymentTable |
Оплаты | ORDER_ID, PAY_SYSTEM_ID, SUM, PAID (Y/N), DATE_PAID |
b_sale_order_props_value / OrderPropsValueTable |
Свойства заказа | ORDER_ID, ORDER_PROPS_ID, VALUE |
b_sale_shipment / ShipmentTable |
Отгрузки | ORDER_ID, DELIVERY_ID, STATUS_ID |
Связь с каталогом. Поле PRODUCT_ID в корзине — это ID элемента инфоблока (торгового предложения). Для группировки по разделам каталога нужен JOIN с b_iblock_section_element и b_iblock_section. Если используются SKU — дополнительный JOIN через PROPERTY_CML2_LINK для выхода на родительский товар.
Deep-dive: отчёт по выручке с аналитикой менеджеров
Самый востребованный отчёт — выручка по периодам с разбивкой по менеджерам. Задача: показать, сколько каждый менеджер принёс в кассу, со скольких заказов, каков средний чек и процент отмен.
ORM-запрос:
use Bitrix\Sale\Internals\OrderTable;
use Bitrix\Main\Entity\ExpressionField;
$result = OrderTable::getList([
'select' => [
'RESPONSIBLE_ID',
'MONTH' => new ExpressionField('MONTH', "DATE_TRUNC('month', %s)", ['DATE_INSERT']),
'REVENUE' => new ExpressionField('REVENUE', 'SUM(CASE WHEN %s NOT IN (\'F\', \'CA\') THEN %s ELSE 0 END)', ['STATUS_ID', 'PRICE']),
'CANCELLED' => new ExpressionField('CANCELLED', 'SUM(CASE WHEN %s IN (\'F\', \'CA\') THEN %s ELSE 0 END)', ['STATUS_ID', 'PRICE']),
'ORDER_COUNT' => new ExpressionField('ORDER_COUNT', 'COUNT(%s)', ['ID']),
'AVG_CHECK' => new ExpressionField('AVG_CHECK', 'AVG(CASE WHEN %s NOT IN (\'F\', \'CA\') THEN %s END)', ['STATUS_ID', 'PRICE']),
],
'filter' => [
'>=DATE_INSERT' => DateTime::createFromPhp(new \DateTime('2024-01-01')),
],
'group' => ['RESPONSIBLE_ID', 'MONTH'],
'order' => ['MONTH' => 'ASC', 'REVENUE' => 'DESC'],
]);
Этот запрос отдаёт данные для таблицы и графика. Менеджер с RESPONSIBLE_ID связывается с b_user для вывода ФИО.
Метрики менеджера, которые считаем:
- Выручка (без отмен и возвратов)
- Сумма отмен — показывает качество работы
- Средний чек — сравнение между менеджерами
- Количество заказов — нагрузка
- Конверсия из «Новый» в «Выполнен» —
COUNT(status=F) / COUNT(*)по статусам - Средняя скорость обработки —
AVG(DATE_STATUS - DATE_INSERT)для перехода из начального статуса
Отчёт по товарам и категориям
Второй по важности отчёт. Показывает, какие товары и категории генерируют выручку, какие лежат мёртвым грузом.
Структура: JOIN BasketTable с OrderTable (фильтр по оплаченным заказам) и с инфоблоком каталога. Группировка по разделам с агрегацией: выручка, количество проданных единиц, средняя цена продажи, средняя скидка.
ABC-анализ встраивается в этот отчёт: товары сортируются по убыванию выручки, считается нарастающий итог, и каждому присваивается категория — A (80% выручки), B (15%), C (5%). Реализуется оконной функцией SUM() OVER (ORDER BY revenue DESC) или программно после выборки.
Визуализация и дашборд
Отчёты размещаются на кастомной странице в /local/admin/. Стек визуализации:
- Chart.js — линейные графики динамики, bar chart для сравнения менеджеров
- HTML-таблицы с сортировкой — для детальных данных
- PhpSpreadsheet — экспорт в xlsx с форматированием, формулами ИТОГО, автоширина колонок
Дашборд строится как single-page с табами: «Общая выручка», «По менеджерам», «По товарам», «ABC-анализ». Данные подгружаются через AJAX-эндпоинт, параметры фильтра (период, менеджер, категория) передаются в запросе.
Кэширование и производительность
На магазине с 50 000+ заказов ORM-запросы с группировкой выполняются 3-10 секунд. Решения:
- Материализованные представления (PostgreSQL) или summary-таблица, пересчитываемая агентом раз в час
-
Индексы — обязательны:
(DATE_INSERT, STATUS_ID)наb_sale_order,(ORDER_ID, PRODUCT_ID)наb_sale_basket -
Кэш отчёта в
managed_cacheБитрикса с TTL 1 час и инвалидацией при изменении заказа
Сроки разработки
| Этап | Содержание | Срок |
|---|---|---|
| Аналитика | Определение метрик, согласование разрезов | 1-2 дня |
| Бэкенд | ORM-запросы, оптимизация, кэширование | 3-5 дней |
| Фронтенд | Дашборд, графики, фильтры | 2-3 дня |
| Экспорт | Excel-шаблоны, форматирование | 1 день |
| Тестирование | Проверка на реальных данных, нагрузка | 1-2 дня |
Общий срок — 1-2 недели в зависимости от количества отчётов и сложности метрик. Результат — дашборд в админке с экспортом, который заменяет ручную выгрузку и обработку в Excel.







