Інтеграція 1С-Бітрікс зі службою доставки ПЕК
ПЕК (Перша Експедиційна Компанія) — одна з ключових транспортних компаній для вантажної та збірної доставки в Росії. Основна специфіка інтеграції: ПЕК працює з вантажами від 1 кг і більше, API заточений під параметри вантажних місць (довжина, ширина, висота, вага кожного місця окремо), а не під стандартний роздрібний формат 1С-Бітрікс. Якщо у вас інтернет-магазин з великогабаритом — дивани, будівельні матеріали, промислове обладнання — ПЕК часто стає основним перевізником.
API ПЕК: особливості
ПЕК надає REST API з авторизацією через Bearer-токен. Токен отримується через POST /v2/sign-in з логіном і паролем з особистого кабінету. Токен не має жорстко обмеженого TTL (на практиці живе 24–48 годин), але рекомендується кешувати і оновлювати при отриманні 401.
Ключові ендпоінти:
-
POST /v2/calculator— розрахунок вартості та термінів -
POST /v2/orders— створення замовлення -
GET /v2/orders/{id}— статус замовлення -
GET /v2/departments— список терміналів ПЕК
Базовий URL: https://api.pek.ru. Документація доступна в особистому кабінеті партнера.
Розрахунок вартості
class PekDeliveryHandler extends \Bitrix\Sale\Delivery\Services\Base
{
protected function calculateConcrete(
\Bitrix\Sale\Shipment $shipment
): \Bitrix\Sale\Delivery\CalculationResult {
$result = new \Bitrix\Sale\Delivery\CalculationResult();
$token = $this->getApiToken();
$payload = $this->buildCalcPayload($shipment);
$response = $this->apiPost('/v2/calculator', $payload, $token);
if (empty($response['price'])) {
$result->addError(new \Bitrix\Main\Error('Розрахунок недоступний'));
return $result;
}
$result->setDeliveryPrice((float)$response['price']);
$result->setPeriodDescription($response['period_min'] . '–' . $response['period_max'] . ' днів');
return $result;
}
private function buildCalcPayload(\Bitrix\Sale\Shipment $shipment): array
{
$order = $shipment->getOrder();
return [
'senderCityId' => (int)$this->getOption('SENDER_CITY_ID'),
'receiverCityId' => $this->getReceiverCityId($shipment),
'cargo' => $this->buildCargoPlaces($shipment),
'service' => $this->getOption('SERVICE_TYPE', 'door_door'),
'declaredValue' => round($order->getPrice(), 2),
];
}
private function buildCargoPlaces(\Bitrix\Sale\Shipment $shipment): array
{
// ПЕК вимагає параметри кожного вантажного місця окремо
$weight = max($shipment->getWeight() / 1000, 1); // г → кг, мінімум 1 кг
return [
[
'weight' => $weight,
'length' => (int)$this->getOption('DEFAULT_LENGTH', 50),
'width' => (int)$this->getOption('DEFAULT_WIDTH', 50),
'height' => (int)$this->getOption('DEFAULT_HEIGHT', 50),
],
];
}
}
Важливо: ПЕК розраховує за об'ємною вагою. Якщо фактична вага менша за об'ємну (Д×Ш×В / 5000 для авіа, / 4000 для авто), рахується об'ємна. Для великогабариту це критично — передавайте реальні габарити товарів.
Отримання cityId
ПЕК використовує власні числові ідентифікатори міст. Пошук міста:
public function findCityId(string $cityName): ?int
{
$response = $this->apiGet('/v2/city?name=' . urlencode($cityName), $this->getApiToken());
return $response[0]['id'] ?? null;
}
Альтернатива: вивантажити довідник міст ПЕК і зберігати маппінг назва_міста → pek_city_id в інфоблоці або кастомній таблиці. При старті рекомендується саме цей підхід — API пошуку міста повертає неоднозначні результати для населених пунктів з однаковою назвою.
Створення замовлення та термінали
private function createPekOrder(\Bitrix\Sale\Shipment $shipment): string
{
$order = $shipment->getOrder();
$props = $order->getPropertyCollection();
$payload = [
'senderCityId' => (int)$this->getOption('SENDER_CITY_ID'),
'receiverCityId' => $this->getReceiverCityId($shipment),
'cargo' => $this->buildCargoPlaces($shipment),
'service' => $this->getOption('SERVICE_TYPE', 'door_door'),
'declaredValue' => round($order->getPrice(), 2),
'sender' => [
'company' => $this->getOption('SENDER_COMPANY'),
'contact' => $this->getOption('SENDER_CONTACT'),
'phone' => $this->getOption('SENDER_PHONE'),
'address' => $this->getOption('SENDER_ADDRESS'),
],
'receiver' => [
'contact' => $props->getItemByOrderPropertyCode('FIO')?->getValue(),
'phone' => $props->getItemByOrderPropertyCode('PHONE')?->getValue(),
'address' => $props->getItemByOrderPropertyCode('ADDRESS')?->getValue(),
],
];
$response = $this->apiPost('/v2/orders', $payload, $this->getApiToken());
return (string)($response['id'] ?? '');
}
При типі door_terminal або terminal_door потрібно передавати ідентифікатор терміналу ПЕК. Список терміналів: GET /v2/departments. Фільтрація за cityId. На сайті реалізується випадаючий список терміналів з картою — віджет або кастомна реалізація на Leaflet/Yandex Maps.
Кейс: магазин будматеріалів
Клієнт — оптово-роздрібний магазин будматеріалів, середня вага замовлення 50–200 кг, багато листового матеріалу. Проблема при впровадженні: 1С-Бітрікс зберігає вагу відправлення як одне число, а ПЕК при замовленні з кількома позиціями різних розмірів вимагає список вантажних місць з габаритами кожного. Довелося реалізувати логіку розбивки: у кожного товару в інфоблоці заведені властивості DELIVERY_LENGTH, DELIVERY_WIDTH, DELIVERY_HEIGHT. При формуванні відправки кожна одиниця товару перетворюється на окреме вантажне місце.
Це збільшило точність розрахунку (розбіжність з реальною вартістю скоротилася з ±30% до ±5%) і усунуло донарахування при отриманні вантажу.
Трекінг статусів
| Статус ПЕК | Значення |
|---|---|
accepted |
Прийнято до перевезення |
in_transit |
В дорозі |
arrived |
Прибув на термінал призначення |
out_for_delivery |
Передано кур'єру |
delivered |
Доставлено |
returned |
Повернення |
Вебхуків у ПЕК немає — тільки polling. Агент 1С-Бітрікс раз на 4 години запитує статуси активних відправлень через GET /v2/orders/{id} і оновлює статус замовлення в магазині.
Терміни
| Склад | Термін |
|---|---|
| Розрахунок вартості + створення замовлення | 4–5 днів |
| + Список терміналів + карта | +2–3 дні |
| + Розбивка на вантажні місця за товарами | +2 дні |
| + Polling статусів + сповіщення | +2 дні |







