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

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, 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 check при добавлении в корзину Любой 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 день.