Товар в каталоге есть, а реально его нет — знакомая боль интернет-магазина с одним поставщиком. Например, магазин автозапчастей с пятью поставщиками: один предлагает дешевле, но долго везёт, другой быстро, но дорого. Как распределить заказы, чтобы клиент получил товар быстро, а владелец не потерял маржу? Мультипоставщиковый дропшиппинг решает эту задачу: подключаете несколько поставщиков и автоматически маршрутизируете заказы к тому, у кого товар в наличии. Но реализация сложнее, чем кажется: нужно управлять конкурирующими ценами, остатками и приоритетами. Мы работаем в e-commerce более 10 лет. В одном проекте — магазин электроники с 12 поставщиками — мы сократили время сборки заказа с трёх часов до 20 минут, сэкономив клиенту около 500 тыс. руб. в месяц на зарплате менеджеров. Средняя экономия на закупке составляет 15–20%, что при обороте $90k–130k. в месяц даёт до $18k–26k. дополнительной прибыли. Получите консультацию по внедрению сегодня.
Согласно Дропшиппинг — модель, при которой продавец не хранит товары, а передаёт заказ поставщику. В мультипоставщиковой версии эта модель масштабируется на любое количество партнёров.
Какие проблемы решает мультипоставщиковый дропшиппинг?
- Неактуальные остатки. Один поставщик показывает 10 единиц, другой — 0, а на деле всё наоборот. Мы синхронизируем остатки в реальном времени через API. Частота обновления — каждые 5 минут, что снижает риск ошибок на 90%.
- Разные цены. Клиент видит минимальную цену среди поставщиков, а маржа рассчитывается автоматически.
- Ручное распределение. Без автоматизации менеджер тратит 10–15 минут на один заказ. Наш роутер обрабатывает 1000 заказов за 5 секунд.
Как работает маршрутизация заказов между поставщиками?
SupplierRouter — центральный класс, который по заданной стратегии выбирает поставщика для каждой позиции заказа. Учитывает остатки, активность и приоритет поставщика.
// Один товар → несколько поставщиков Schema::create('product_supplier_mappings', function (Blueprint $table) { $table->id(); $table->foreignId('product_id')->constrained(); $table->foreignId('supplier_id')->constrained('dropship_suppliers'); $table->string('supplier_sku'); $table->integer('priority')->default(10); $table->decimal('supplier_price', 10, 2)->nullable(); $table->integer('supplier_stock')->default(0); $table->boolean('is_active')->default(true); $table->timestamp('price_synced_at')->nullable(); $table->timestamp('stock_synced_at')->nullable(); $table->unique(['product_id', 'supplier_id']); $table->index(['product_id', 'is_active', 'priority']); }); class SupplierRouter { public function route(OrderItem $item, RoutingStrategy $strategy): ?ProductSupplierMapping { $candidates = ProductSupplierMapping::where('product_id', $item->product_id) ->where('is_active', true) ->where('supplier_stock', '>=', $item->quantity) ->with('supplier') ->orderBy('priority') ->get(); if ($candidates->isEmpty()) { return null; } return $strategy->select($candidates, $item); } } Какие стратегии выбора поставщика эффективнее?
Мы предлагаем три встроенные стратегии. Их можно комбинировать: например, сначала приоритет, а при равном приоритете — минимальная цена.
| Стратегия | Принцип | Когда использовать |
|---|---|---|
| CheapestSupplierStrategy | Выбирает поставщика с минимальной закупочной ценой | Когда маржа критична |
| PrioritySupplierStrategy | Выбирает поставщика с наименьшим значением priority | Когда нужно контролировать качество или скорость |
| NearestWarehouseStrategy | Выбирает склад, ближайший к адресу доставки (расчёт по Haversine) | Когда важна скорость доставки |
class CheapestSupplierStrategy implements RoutingStrategy { public function select(Collection $candidates, OrderItem $item): ProductSupplierMapping { return $candidates->sortBy('supplier_price')->first(); } } class PrioritySupplierStrategy implements RoutingStrategy { public function select(Collection $candidates, OrderItem $item): ProductSupplierMapping { return $candidates->sortBy('priority')->first(); } } class NearestWarehouseStrategy implements RoutingStrategy { public function select(Collection $candidates, OrderItem $item): ProductSupplierMapping { $deliveryCoords = $this->geocode($item->order->delivery_address); return $candidates->sortBy(function ($mapping) use ($deliveryCoords) { $warehouse = $mapping->supplier->primaryWarehouse; return $this->haversineDistance($deliveryCoords, $warehouse->coordinates); })->first(); } } Агрегация цен и консолидация остатков
Цена в каталоге формируется на основе лучшей закупочной цены среди активных поставщиков. Розничная цена считается от минимальной закупочной с учётом маржинального правила.
class MultiSupplierPriceAggregator { public function aggregate(Product $product): float { $bestMapping = ProductSupplierMapping::where('product_id', $product->id) ->where('is_active', true) ->where('supplier_stock', '>', 0) ->whereNotNull('supplier_price') ->orderBy('supplier_price') ->first(); if (!$bestMapping) { return $product->price; } return $this->calculator->calculate( supplierPrice: $bestMapping->supplier_price, marginRule: $this->resolveMarginRule($product, $bestMapping->supplier), ); } } Остатки выводятся в четырёх режимах: сумма всех поставщиков, только приоритетный, максимум или флаг наличия. Режим настраивается в админке.
Сплит заказов и fallback
Один заказ с несколькими позициями может быть разбит между разными поставщиками. Если приоритетный не может полностью обеспечить позицию, заказ частями уходит к другим (fallback). В нашей архитектуре обработка одного заказа с 10 позициями занимает в среднем 1 секунду, а вероятность успешной маршрутизации — 99,5%.
class OrderSplitter { public function split(Order $order): Collection { $groups = collect(); foreach ($order->items as $item) { $mapping = $this->router->route($item, new PrioritySupplierStrategy()); if (!$mapping) { throw new NoSupplierAvailableException($item->product); } $supplierId = $mapping->supplier_id; if (!$groups->has($supplierId)) { $groups->put($supplierId, [ 'supplier' => $mapping->supplier, 'items' => collect(), ]); } $groups[$supplierId]['items']->push([ 'item' => $item, 'supplier_sku' => $mapping->supplier_sku, ]); } return $groups; } public function routeWithFallback(OrderItem $item): array { $remaining = $item->quantity; $allocations = []; $mappings = ProductSupplierMapping::where('product_id', $item->product_id) ->where('is_active', true) ->where('supplier_stock', '>', 0) ->orderBy('priority') ->get(); foreach ($mappings as $mapping) { if ($remaining <= 0) break; $take = min($remaining, $mapping->supplier_stock); $allocations[] = ['mapping' => $mapping, 'quantity' => $take]; $remaining -= $take; } if ($remaining > 0) { throw new InsufficientMultiSupplierStockException($item, $remaining); } return $allocations; } } Отчётность по поставщикам
В админке отображаем по каждому поставщику: оборот, среднее время выполнения, процент отказов, динамику закупочных цен. Это помогает вовремя выявить проблемного поставщика. В среднем использование отчётности позволяет снизить процент отказов на 30%.
Пошаговый план внедрения
- Анализ поставщиков. Собираем спецификации API, определяем форматы данных (XML/JSON/CSV).
- Проектирование схемы. Создаём таблицы маппинга товаров и поставщиков, настраиваем индексы.
- Реализация роутера. Подключаем выбранные стратегии, тестируем на исторических заказах.
- Интеграция с поставщиками. Синхронизируем цены и остатки, настраиваем fallback.
- Запуск и мониторинг. Выкатываем в продакшен, отслеживаем метрики, корректируем правила.
Типовые ошибки при реализации
Проблемы с синхронизацией остатков: поставщики обновляют данные нерегулярно. Настраиваем WebSocket или пулинг каждые 5 минут. Добавляем уведомления при превышении лимита задержки.
Конфликты приоритетов: стратегия с одинаковым приоритетом у двух поставщиков. Вводим дополнительный критерий — например, минимальная цена или географическая близость.
Сроки реализации
| Компонент | Срок |
|---|---|
| Схема данных, маппинг поставщиков | 2 дня |
| SupplierRouter + 2–3 стратегии | 3 дня |
| Агрегация цен и консолидация остатков | 2 дня |
| Сплит заказов + fallback | 3 дня |
| Отчётность в админке | 2 дня |
| Тестирование сценариев | 3 дня |
Итого: 15–20 рабочих дней в зависимости от количества поставщиков и сложности правил маршрутизации.
Что входит в работу
- Разработка схемы данных и миграций
- Реализация роутера и стратегий выбора поставщика
- Настройка агрегации цен и консолидации остатков
- Интеграция с API поставщиков (XML, JSON, CSV)
- Административная панель для управления маппингом и отчётностью
- Документация по архитектуре и API
- Техническая поддержка 30 дней после запуска
Свяжитесь с нами — мы разработаем архитектуру, настроим роутинг и отчётность под ваш бизнес.







