Розробка кастомних імпорт/експорт модулів 1С-Бітрікс

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Розробка кастомних імпорт/експорт модулів 1С-Бітрікс
Середня
~1-2 тижні
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1230
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    843
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    580
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    749
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    980

Розробка кастомних імпорт/експорт модулів 1С-Бітрікс

Стандартний обмін даними Бітрікс — CommerceML для 1С, CSV-імпорт в інфоблоки — покриває типові завдання. Коли джерело даних нестандартне, структура даних складна або потрібна двостороння синхронізація в реальному часі — пишемо власний модуль.

Архітектура кастомного модуля

Модуль Бітрікс — це директорія в /local/modules/{vendor}.{modulename}/, зареєстрована через RegisterModule. Структура:

local/modules/company.import/
├── install/
│   ├── index.php          # InstallDB(), UnInstallDB(), DoInstall()
│   └── db/mysql/install.sql
├── lib/
│   ├── Importer.php       # основна логіка
│   ├── Parser/
│   │   ├── XmlParser.php
│   │   └── CsvParser.php
│   └── Queue/
│       └── ImportQueue.php
├── admin/
│   └── import_settings.php  # адміністративний інтерфейс
├── include.php
└── .settings.php

Імпорт із довільних джерел

Імпорт із XML (кастомна схема, не CommerceML):

namespace Company\Import;

use Bitrix\Main\Loader;
use Bitrix\Catalog\ProductTable;

class Importer {
    private \SimpleXMLElement $xml;

    public function __construct(string $filePath) {
        Loader::includeModule('iblock');
        Loader::includeModule('catalog');
        $this->xml = simplexml_load_file($filePath);
    }

    public function run(): array {
        $stats = ['created' => 0, 'updated' => 0, 'errors' => 0];

        foreach ($this->xml->products->product as $product) {
            try {
                $this->processProduct($product, $stats);
            } catch (\Throwable $e) {
                \Bitrix\Main\Diag\Debug::writeToFile($e->getMessage(), 'IMPORT ERROR', '/bitrix/modules/company.import/error.log');
                $stats['errors']++;
            }
        }
        return $stats;
    }

    private function processProduct(\SimpleXMLElement $p, array &$stats): void {
        $externalId = (string)$p->id;
        $existing   = $this->findByExternalId($externalId);

        $fields = [
            'IBLOCK_ID'       => IMPORT_IBLOCK_ID,
            'NAME'            => (string)$p->name,
            'CODE'            => \CUtil::translit((string)$p->name, 'ru'),
            'ACTIVE'          => (string)$p->is_active === '1' ? 'Y' : 'N',
            'PROPERTY_VALUES' => [
                'EXTERNAL_ID'  => $externalId,
                'VENDOR_CODE'  => (string)$p->sku,
                'DESCRIPTION'  => (string)$p->description,
            ],
        ];

        if ($existing) {
            \CIBlockElement::Update($existing, $fields);
            $stats['updated']++;
        } else {
            $el = new \CIBlockElement();
            $newId = $el->Add($fields);
            if (!$newId) throw new \RuntimeException($el->LAST_ERROR);
            $stats['created']++;
        }

        // Оновлюємо ціну та залишок
        \CPrice::SetBasePrice($newId ?? $existing, (float)$p->price, 'RUB');
        \CCatalogProduct::Update($newId ?? $existing, ['QUANTITY' => (int)$p->stock]);
    }
}

Пакетна обробка та прогрес

При великому обсязі даних (100 000+ записів) обробка через веб-запит неможлива — timeout. Використовуємо агент Бітрікс зі збереженням прогресу:

// У таблиці зберігається: файл, поточна позиція, статистика
class ImportQueue {
    public static function processChunk(int $jobId, int $offset, int $limit = 500): array {
        $job = ImportJobTable::getById($jobId)->fetch();
        // ... читаємо $limit рядків починаючи з $offset
        // ... обробляємо
        // ... оновлюємо прогрес у БД
        return ['processed' => $count, 'total' => $job['total_rows']];
    }
}

// Агент викликається щохвилини, обробляє наступний чанк
function ImportAgent(): string {
    $activeJob = getActiveImportJob();
    if (!$activeJob) return '';

    $result = ImportQueue::processChunk($activeJob['id'], $activeJob['offset']);
    if ($activeJob['offset'] + $result['processed'] >= $result['total']) {
        markJobComplete($activeJob['id']);
        return ''; // агент завершено
    }
    return 'ImportAgent();'; // агент продовжує
}

Експорт даних

Експорт у довільний формат для зовнішньої системи:

class Exporter {
    public function exportOrders(\DateTime $from, \DateTime $to): string {
        $orders = \Bitrix\Sale\OrderTable::getList([
            'filter' => [
                '>=DATE_INSERT' => $from->format('d.m.Y H:i:s'),
                '<=DATE_INSERT' => $to->format('d.m.Y H:i:s'),
                'CANCELED'      => 'N',
            ],
            'select' => ['ID', 'ACCOUNT_NUMBER', 'PRICE', 'CURRENCY', 'DATE_INSERT', 'USER_ID'],
        ])->fetchAll();

        $xml = new \XMLWriter();
        $xml->openMemory();
        $xml->startDocument('1.0', 'UTF-8');
        $xml->startElement('orders');

        foreach ($orders as $order) {
            $xml->startElement('order');
            $xml->writeElement('id',      $order['ID']);
            $xml->writeElement('number',  $order['ACCOUNT_NUMBER']);
            $xml->writeElement('amount',  $order['PRICE']);
            $xml->writeElement('date',    $order['DATE_INSERT']->format(\DateTime::ATOM));
            // ... позиції замовлення
            $xml->endElement();
        }

        $xml->endElement();
        return $xml->outputMemory();
    }
}

Двостороння синхронізація

Найскладніше — синхронізація без втрат при одночасних змінах в обох системах.

Рішення: timestamp-based sync із полем SYNC_HASH:

ALTER TABLE b_iblock_element ADD COLUMN sync_hash VARCHAR(32);
ALTER TABLE b_iblock_element ADD COLUMN synced_at DATETIME;

При експорті записуємо хеш стану. При наступному імпорті: якщо хеш змінився в джерелі — оновлюємо в Бітрікс. Якщо хеш змінився в Бітрікс (користувач відредагував) — відправляємо зміни назад у джерело. Якщо обидва змінилися — конфлікт, логуємо для ручного розбору.

Адміністративний інтерфейс модуля

// admin/import_settings.php
require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_admin_before.php';

$APPLICATION->SetTitle('Налаштування імпорту');

// Форма налаштувань: шлях до FTP, розклад агента, маппінг полів
// Лог останніх запусків із результатами (створено/оновлено/помилки)
// Кнопка "Запустити зараз"

Формати та джерела

Формат/Джерело Інструменти Особливості
XML (кастомний) SimpleXML, XMLReader XMLReader для файлів > 100 МБ
CSV/XLSX PhpSpreadsheet, fgetcsv XLSX — бінарний, потребує бібліотеки
JSON REST API curl, Guzzle Пагінація, rate limiting
FTP/SFTP phpseclib Автоматичне завантаження файлів
1С CommerceML Вбудований обмін Бітрікс Кастомізація через події
Google Sheets Google Sheets API v4 Для невеликих обсягів

Терміни

Етап Термін
Аналіз форматів і маппінг полів 1–2 дні
Розробка парсера/експортера 3–5 днів
Пакетна обробка, агент Бітрікс 2–3 дні
Адміністративний інтерфейс 2–3 дні
Двостороння синхронізація (якщо потрібна) 3–5 днів
Тестування на реальних даних 2–3 дні

Разом: 2–3 тижні для одностороннього імпорту; 3–4 тижні для двосторонньої синхронізації.