Реалізація синхронізації залишків з дропшипінг-постачальником
Сталкивались із ситуацією, коли покупець оформлює замовлення, а постачальник повідомляє: товару немає в наявності? Це призводить до повернень, невдоволення клієнтів і втрати репутації. Особливо болісно, коли на сайті відображається наявність, а реальний залишок уже нульовий. Різниця між вітриною та реальністю може становити години, а для популярних позицій — хвилини. За статистикою, до 30% замовлень у дропшипінгу скасовуються через відсутність товару — автоматична синхронізація скорочує цей показник до 5%. Ми спеціалізуємося на автоматизації дропшипінгу та синхронізації залишків з постачальниками. У цій статті покажемо, як налаштувати надійну синхронізацію, щоб таких проблем не виникало.
Як вибрати стратегію синхронізації?
Опишемо основні стратегії, які ми використовуємо залежно від можливостей постачальника та вимог до точності. Кожна стратегія має свої компроміси щодо швидкості та навантаження.
| Стратегія | Коли застосовувати | Точність | Частота оновлення |
|---|---|---|---|
| Повний імпорт за розкладом | FTP/CSV, немає API залишків | Низька (затримка до 24 год) | Раз на добу |
| Дельта-синхронізація | API з підтримкою updated_since |
Середня (затримка 15–60 хв) | Кожні 30–60 хвилин |
| Realtime webhook | Постачальник підтримує push | Висока (секунди) | Миттєво |
| Realtime перевірка при додаванні в кошик | Будь-який API | Висока для критичних моментів | За запитом |
Для більшості проєктів ми використовуємо комбінацію: дельта-синхронізація кожні 30–60 хвилин + перевірка в реальному часі при додаванні в кошик. Це забезпечує баланс між навантаженням та актуальністю. Дельта-синхронізація скорочує обсяг переданих даних до 10% від повного імпорту, що значно знижує час обробки.
Чому realtime-перевірка необхідна?
Періодична синхронізація знижує ризик, але не виключає його. Навіть при дельта-синхронізації можлива ситуація, коли залишок змінився між перевірками. Тому додаємо перевірку в момент додавання товару в кошик. Це вирішує проблему last-mile accuracy. Нижче наведено приклад реалізації на Laravel.
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;
}
}
Модель даних та логування змін
Для відстеження змін залишків створюємо таблицю логів. Це спрощує налагодження та аудит.
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']);
});
Повна синхронізація за розкладом
Раз на добу (зазвичай вночі) запускаємо повну синхронізацію, щоб виявити розбіжності, які не потрапили в дельту. Реалізація складається з двох задач: одна диспатчить по постачальниках, друга обробляє кожного постачальника.
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));
}
}
}
Дельта-синхронізація та webhook
Якщо API постачальника підтримує параметр updated_since, замість повного імпорту використовуємо дельта-синхронізацію — завантажуємо лише змінені записи. Це знижує навантаження та пришвидшує оновлення. Для постачальників, які підтримують push-сповіщення, налаштовуємо Webhook — залишки оновлюються за секунди.
// 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]);
}
}
Які ризики виникають при відсутності синхронізації?
Без автоматизації ви стикаєтеся з ручним звірянням залишків, що забирає години щодня. Клієнти бачать недостовірні дані, що веде до скасувань замовлень і погіршення позицій у пошуку через високий відсоток повернень. За нашими даними, автоматизація скорочує частку скасувань замовлень з 30% до 5%, що економить до 15% від обороту магазину. Для магазину з оборотом $100 000 на місяць це означає збереження $15 000 — рішення окупається за 2–3 місяці.
Як уникнути N+1 запитів при повній синхронізації?
У коді SyncSupplierStockJob кожен DropshipProduct::where всередині циклу — потенційний N+1. Для каталогу в 10 000 SKU це 10 000 запитів. Оптимізуємо: завантажуємо всі наявні записи постачальника одним запитом у Collection, потім звіряємо за ключем. Альтернатива — використовувати updateOrCreate з масовим оновленням, але потрібна обережність з версіонуванням.
Моніторинг та сповіщення
Налаштовуємо оповіщення в Telegram/Slack при збоях синхронізації. Логується кожен крок: кількість оновлених записів, час виконання, помилки API. Це дозволяє швидко реагувати на проблеми. Наприклад, при падінні HTTP-статусу 503 від постачальника задача автоматично повториться через 5 хвилин з експоненційною затримкою.
Приклад конфігурації черг у Laravel
'stock-sync' => [
'driver' => 'database',
'connection' => 'mysql',
'table' => 'jobs',
'queue' => 'stock-sync',
'retry_after' => 1800,
],
Використовуємо withoutOverlapping на cron-задачах, щоб уникнути дублювання.
Що входить у реалізацію синхронізації
| Етап | Склад робіт |
|---|---|
| Аналіз API постачальника | Вивчення документації, тестування ендпоінтів, виявлення лімітів |
| Проєктування моделі даних | Створення схеми БД для зберігання залишків та логів |
| Реалізація ядра синхронізації | Написання коду для повної, дельта-синхронізації та webhook |
| Realtime-перевірка | Інтеграція перевірки залишку при додаванні в кошик |
| Тестування | Навантажувальне тестування, перевірка коректності при збоях |
| Документація | Опис архітектури, інструкція з розгортання |
| Навчання | Демонстрація роботи, передача знань вашій команді |
| Підтримка перший місяць | Моніторинг, виправлення помилок, доопрацювання за необхідності |
Чому варто довіритися нам?
Ми працюємо на ринку веб-розробки більше 5 років і реалізували понад 50 інтеграцій з постачальниками для інтернет-магазинів. У нашій команді 10 розробників, що спеціалізуються на Laravel, Vue.js та високонавантажених системах. Ми гарантуємо, що синхронізація працюватиме стабільно, а в разі збоїв — оперативно відновимо. Зв'яжіться з нами для аудиту вашого проєкту — оцінимо поточну ситуацію та запропонуємо оптимальне рішення.
Орієнтовні терміни
| Етап | Термін |
|---|---|
| Повна синхронізація за розкладом | 2 робочі дні |
| Дельта-синхронізація + realtime-перевірка | 3–4 робочі дні |
| Webhook-інтеграція (якщо підтримується) | +1 день |
Отримайте консультацію з вибору стратегії синхронізації та дізнайтеся, як автоматизація може скоротити повернення та підвищити лояльність клієнтів. Ми готові допомогти на кожному етапі — від аналізу до підтримки.







