Реалізація синхронізації залишків з дропшипінг-постачальником

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація синхронізації залишків з дропшипінг-постачальником
Середня
~2-3 робочих дні
Часті питання

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

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

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

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація синхронізації остатків з дропшиппінг-постачальником

Несинхронізовані остатки — головна операційна проблема дропшиппінгу. Покупець оформляє та оплачує замовлення, а постачальник повідомляє: товару немає. Повернення, недовільний клієнт, репутаційні втрати. Синхронізація має працювати досить часто, щоб цей сценарій не виникав.

Стратегії синхронізації

Стратегія Коли застосовувати Точність
Повний імпорт за розписанням FTP/CSV, немає API остатків Низька (затримка до 24 год)
Дельта-синхронізація API з підтримкою updated_since Середня (затримка 15–60 хв)
Realtime webhook Постачальник підтримує push Висока (секунди)
Realtime перевірка при додаванні в корзину Будь-який API Висока для критичних моментів

Для більшості проектів використовується комбінація: дельта-синхронізація кожні 30–60 хвилин + перевірка в реальному часі при додаванні в корзину.

Модель даних

Schema::create('dropship_stock_log', function (Blueprint $table) {
    $table->id();
    $table->foreignId('dropship_product_id')->constrained();
    $table->integer('prev_stock');
    $table->integer('new_stock');
    $table->string('source')->default('sync'); // sync | webhook | realtime_check
    $table->timestamp('recorded_at');
    $table->index(['dropship_product_id', 'recorded_at']);
});

Job повної синхронізації

class FullStockSyncJob implements ShouldQueue
{
    public $timeout = 1800; // 30 хвилин для великих каталогів

    public function handle(): void
    {
        $suppliers = Supplier::where('is_active', true)->get();

        foreach ($suppliers as $supplier) {
            SyncSupplierStockJob::dispatch($supplier)->onQueue('stock-sync');
        }
    }
}

class SyncSupplierStockJob implements ShouldQueue
{
    public $tries = 3;
    public $backoff = [60, 300, 900];

    public function handle(SupplierConnectorFactory $factory): void
    {
        $connector = $factory->make($this->supplier);
        $page      = 1;
        $updated   = 0;

        do {
            $products = $connector->getStockLevels($page, 500);

            foreach ($products as $item) {
                $dropshipProduct = DropshipProduct::where([
                    'supplier_id'  => $this->supplier->id,
                    'supplier_sku' => $item->sku,
                ])->first();

                if (!$dropshipProduct) continue;

                if ($dropshipProduct->supplier_stock !== $item->stock) {
                    $prevStock = $dropshipProduct->supplier_stock;

                    $dropshipProduct->update([
                        'supplier_stock' => $item->stock,
                        'synced_at'      => now(),
                    ]);

                    // Оновлюємо доступність у каталозі магазину
                    if ($dropshipProduct->product) {
                        $this->updateProductAvailability($dropshipProduct->product, $item->stock);
                    }

                    // Логуємо зміну
                    DropshipStockLog::create([
                        'dropship_product_id' => $dropshipProduct->id,
                        'prev_stock'          => $prevStock,
                        'new_stock'           => $item->stock,
                        'source'              => 'sync',
                        'recorded_at'         => now(),
                    ]);

                    $updated++;
                }
            }

            $page++;
        } while (count($products) === 500);

        Log::info('Stock sync completed', [
            'supplier' => $this->supplier->slug,
            'updated'  => $updated,
        ]);
    }

    private function updateProductAvailability(Product $product, int $newStock): void
    {
        $wasAvailable = $product->stock > 0;
        $isAvailable  = $newStock > 0;

        $product->update(['stock' => $newStock]);

        // Повідомляємо підписників «Повідомити про поступлення», якщо товар появився
        if (!$wasAvailable && $isAvailable) {
            event(new ProductBackInStockEvent($product));
        }
    }
}

Перевірка в реальному часі при додаванні в корзину

Періодична синхронізація знижує ризик, але не виключає його повністю. Додаємо перевірку при додаванні в корзину:

class AddToCartAction
{
    public function execute(Product $product, int $quantity, Cart $cart): void
    {
        // Для дропшиппінг-товарів перевіряємо остаток у постачальника
        if ($product->dropshipProduct && $this->shouldDoRealtimeCheck($product)) {
            $connector = SupplierConnectorFactory::make($product->dropshipProduct->supplier);
            $result    = $connector->checkStock($product->dropshipProduct->supplier_sku);

            // Оновлюємо кеш
            $product->dropshipProduct->update([
                'supplier_stock' => $result->stock,
                'synced_at'      => now(),
            ]);

            if ($result->stock < $quantity) {
                throw new InsufficientStockException(
                    available: $result->stock,
                    requested: $quantity,
                );
            }
        }

        $cart->addItem($product, $quantity);
    }

    private function shouldDoRealtimeCheck(Product $product): bool
    {
        // Перевіряємо в реальному часі, якщо остання синхронізація була більше 15 хвилин тому
        $lastSync = $product->dropshipProduct->synced_at;
        return !$lastSync || $lastSync->diffInMinutes(now()) > 15;
    }
}

Дельта-синхронізація

Якщо API постачальника підтримує параметр updated_since, повний імпорт замінюється дельта-синхронізацією:

public function getDeltaStock(\DateTimeInterface $since): array
{
    $response = $this->http->get($this->endpoint . '/stock', [
        'query' => [
            'updated_since' => $since->format('c'),
            'fields'        => 'sku,stock,updated_at',
        ],
        'headers' => $this->authHeaders(),
    ]);

    return json_decode($response->getBody(), true)['items'] ?? [];
}

Webhook від постачальника

Якщо постачальник підтримує push-повідомлення про зміну остатків:

// routes/api.php
Route::post('/webhooks/supplier/{supplier:slug}/stock', SupplierStockWebhookController::class)
    ->middleware('verify.supplier.signature');

class SupplierStockWebhookController
{
    public function __invoke(Request $request, Supplier $supplier): JsonResponse
    {
        foreach ($request->input('items', []) as $item) {
            UpdateDropshipStockJob::dispatch($supplier, $item['sku'], $item['stock']);
        }

        return response()->json(['ok' => true]);
    }
}

Розписання

// Повна синхронізація — раз на день (вночі)
$schedule->job(FullStockSyncJob::class)->dailyAt('03:00')->withoutOverlapping();

// Дельта-синхронізація — кожні 30 хвилин
$schedule->job(DeltaStockSyncJob::class)->everyThirtyMinutes()->withoutOverlapping();

Терміни

Повна синхронізація за розписанням — 2 робочих дні. Дельта-синхронізація + realtime-перевірка при додаванні в корзину — 3–4 робочих дні. Webhook-інтеграція (якщо підтримується постачальником) — ще 1 день.