Ми часто стикаємося з ситуацією: магазин зростає, а ручне завантаження товарів від постачальників стає вузьким місцем. Менеджери витрачають години на копіювання з Excel, помиляються в цінах, а клієнти йдуть через неактуальні залишки. В одному проєкті ручна обробка 500 товарів займала 3 години щодня; після інтеграції — 2 хвилини автоматично. Помилки при введенні знизилися з 8% до 0,1% — тобто в 80 разів. Інтеграція постачальника — технічне завдання, складність якого визначається не кількістю товарів, а форматом та якістю даних з боку постачальника. REST API з документацією — найкращий сценарій. Прайс в Excel без артикулів і з кирилицею в заголовках — найгірший. Зустрічаються обидва. Середня економія на ручній праці після інтеграції — десятки тисяч гривень на місяць для магазину з 1000 товарів.
Як вибрати тип інтеграції для вашого постачальника
Вибір протоколу залежить від можливостей постачальника та вимог до актуальності даних. Якщо потрібні реальні залишки — тільки REST API. Якщо дані змінюються раз на добу — підійде FTP з CSV. Ми допомагаємо визначити оптимальний варіант на етапі аудиту. Основні типи:
- REST API: постачальник надає endpoint'и для отримання каталогу, залишків, цін і прийому замовлень. Потребує ключа API або OAuth-авторизації. Найзручніший формат.
- SOAP/XML-RPC: застарілий, але все ще поширений у великих дистриб'юторів. Потребує парсингу WSDL і генерації клієнтського коду.
- FTP/SFTP + CSV/XML: постачальник викладає файл на сервер за розкладом. Магазин забирає та обробляє. Немає можливості перевірити залишок у реальному часі.
- Email з прайс-листом: крайній випадок. Застосовується парсер вкладень + OCR для PDF.
- EDI (EDIFACT/X12): використовується великими FMCG та фармацевтичними дистриб'юторами. Детальніше про стандарт можна прочитати в Wikipedia.
Порівняння: REST API оновлює залишки миттєво, FTP — із затримкою до 24 годин. Для динамічних товарів REST у 100 разів швидше за часом оновлення.
Реалізація коннекторів: фабрика та приклади
Фабрика коннекторів
class SupplierConnectorFactory
{
public static function make(Supplier $supplier): SupplierConnectorInterface
{
return match($supplier->integration_type) {
'rest_api' => new RestApiConnector($supplier, app(HttpClient::class)),
'soap' => new SoapConnector($supplier),
'ftp_csv' => new FtpCsvConnector($supplier, app(SftpFilesystem::class)),
'ftp_xml' => new FtpXmlConnector($supplier, app(SftpFilesystem::class)),
default => throw new UnsupportedIntegrationTypeException($supplier->integration_type),
};
}
}
Приклад коннектора для FTP + CSV
Частина постачальників вивантажує прайс на FTP раз на добу. Коннектор забирає файл, парсить і нормалізує дані. У коді нижче показано завантаження, мапінг заголовків та очищення рядків:
class FtpCsvConnector implements SupplierConnectorInterface
{
public function getProducts(int $page = 1, int $perPage = 100): array
{
$localPath = $this->downloadFile();
$products = [];
$handle = fopen($localPath, 'r');
$headers = fgetcsv($handle, 0, ';');
$headers = array_map('trim', $headers);
$mapping = $this->resolveHeaderMapping($headers);
while (($row = fgetcsv($handle, 0, ';')) !== false) {
$normalized = $this->normalizeRow(
array_combine($headers, $row),
$mapping
);
if ($normalized) {
$products[] = $normalized;
}
}
fclose($handle);
@unlink($localPath);
return array_slice($products, ($page - 1) * $perPage, $perPage);
}
private function resolveHeaderMapping(array $headers): array
{
$aliases = [
'sku' => ['артикул', 'sku', 'код', 'article', 'item_no'],
'name' => ['наименование', 'название', 'name', 'title', 'товар'],
'price' => ['цена', 'price', 'стоимость', 'цена_розница'],
'stock' => ['остаток', 'количество', 'stock', 'qty', 'available'],
];
$mapping = [];
foreach ($headers as $header) {
$lower = mb_strtolower(trim($header));
foreach ($aliases as $field => $list) {
if (in_array($lower, $list)) {
$mapping[$field] = $header;
break;
}
}
}
return $mapping;
}
private function downloadFile(): string
{
$remotePath = $this->supplier->credentials['ftp_path'];
$localPath = sys_get_temp_dir() . '/' . uniqid('supplier_') . '.csv';
$this->sftp->download($remotePath, $localPath);
return $localPath;
}
}
Для SOAP-інтеграції використовується SoapClient з авторизацією та кешуванням WSDL. Подробиці можна знайти в офіційній документації PHP.
Чому гнучкий мапінг полів критичний?
Постачальники називають одні й ті самі поля по-різному: артикул, SKU, код, article. Без мапінгу кожен новий постачальник потребує переписування коду. Фабрика коннекторів з таблицею аліасів вирішує цю проблему за 10 рядків конфігурації. Це знижує час підключення нового постачальника з 5 днів до 2–3.
Обробка даних і помилок
Нормалізація даних постачальника
Дані від різних постачальників неминуче розходяться за структурою. Нормалізація виконується перед збереженням у dropship_products:
class SupplierProductNormalizer
{
public function normalize(array $raw, Supplier $supplier): ?SupplierProductDTO
{
$sku = preg_replace('/[^\w\-]/', '', $raw['sku'] ?? '');
if (!$sku) return null;
$price = (float) str_replace([' ', ','], ['', '.'], $raw['price'] ?? '0');
if ($price <= 0) return null;
$stock = $this->parseStock($raw['stock'] ?? '0');
return new SupplierProductDTO(
sku: $sku,
name: mb_convert_encoding(trim($raw['name'] ?? ''), 'UTF-8', 'auto'),
price: $price,
stock: $stock,
);
}
private function parseStock(mixed $value): int
{
if (is_numeric($value)) return (int) $value;
$lower = mb_strtolower((string) $value);
return match(true) {
str_contains($lower, 'наличи') => 999,
str_contains($lower, 'нет') => 0,
str_contains($lower, 'ожида') => 0,
default => 0,
};
}
}
Обробка помилок з'єднання з експоненційною затримкою
Постачальники бувають ненадійними: API лягає на техобслуговування, FTP змінює структуру директорій, CSV приходить з іншим кодуванням. Всі коннектори обгортаються в Retry-політику через Laravel Queue з експоненційною затримкою:
class SyncSupplierJob implements ShouldQueue
{
public $tries = 3;
public $backoff = [60, 300, 900]; // 1 хв, 5 хв, 15 хв
public function failed(Throwable $e): void
{
Notification::route('mail', config('suppliers.admin_email'))
->notify(new SupplierSyncFailedNotification($this->supplier, $e));
}
}
Як ми гарантуємо відмовостійкість?
Експоненційна затримка збільшує інтервал між спробами (60, 300, 900 секунд), знижуючи навантаження на постачальника і підвищуючи ймовірність успіху після збою. Якщо всі спроби вичерпано, адміністратор отримує сповіщення з деталями помилки. Це дозволяє реагувати до того, як проблема вплине на продажі.
Процес роботи: покроково
- Аудит постачальників: визначаємо формати даних, протоколи, частоту оновлень.
- Проектування архітектури: вибираємо тип коннектора, налаштовуємо мапінг полів.
- Розробка коннектора: пишемо код під кожен тип (REST, SOAP, FTP, EDI).
- Тестування на реальних даних постачальника: перевіряємо коректність імпорту та обробку помилок.
- Деплой та налаштування розкладу: підключаємо Cron/Queue для регулярної синхронізації.
- Моніторинг та документація: передаємо інструкції з експлуатації.
Порівняння типів інтеграції
| Тип | Швидкість | Актуальність | Складність розробки |
|---|---|---|---|
| REST API | Висока | Реальний час | Низька |
| SOAP | Середня | Реальний час | Середня |
| FTP + CSV | Низька | Раз на добу | Середня |
| Email + парсер | Низька | Раз на добу | Висока |
Орієнтовні терміни
| Тип інтеграції | Термін |
|---|---|
| REST API з документацією | 2–3 дні |
| SOAP з WSDL | 3–4 дні |
| FTP + CSV (стандартний формат) | 2–3 дні |
| FTP + CSV (нестандартний формат) | 3–5 днів |
| Декілька постачальників (кожен наступний) | 1–3 дні |
Як інтеграція дропшиппінгу окупається?
Автоматизація виключає людські помилки: невірні ціни, застарілі залишки, дублі товарів. В результаті конверсія зростає на 15–30%, а час на обробку замовлень скорочується вдвічі. Наш досвід — понад 10 впроваджень дропшиппінг-інтеграцій для магазинів у нішах від електроніки до одягу. Окупність настає в середньому за 3–6 місяців за рахунок зниження трудозатрат. Кожна помилка в замовленні коштує сотні гривень — автоматизація виключає 99% таких помилок.
Зв'яжіться з нами для аудиту ваших постачальників. Замовте консультацію — ми підготуємо рішення під ваш бізнес.







