Developing 1C-Bitrix sales reports

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Developing sales reports for 1C-Bitrix

Stock analytics of sale module in 1C-Bitrix outputs flat order table with minimal grouping. For managing sales this is not enough: you need segmentation by managers with returns accounted for, breakdown by product categories, average check dynamics, repeat purchase analysis. Ready reports can't connect data from different tables — orders, basket, payments, order properties — into single analytics query.

Custom sales reports — this is set of SQL/ORM queries, visualization in admin panel and Excel export for passing to management or finance department.

Data architecture: where the numbers come from

All sales data distributed across multiple sale module tables:

Table / ORM-class What stores Key fields
b_sale_order / OrderTable Orders ID, DATE_INSERT, PRICE, CURRENCY, STATUS_ID, USER_ID, RESPONSIBLE_ID
b_sale_basket / BasketTable Basket positions ORDER_ID, PRODUCT_ID, QUANTITY, PRICE, DISCOUNT_PRICE, NAME
b_sale_payment / PaymentTable Payments ORDER_ID, PAY_SYSTEM_ID, SUM, PAID (Y/N), DATE_PAID
b_sale_order_props_value / OrderPropsValueTable Order properties ORDER_ID, ORDER_PROPS_ID, VALUE
b_sale_shipment / ShipmentTable Shipments ORDER_ID, DELIVERY_ID, STATUS_ID

Connection with catalog. The PRODUCT_ID field in basket — is ID of iblock element (trade offer). To group by catalog sections you need JOIN with b_iblock_section_element and b_iblock_section. If using SKU — additional JOIN via PROPERTY_CML2_LINK to reach parent product.

Deep-dive: revenue report with manager analytics

Most demanded report — revenue by periods with manager breakdown. Task: show how much each manager brought in, from how many orders, what's average check and cancellation percentage.

ORM query:

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'],
]);

This query returns data for table and graph. Manager with RESPONSIBLE_ID linked with b_user for displaying full name.

Manager metrics being calculated:

  • Revenue (without cancellations and returns)
  • Cancellation sum — shows work quality
  • Average check — comparison between managers
  • Order count — workload
  • Conversion from "New" to "Completed" — COUNT(status=F) / COUNT(*) by statuses
  • Average processing speed — AVG(DATE_STATUS - DATE_INSERT) for transition from initial status

Report by products and categories

Second most important report. Shows which products and categories generate revenue, which are dead weight.

Structure: JOIN BasketTable with OrderTable (filter by paid orders) and with catalog iblock. Grouping by sections with aggregation: revenue, units sold, average sale price, average discount.

ABC-analysis embedded into this report: products sorted by revenue descending, cumulative total calculated, and each assigned category — A (80% revenue), B (15%), C (5%). Implemented via window function SUM() OVER (ORDER BY revenue DESC) or programmatically after query.

Visualization and dashboard

Reports placed on custom page in /local/admin/. Visualization stack:

  • Chart.js — line graphs of dynamics, bar charts for manager comparison
  • HTML tables with sorting — for detailed data
  • PhpSpreadsheet — export to xlsx with formatting, TOTAL formulas, auto column width

Dashboard built as single-page with tabs: "Overall revenue", "By managers", "By products", "ABC-analysis". Data loaded via AJAX endpoint, filter parameters (period, manager, category) passed in request.

Caching and performance

On store with 50,000+ orders ORM queries with grouping execute 3-10 seconds. Solutions:

  • Materialized views (PostgreSQL) or summary table, recalculated by agent once an hour
  • Indexes — mandatory: (DATE_INSERT, STATUS_ID) on b_sale_order, (ORDER_ID, PRODUCT_ID) on b_sale_basket
  • Report cache in Bitrix managed_cache with TTL 1 hour and invalidation on order change

Development timeline

Stage Content Timeline
Analysis Metrics definition, aggregation agreement 1-2 days
Backend ORM queries, optimization, caching 3-5 days
Frontend Dashboard, graphs, filters 2-3 days
Export Excel templates, formatting 1 day
Testing Real data checks, load testing 1-2 days

Total timeline — 1-2 weeks depending on number of reports and metrics complexity. Result — admin dashboard with export, replacing manual Excel export and processing.