Інтеграція дропшипінг-постачальників з інтернет-магазином

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Інтеграція дропшипінг-постачальників з інтернет-магазином
Складна
~5 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Інтеграція дропшиппінг-постачальників з інтернет-магазином

Інтеграція постачальника — технічна задача, складність якої визначається не кількістю товарів, а форматом та якістю даних на стороні постачальника. REST API з документацією — найкращий сценарій. Прайс в Excel без артикулів та з кирилицею в заголовках — найгірший. Зустрічаються обидва.

Типи інтеграцій

REST API — постачальник надає endpoint'и для отримання каталогу, остатків, цін та прийому замовлень. Найзручніший формат. Вимагає ключа API або OAuth-авторизації.

SOAP/XML-RPC — застарілий, але все ще поширений формат у великих дистрибюторів та виробників. Вимагає парсингу WSDL та генерації клієнтського коду.

FTP/SFTP + CSV/XML — постачальник виклаадає файл на сервер за розписанням. Магазин забирає його та обробляє. Нема можливості перевірити остаток у реальному часі.

Email з прайс-листом — крайній випадок. Застосовується парсер вкладень + OCR для PDF.

EDI (EDIFACT/X12) — використовується великими FMCG та фармацевтичними дистрибюторами.

Фабрика коннекторів

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); // видаляємо BOM та пробіли

        // Маппінг заголовків (постачальники називають поля по-різному)
        $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

class SoapConnector implements SupplierConnectorInterface
{
    private \SoapClient $client;

    public function __construct(private Supplier $supplier)
    {
        $this->client = new \SoapClient(
            $supplier->credentials['wsdl_url'],
            ['login' => $supplier->credentials['login'],
             'password' => $supplier->credentials['password'],
             'cache_wsdl' => WSDL_CACHE_DISK,
             'trace' => false,
            ]
        );
    }

    public function getProducts(int $page = 1, int $perPage = 100): array
    {
        $result = $this->client->GetProductList([
            'SessionID' => $this->getSession(),
            'PageNum'   => $page,
            'PageSize'  => $perPage,
        ]);

        return collect($result->ProductList->Product ?? [])
            ->map(fn($item) => new SupplierProductDTO(
                sku:   $item->Article,
                name:  $item->Name,
                price: (float) $item->Price,
                stock: (int) $item->Qty,
            ))
            ->toArray();
    }
}

Нормалізація даних постачальника

Дані від різних постачальників неминуче розходяться за структурою. Нормалізація виконується перед збереженням у 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;

        // Нормалізуємо остаток: "в наявності" → 999, "немає" → 0
        $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 з exponential backoff:

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));
    }
}

Терміни інтеграції

Тип інтеграції Термін
REST API з документацією 2–3 дні
SOAP з WSDL 3–4 дні
FTP + CSV (стандартний формат) 2–3 дні
FTP + CSV (нестандартний формат) 3–5 днів
Кілька постачальників (кожний наступний) 1–3 дні