Реализация дропшиппинга на сайте
Дропшиппинг с технической точки зрения — это слой абстракции между покупателем и поставщиком. Магазин хранит только данные о товарах и заказах, физических запасов нет. Реализация требует трёх взаимосвязанных подсистем: импорта и синхронизации каталога, передачи заказов поставщику и отслеживания статусов доставки. Ни одну из них нельзя сделать «на потом» — без синхронизации остатков магазин принимает заказы на товары, которых нет у поставщика.
Архитектура системы
┌─────────────────────────────────────────────────────────┐
│ Интернет-магазин │
│ │
│ Каталог товаров Корзина/Оформление Личный кабинет │
│ │ │ │ │
│ └──────────────────┼───────────────────┘ │
│ │ │
│ ┌────────────▼─────────────┐ │
│ │ Dropshipping Kernel │ │
│ │ - Supplier Router │ │
│ │ - Stock Aggregator │ │
│ │ - Price Calculator │ │
│ │ - Order Dispatcher │ │
│ └────────────┬─────────────┘ │
└───────────────────────────┼─────────────────────────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ Поставщик 1 │ │ Поставщик 2 │ │ Поставщик N │
│ REST API │ │ FTP + CSV │ │ SOAP/XML │
└─────────────┘ └─────────────┘ └─────────────┘
Модели данных
// Поставщик
Schema::create('dropship_suppliers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('slug')->unique();
$table->enum('integration_type', ['api', 'csv', 'xml', 'soap']);
$table->jsonb('credentials')->nullable(); // зашифровано через $casts + Crypt
$table->string('api_endpoint')->nullable();
$table->integer('processing_days')->default(1); // срок сборки заказа
$table->decimal('default_margin', 5, 2)->default(30.00); // % маржи
$table->boolean('is_active')->default(true);
$table->timestamps();
});
// Товар поставщика (исходные данные)
Schema::create('dropship_products', function (Blueprint $table) {
$table->id();
$table->foreignId('supplier_id')->constrained('dropship_suppliers');
$table->string('supplier_sku'); // артикул поставщика
$table->string('name');
$table->text('description')->nullable();
$table->decimal('supplier_price', 10, 2);
$table->integer('supplier_stock')->default(0);
$table->jsonb('attributes')->nullable();
$table->string('image_url')->nullable();
$table->foreignId('product_id')->nullable()->constrained('products'); // привязка к товару магазина
$table->timestamp('synced_at')->nullable();
$table->timestamps();
$table->unique(['supplier_id', 'supplier_sku']);
});
Ядро дропшиппинга
class DropshippingKernel
{
public function __construct(
private SupplierRepositoryInterface $suppliers,
private PriceCalculator $priceCalculator,
private OrderDispatcher $orderDispatcher,
) {}
/**
* Получить итоговую цену товара с учётом маржи поставщика
*/
public function calculateRetailPrice(DropshipProduct $dp): float
{
$supplier = $dp->supplier;
$margin = $dp->margin_override ?? $supplier->default_margin;
return $this->priceCalculator->calculate(
supplierPrice: $dp->supplier_price,
marginPercent: $margin,
);
}
/**
* Проверить доступность товара у поставщика в реальном времени
*/
public function checkAvailability(DropshipProduct $dp): StockResult
{
$connector = SupplierConnectorFactory::make($dp->supplier);
return $connector->checkStock($dp->supplier_sku);
}
/**
* Передать заказ поставщику после подтверждения оплаты
*/
public function dispatchOrder(Order $order): void
{
// Группируем позиции по поставщикам
$bySupplier = $order->items->groupBy(
fn($item) => $item->product->dropshipProduct?->supplier_id
);
foreach ($bySupplier as $supplierId => $items) {
if (!$supplierId) continue; // собственные товары — пропускаем
$this->orderDispatcher->dispatch(
supplier: Supplier::find($supplierId),
order: $order,
items: $items,
);
}
}
}
Коннекторы поставщиков
Каждый поставщик требует своего коннектора. Базовый интерфейс:
interface SupplierConnectorInterface
{
public function getProducts(int $page = 1, int $perPage = 100): array;
public function checkStock(string $sku): StockResult;
public function placeOrder(SupplierOrderDTO $dto): SupplierOrderResult;
public function getOrderStatus(string $supplierOrderId): OrderStatusResult;
}
Реализация для поставщика с REST API:
class RestApiSupplierConnector implements SupplierConnectorInterface
{
public function __construct(
private readonly Supplier $supplier,
private readonly \GuzzleHttp\Client $http,
) {}
public function placeOrder(SupplierOrderDTO $dto): SupplierOrderResult
{
$response = $this->http->post($this->supplier->api_endpoint . '/orders', [
'headers' => ['Authorization' => 'Bearer ' . $this->getToken()],
'json' => [
'external_id' => $dto->orderId,
'items' => $dto->items->map(fn($i) => [
'sku' => $i->supplierSku,
'quantity' => $i->quantity,
])->toArray(),
'delivery' => [
'name' => $dto->recipientName,
'address' => $dto->deliveryAddress,
'phone' => $dto->phone,
],
],
]);
$data = json_decode($response->getBody(), true);
return new SupplierOrderResult(
supplierOrderId: $data['order_id'],
status: $data['status'],
);
}
}
Обработка смешанных заказов
Когда в одном заказе есть и собственные товары, и дропшиппинг-позиции, обработка разделяется:
- Собственные товары списываются со склада немедленно
- Дропшиппинг-товары передаются поставщику после подтверждения оплаты
- Покупатель получает сводный трекинг с несколькими отправлениями
Для покупателя это прозрачно — он видит единый заказ. На уровне базы данных каждая позиция хранит ссылку на supplier_order_id.
Статусная машина заказа
placed → payment_confirmed → dispatched_to_supplier
→ supplier_confirmed → shipped → delivered
→ supplier_rejected → refunded
Переходы между статусами обрабатываются через Laravel Events + Listeners. Каждый переход отправляет уведомление покупателю (email, SMS).
Сроки реализации
| Этап | Срок |
|---|---|
| Проектирование схемы БД и архитектуры | 2 дня |
| Базовые модели, ядро, интерфейсы | 3 дня |
| Первый коннектор поставщика (REST API) | 2 дня |
| Синхронизация каталога (cron + queue) | 2 дня |
| Dispatch заказов и обработка статусов | 3 дня |
| UI в админке: управление поставщиками | 2 дня |
| Тестирование и отладка | 2 дня |
Итого: 16–20 рабочих дней для полнофункциональной системы с одним поставщиком. Каждый дополнительный поставщик — 3–5 рабочих дней.







