Товар в каталоге есть, а реально его нет — знакомая боль интернет-магазина с одним поставщиком. Например, магазин автозапчастей с пятью поставщиками: один предлагает дешевле, но долго везёт, другой быстро, но дорого. Как распределить заказы, чтобы клиент получил товар быстро, а владелец не потерял маржу? Мультипоставщиковый дропшиппинг решает эту задачу: подключаете несколько поставщиков и автоматически маршрутизируете заказы к тому, у кого товар в наличии. Но реализация сложнее, чем кажется: нужно управлять конкурирующими ценами, остатками и приоритетами. Мы работаем в e-commerce более 10 лет. В одном проекте — магазин электроники с 12 поставщиками — мы сократили время сборки заказа с трёх часов до 20 минут, сэкономив клиенту около 500 тыс. руб. в месяц на зарплате менеджеров. Средняя экономия на закупке составляет 15–20%, что при обороте 10 млн руб. в месяц даёт до 2 млн руб. дополнительной прибыли. Получите консультацию по внедрению сегодня.
Согласно Дропшиппинг — модель, при которой продавец не хранит товары, а передаёт заказ поставщику. В мультипоставщиковой версии эта модель масштабируется на любое количество партнёров.
Какие проблемы решает мультипоставщиковый дропшиппинг?
- Неактуальные остатки. Один поставщик показывает 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 дней после запуска
Свяжитесь с нами — мы разработаем архитектуру, настроим роутинг и отчётность под ваш бизнес.







