Налаштування синхронізації залишків постачальників при дропшипінгу 1С-Бітрікс

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Налаштування синхронізації залишків постачальників при дропшипінгу 1С-Бітрікс
Проста
~1 робочий день
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • 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
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Налаштування синхронізації залишків постачальників при дропшипінгу 1С-Бітрікс

Покупець замовляє товар, якого вже давно немає у постачальника — класична проблема дропшипінгу. Щоб цього не сталося, залишки на сайті мають відображати реальну наявність у постачальника. Bitrix зберігає залишки в b_catalog_store_product, завдання — підтримувати цю таблицю в актуальному стані.

Архітектура синхронізації

Три варіанти отримання даних від постачальника:

Push-вебхук від постачальника — постачальник сам повідомляє при зміні залишку. Найшвидший варіант; вимагає від постачальника технічної можливості надсилати POST-запити.

Pull-фід за розкладом — агент Bitrix завантажує файл (XML/CSV/JSON) з FTP або HTTP постачальника кожні N хвилин. Найпоширеніший варіант.

Прямий доступ до API постачальника — запитуємо залишок у момент перегляду товару або додавання до кошика. Навантажує API постачальника, але дає точні дані.

Pull-синхронізація через фід

Агент Bitrix запускається за розкладом і оновлює залишки:

// /local/lib/Dropshipping/StockSync/FeedProcessor.php
namespace Local\Dropshipping\StockSync;

class FeedProcessor
{
    public function syncSupplier(int $supplierId): SyncResult
    {
        $supplier = SupplierRepository::findById($supplierId);
        $raw      = $this->downloadFeed($supplier['UF_FEED_URL'], $supplier['UF_API_KEY']);
        $items    = $this->parseFeed($raw, $supplier['UF_FEED_FORMAT']);

        $updated = 0;
        $skipped = 0;

        foreach ($items as $item) {
            $productId = SupplierProductMap::findProductId(
                $supplierId,
                $item['sku']
            );

            if (!$productId) {
                $skipped++;
                continue;
            }

            $this->updateStock($productId, $supplier['UF_STORE_ID'], (int)$item['quantity']);
            $updated++;
        }

        return new SyncResult($supplierId, $updated, $skipped);
    }

    private function updateStock(int $productId, int $storeId, int $quantity): void
    {
        $existing = \CCatalogStoreProduct::GetList(
            [],
            ['PRODUCT_ID' => $productId, 'STORE_ID' => $storeId]
        )->Fetch();

        if ($existing) {
            \CCatalogStoreProduct::Update($existing['ID'], ['AMOUNT' => $quantity]);
        } else {
            \CCatalogStoreProduct::Add([
                'PRODUCT_ID' => $productId,
                'STORE_ID'   => $storeId,
                'AMOUNT'     => $quantity,
            ]);
        }

        // Оновлюємо загальний залишок у b_catalog_product
        $total = $this->getTotalStock($productId);
        \CCatalogProduct::Update($productId, ['QUANTITY' => $total]);
    }
}

Парсинг форматів фідів

Постачальники використовують різні формати. Реалізуємо інтерфейс і конкретні парсери:

interface FeedParserInterface
{
    public function parse(string $raw): array; // повертає [{sku, quantity}, ...]
}

class CsvFeedParser implements FeedParserInterface
{
    public function parse(string $raw): array
    {
        $lines  = str_getcsv($raw, "\n");
        $result = [];

        // Визначаємо розділювач: ; або ,
        $delimiter = str_contains($lines[0], ';') ? ';' : ',';

        foreach (array_slice($lines, 1) as $line) { // пропускаємо заголовок
            [$sku, $qty] = str_getcsv($line, $delimiter);
            if ($sku && is_numeric($qty)) {
                $result[] = ['sku' => trim($sku), 'quantity' => (int)$qty];
            }
        }

        return $result;
    }
}

class XmlFeedParser implements FeedParserInterface
{
    public function parse(string $raw): array
    {
        $xml    = simplexml_load_string($raw, 'SimpleXMLElement', LIBXML_NOCDATA);
        $result = [];

        foreach ($xml->offer as $offer) {
            $result[] = [
                'sku'      => (string)$offer->vendorCode,
                'quantity' => (int)$offer->stock,
            ];
        }

        return $result;
    }
}

Push-синхронізація (вебхук від постачальника)

// /local/ajax/supplier/stock-webhook.php
\Bitrix\Main\Application::getInstance()->initializeExtended();

$key        = $_SERVER['HTTP_X_SUPPLIER_KEY'] ?? '';
$supplierId = \Local\Dropshipping\SupplierAuth::validate($key);

if (!$supplierId) {
    http_response_code(403);
    die('{"error":"Unauthorized"}');
}

$body  = json_decode(file_get_contents('php://input'), true);
$items = $body['items'] ?? [];

$processor = new \Local\Dropshipping\StockSync\FeedProcessor();
$result    = $processor->syncItems($supplierId, $items);

echo json_encode(['updated' => $result->updated, 'skipped' => $result->skipped]);

Реєстрація агента синхронізації

// Агент запускається кожні 30 хвилин для кожного постачальника
\CAgent::Add([
    'NAME'       => '\Local\Dropshipping\StockSync\SyncAgent::run();',
    'MODULE_ID'  => 'local',
    'PERIOD'     => 1800, // 30 хвилин
    'NEXT_EXEC'  => date('d.m.Y H:i:s', time() + 1800),
    'ACTIVE'     => 'Y',
]);

Обробка товарів із нульовим залишком

При обнуленні залишку важливо не просто встановити QUANTITY = 0, а й зняти товар із продажу або показати «Немає в наявності»:

private function handleZeroStock(int $productId): void
{
    // Встановлюємо статус «Немає в наявності» через b_catalog_product
    \CCatalogProduct::Update($productId, [
        'QUANTITY'             => 0,
        'QUANTITY_TRACE'       => 'Y',
        'CAN_BUY_ZERO'        => 'N',
        'NEGATIVE_AMOUNT_TRACE' => 'N',
    ]);

    // Скидаємо кеш картки товару
    \Bitrix\Main\Data\TaggedCache::clearByTag('iblock_id_' . CATALOG_IBLOCK_ID);
}

Логування та моніторинг

Кожна синхронізація логується до таблиці HL-блока StockSyncLog:

Поле Значення
UF_SUPPLIER_ID ID постачальника
UF_DATE Дата синхронізації
UF_UPDATED Кількість оновлених позицій
UF_SKIPPED Артикули без відповідності
UF_DURATION Час виконання, мс
UF_ERROR Текст помилки (якщо є)

Якщо за останні 2 години немає успішної синхронізації для активного постачальника — агент-монітор надсилає алерт на пошту технічного адміністратора.