Інтеграція служби доставки СДЕК на сайт

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

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

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Інтеграція служби доставки СДЕК на сайт
Середня
~2-3 робочих дні
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • 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

Інтеграція служби доставки СДЭК на сайт

СДЭК — один з найбільших логістичних операторів Росії з покриттям більше 5400 міст, власною мережею ПВЗ і постаматів. API v2 дозволяє підключити розрахунок вартості, вибір ПВЗ на карті, створення замовлень на доставку й відстеження посилок прямо з вашого сайту.

Авторизація в API

СДЭК використовує OAuth 2.0 з client credentials grant. Токен живе 3600 секунд, потім потрібен новий:

class CdekAuthService
{
    private const TOKEN_URL = 'https://api.cdek.ru/v2/oauth/token';
    private const CACHE_KEY = 'cdek_access_token';

    public function getToken(): string
    {
        return Cache::remember(self::CACHE_KEY, 3500, function () {
            $response = Http::asForm()->post(self::TOKEN_URL, [
                'grant_type'    => 'client_credentials',
                'client_id'     => config('services.cdek.client_id'),
                'client_secret' => config('services.cdek.client_secret'),
            ]);

            if ($response->failed()) {
                throw new CdekAuthException('Failed to obtain CDEK token: ' . $response->body());
            }

            return $response->json('access_token');
        });
    }
}

Для тестування використовуються окремі credentials:

  • client_id: EMscd6r9JnFiQ3bLoyjJY6eM
  • client_secret: PjLZkKBHEiLK3YsjtNrt7ZpUzj
  • базовий URL: https://api.edu.cdek.ru/v2

Розрахунок вартості доставки

class CdekCalculatorService
{
    public function calculateTariffList(
        string $fromCityCode,
        string $toCityCode,
        array  $packages,
        int    $deliveryType = 1 // 1=дверь-дверь, 2=дверь-ПВЗ, 3=ПВЗ-дверь, 4=ПВЗ-ПВЗ
    ): array {
        $response = Http::withToken($this->auth->getToken())
            ->post('https://api.cdek.ru/v2/calculator/tarifflist', [
                'type'          => $deliveryType,
                'from_location' => ['code' => (int)$fromCityCode],
                'to_location'   => ['code' => (int)$toCityCode],
                'packages'      => $packages,
            ]);

        if ($response->failed()) {
            throw new CdekApiException($response->body());
        }

        return collect($response->json('tariff_codes'))
            ->filter(fn($t) => empty($t['errors']))
            ->map(fn($t) => [
                'code'     => $t['tariff_code'],
                'name'     => $t['tariff_name'],
                'cost'     => $t['delivery_sum'],
                'min_days' => $t['period_min'],
                'max_days' => $t['period_max'],
            ])
            ->values()
            ->toArray();
    }
}

Основні тарифи: 136 — посилка склад-склад, 137 — посилка склад-дверь, 138 — посилка дверь-склад, 139 — посилка дверь-дверь.

Отримання коду міста СДЭК

СДЭК використовує власні коди міст, не збігаючись з ФИАС або КЛАДР. Пошук по назві:

public function findCityCode(string $cityName, string $countryCode = 'RU'): ?int
{
    $response = Http::withToken($this->auth->getToken())
        ->get('https://api.cdek.ru/v2/location/cities', [
            'country_codes' => [$countryCode],
            'city'          => $cityName,
            'size'          => 5,
        ]);

    $cities = $response->json('0');
    return $cities['code'] ?? null;
}

Рекомендується кешувати справочник міст локально — він змінюється рідко.

Список пунктів видачі

public function getPickupPoints(string $cityCode, float $weightKg): array
{
    $response = Http::withToken($this->auth->getToken())
        ->get('https://api.cdek.ru/v2/deliverypoints', [
            'city_code'  => $cityCode,
            'weight_max' => (int)($weightKg),
            'type'       => 'PVZ',
            'is_handout' => 'true',
        ]);

    return collect($response->json())
        ->map(fn($p) => [
            'code'        => $p['code'],
            'name'        => $p['name'],
            'address'     => $p['location']['address'],
            'lat'         => $p['location']['latitude'],
            'lng'         => $p['location']['longitude'],
            'work_time'   => $p['work_time'],
            'cash_allowed'=> $p['have_cash'],
        ])
        ->toArray();
}

Створення замовлення

Після підтвердження покупки — реєструємо замовлення в СДЭК:

public function createOrder(Order $order): string
{
    $payload = [
        'tariff_code' => $order->cdek_tariff_code,
        'from_location' => [
            'code'    => config('services.cdek.warehouse_city_code'),
            'address' => config('services.cdek.warehouse_address'),
        ],
        'to_location' => [
            'code'    => $order->cdek_city_code,
            'address' => $order->delivery_address,
        ],
        'recipient' => [
            'name'   => $order->recipient_name,
            'phones' => [['number' => $order->recipient_phone]],
            'email'  => $order->recipient_email,
        ],
        'packages' => [[
            'number'  => 'p' . $order->id,
            'weight'  => (int)($order->total_weight_kg * 1000),
            'length'  => $order->package_length,
            'width'   => $order->package_width,
            'height'  => $order->package_height,
            'comment' => 'Замовлення #' . $order->id,
            'items'   => $order->items->map(fn($item) => [
                'name'    => $item->product->name,
                'ware_key'=> (string)$item->product_id,
                'cost'    => $item->price,
                'amount'  => $item->quantity,
                'weight'  => (int)($item->product->weight_g),
            ])->toArray(),
        ]],
    ];

    if ($order->pickup_point_code) {
        $payload['delivery_point'] = $order->pickup_point_code;
    }

    $response = Http::withToken($this->auth->getToken())
        ->post('https://api.cdek.ru/v2/orders', $payload);

    $orderId = $response->json('entity.uuid');

    if (!$orderId) {
        throw new CdekOrderException('Не вдалося створити замовлення СДЭК');
    }

    return $orderId;
}

Відстеження статусів через webhook

СДЭК уміє відправляти уведомлення про зміну статусу замовлення:

Http::withToken($token)->post('https://api.cdek.ru/v2/webhooks', [
    'url'  => 'https://yoursite.ru/api/cdek/webhook',
    'type' => 'ORDER_STATUS',
]);

public function handleWebhook(Request $request): Response
{
    $data = $request->json()->all();

    if ($data['type'] !== 'ORDER_STATUS') {
        return response('ok', 200);
    }

    $order = Order::where('cdek_uuid', $data['attributes']['uuid'])->first();

    if ($order) {
        $order->update([
            'cdek_status' => $data['attributes']['status']['code'],
            'cdek_status_at' => now(),
        ]);

        if (in_array($data['attributes']['status']['code'], ['READY_FOR_PICKUP', 'DELIVERED'])) {
            dispatch(new NotifyCustomerDeliveryStatus($order));
        }
    }

    return response('ok', 200);
}

Ключові статуси: CREATED, ACCEPTED_AT_SENDER_WAREHOUSE, READY_FOR_PICKUP, DELIVERED, NOT_DELIVERED.

Друк накладних

public function getPrintForm(string $cdekUuid): string
{
    $response = Http::withToken($this->auth->getToken())
        ->post('https://api.cdek.ru/v2/print/orders', [
            'orders' => [['order_uuid' => $cdekUuid]],
            'copy'   => 1,
        ]);

    $taskUuid = $response->json('entity.uuid');

    for ($i = 0; $i < 10; $i++) {
        sleep(2);
        $status = Http::withToken($this->auth->getToken())
            ->get("https://api.cdek.ru/v2/print/orders/{$taskUuid}")
            ->json();

        if ($status['entity']['status'] === 'READY') {
            return $status['entity']['url'];
        }
    }

    throw new \RuntimeException('Print form generation timeout');
}

Терміни й обсяг робіт

Базова інтеграція (розрахунок стоимости + ПВЗ на карті + створення замовлень) — 5–7 робочих днів. Додавання відстеження через webhook, печаті накладних, синхронізації статусів — ще 3–4 дні. Тестування в тестовій середовищі СДЭК перед переключенням на боєву — обов'язковий етап, займає 1–2 дні.