Setting up automatic report generation in 1C-Bitrix

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

Automated Report Generation in 1C-Bitrix

Manual report exports waste time and introduce errors. Automated generation solves this through Bitrix agents and scheduled delivery. The goal is to configure the full cycle: data → file → delivery to the recipient.

Bitrix Agents as the Automation Foundation

An agent (b_agent) is a PHP function that Bitrix calls on a schedule via the CAgent mechanism. Execution is triggered by HTTP requests to the site (by default) or via cron (/bitrix/modules/main/include/cron_events.php).

Configuring cron instead of the HTTP trigger — mandatory for production:

# /etc/cron.d/bitrix
*/5 * * * * www-data /usr/bin/php /var/www/site/bitrix/modules/main/include/cron_events.php > /dev/null 2>&1

Creating an agent programmatically:

\CAgent::AddAgent(
    'GenerateDailyReports();',  // Function name
    'local',                     // Module
    'N',                         // Periodic
    86400,                       // Interval in seconds (once per day)
    '',                          // First run date (empty = immediately)
    'Y',                         // Active
    date('d.m.Y H:i:s', mktime(8, 0, 0)), // Next run time (8:00)
    30                           // Sort order
);

Report Generation Agent Template

function GenerateDailyReports(): string
{
    $reports = [
        [
            'type'      => 'orders',
            'filename'  => 'orders_' . date('Y-m-d') . '.xlsx',
            'params'    => ['date_from' => date('Y-m-d', strtotime('-1 day')), 'status' => null],
            'recipient' => '[email protected]',
        ],
        [
            'type'      => 'low_stock',
            'filename'  => 'stock_' . date('Y-m-d') . '.xlsx',
            'params'    => ['threshold' => 5],
            'recipient' => '[email protected]',
        ],
    ];

    foreach ($reports as $reportConfig) {
        try {
            $generator = ReportGeneratorFactory::create($reportConfig['type']);
            $filePath  = $generator->generate($reportConfig['params']);

            $savedName = '/upload/reports/' . $reportConfig['filename'];
            rename($filePath, $_SERVER['DOCUMENT_ROOT'] . $savedName);

            sendReportEmail($reportConfig['recipient'], $savedName, $reportConfig['filename']);

            \Bitrix\Main\Diag\Debug::writeToFile(
                date('Y-m-d H:i:s') . ' Report generated: ' . $reportConfig['filename'],
                '',
                '/local/logs/reports.log'
            );
        } catch (\Throwable $e) {
            \Bitrix\Main\Diag\Debug::writeToFile(
                date('Y-m-d H:i:s') . ' ERROR: ' . $e->getMessage(),
                '',
                '/local/logs/reports_errors.log'
            );
        }
    }

    return 'GenerateDailyReports();';
}

Sending Reports by Email

Reports are sent via a Bitrix mail event with an attachment:

function sendReportEmail(string $to, string $filePath, string $fileName): void
{
    $absolutePath = $_SERVER['DOCUMENT_ROOT'] . $filePath;

    // Attach the file via CFile and a mail event
    $event = new \Bitrix\Main\Mail\Event();
    $fields = [
        'TO'      => $to,
        'SUBJECT' => 'Auto-report: ' . $fileName . ' — ' . date('d.m.Y'),
        'BODY'    => 'Report generated automatically. File is attached.',
    ];

    // Alternative — send directly via PHPMailer with attachment
    $mail = new \PHPMailer\PHPMailer\PHPMailer(true);
    $mail->CharSet = 'UTF-8';
    $mail->setFrom('[email protected]', 'Reporting System');
    $mail->addAddress($to);
    $mail->Subject = $fields['SUBJECT'];
    $mail->Body    = $fields['BODY'];
    $mail->addAttachment($absolutePath, $fileName);
    $mail->send();
}

Report Archive Storage and Access

Generated files are stored in /upload/reports/ with 30-day history retention. Cleanup of old files is handled by a separate agent:

function CleanOldReports(): string
{
    $dir = $_SERVER['DOCUMENT_ROOT'] . '/upload/reports/';
    foreach (glob($dir . '*.xlsx') as $file) {
        if (filemtime($file) < time() - 30 * 86400) {
            unlink($file);
        }
    }
    return 'CleanOldReports();';
}

The archive page in the manager's personal account lists files with dates and download links, with access control checks.

Timeline

Configuration Timeline
1 agent + 1 report type + email 1 day
3–5 reports with different schedules 2–4 days
Report archive + UI in personal account + notifications 4–6 days