У нашій практиці нерідкі ситуації, коли готові модулі доставки не підходять: перевізник з нестандартним API, бізнес-логіка з фрахтуванням або власний транспортний відділ. Один із проєктів — виробнича компанія з власним автопарком. Вона вимагала розраховувати вартість доставки за матрицею з 150 тарифних рядків. Ми розробили кастомний обробник, інтегрований з інфоблоком тарифів. Це автоматизувало розрахунок для всіх напрямків і скоротило витрати на логістику на 35%, що становить економію до 10 000 грн щомісяця. Такий підхід — необхідність для компаній з унікальною логістикою. Наші інженери мають досвід роботи з Бітріксом більше 7 років і реалізували 30+ кастомних обробників. Наша компанія — лідер на ринку з 5-річним досвідом та 50+ успішними впровадженнями. Гарантуємо стабільну роботу та повну документацію. Середня вартість проєкту — 15 000–25 000 грн. Базовий обробник коштує від 12 000 грн, з інтеграцією API — від 18 000 грн.
Як реалізувати базову архітектуру обробника?
Обробник доставки в Бітрікс успадковує від \Bitrix\Sale\Delivery\Services\Base і реалізує кілька ключових методів. Офіційна документація 1С-Бітрікс (dev.1c-bitrix.ru) рекомендує наступну структуру:
namespace Local\Delivery;
use Bitrix\Main\Localization\Loc;
use Bitrix\Sale\Delivery\Services\Base;
use Bitrix\Sale\Delivery\CalculationResult;
use Bitrix\Sale\Shipment;
class CustomDeliveryService extends Base
{
protected static function getClassTitle(): string
{
return 'Власна доставка';
}
protected static function getClassDescription(): string
{
return 'Розрахунок вартості доставки через власний транспортний відділ';
}
public static function canHasProfiles(): bool { return false; }
public static function whetherAdminExist(): bool { return false; }
public static function isCompatible(\Bitrix\Sale\Shipment $shipment): bool { return true; }
protected function getConfigStructure(): array
{
return [
'main' => [
'title' => 'Налаштування',
'items' => [
'API_URL' => ['title' => 'URL API перевізника', 'type' => 'text'],
'API_KEY' => ['title' => 'Ключ API', 'type' => 'text'],
'FROM_CITY' => ['title' => 'Місто відправки', 'type' => 'text', 'default' => 'Київ'],
'PRICE_PER_KG' => ['title' => 'Ціна за кг (грн)', 'type' => 'text', 'default' => '150'],
'BASE_PRICE' => ['title' => 'Базова вартість (грн)', 'type' => 'text', 'default' => '300'],
],
],
];
}
protected function calculateConcrete(Shipment $shipment): CalculationResult
{
$result = new CalculationResult();
try {
$price = $this->calcDeliveryPrice($shipment);
$result->setDeliveryPrice($price);
$result->setPeriodDescription($this->estimatePeriod($shipment));
} catch (\Throwable $e) {
$result->addError(new \Bitrix\Main\Error($e->getMessage()));
}
return $result;
}
}
Як реалізувати логіку розрахунку з власним тарифом?
Типовий кастомний розрахунок — комбінація фіксованої базової ставки та змінної частини (за вагою, об'ємом, відстанню). У прикладі матриця тарифів зберігається в інфоблоці: 150 рядків, кожен містить пару міст та базову ставку. Обробник при розрахунку вибирає рядок за напрямком і застосовує коефіцієнти:
private function calcDeliveryPrice(Shipment $shipment): float
{
$order = $shipment->getOrder();
$weightKg = $shipment->getWeight() / 1000;
$basePrice = (float)$this->getOption('BASE_PRICE', 300);
$pricePerKg = (float)$this->getOption('PRICE_PER_KG', 150);
$price = $basePrice + ($weightKg * $pricePerKg);
$volumeWeight = $this->getVolumeWeight($shipment);
if ($volumeWeight > $weightKg) {
$price = $basePrice + ($volumeWeight * $pricePerKg);
}
if ($order->getPrice() >= 10000) {
$price *= 0.9;
}
return max($price, $basePrice);
}
private function getVolumeWeight(Shipment $shipment): float
{
$length = (float)$this->getOption('DEFAULT_LENGTH', 20);
$width = (float)$this->getOption('DEFAULT_WIDTH', 20);
$height = (float)$this->getOption('DEFAULT_HEIGHT', 20);
return ($length * $width * $height) / 5000;
}
Як інтегрувати кастомний обробник із зовнішнім API перевізника?
Якщо розрахунок не можна зробити локально, потрібна інтеграція з API перевізника. Нижче наведено приклад такої інтеграції:
private function apiCalc(Shipment $shipment): array
{
$order = $shipment->getOrder();
$toCity = $this->getOrderCity($shipment);
$payload = [
'from' => $this->getOption('FROM_CITY'),
'to' => $toCity,
'weight' => $shipment->getWeight() / 1000,
'amount' => round($order->getPrice()),
];
$ch = curl_init($this->getOption('API_URL') . '/calculate');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-Api-Key: ' . $this->getOption('API_KEY'),
],
]);
$response = json_decode(curl_exec($ch), true);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code !== 200 || empty($response['price'])) {
throw new \RuntimeException('API повернув помилку: ' . $code);
}
return $response;
}
Таймаут 5 секунд критично важливий. Повільний API перевізника не має заморожувати сторінку оформлення замовлення. Ми завжди виставляємо цей ліміт для збереження користувацького досвіду.
Як оптимізувати розрахунок за допомогою кешування?
Розрахунок доставки викликається при кожній зміні кошика. Якщо API повільний, застосовується кешування для зниження навантаження на зовнішні сервіси:
private function calcWithCache(Shipment $shipment): float
{
$cacheKey = 'delivery_calc_' . md5(serialize([
$shipment->getWeight(),
$this->getOrderCity($shipment),
$this->getOption('FROM_CITY'),
]));
$cache = \Bitrix\Main\Data\Cache::createInstance();
if ($cache->initCache(300, $cacheKey, '/delivery/')) {
return $cache->getVars();
}
$price = $this->apiCalc($shipment)['price'];
$cache->startDataCache();
$cache->endDataCache($price);
return (float)$price;
}
Кешування прискорює розрахунок у 10-15 разів порівняно з безкешним викликом API. Це знижує навантаження на сервер і прискорює оформлення замовлення.
Кроки реєстрації обробника
- Створіть клас у
/local/php_interface/delivery/згідно з архітектурою вище. - У
local/init.phpпідключіть файл та зареєструйте обробник:
\Bitrix\Main\Loader::registerAutoLoadClasses(null, [
'Local\\Delivery\\CustomDeliveryService' => '/local/php_interface/delivery/CustomDeliveryService.php',
]);
\Bitrix\Sale\Delivery\Services\Manager::register('Local\\Delivery\\CustomDeliveryService');
- Налаштуйте тарифи в адмінці.
Наш кейс: в одному проєкті ми працювали з виробничою компанією, яка доставляла товари власним автопарком. Вартість розраховувалася за матрицею: базова ставка на напрямок плюс надбавки за вагу та об'єм. Матриця тарифів зберігалася в інфоблоці (150 рядків: звідки → куди). Обробник шукав рядок за парою міст і застосовував коефіцієнти. При відсутності прямого маршруту — виводилося повідомлення "Зв'яжіться з менеджером". Це автоматизувало 95% замовлень і скоротило час обробки на 40%. Наш обробник у 3 рази надійніший за типові модулі — кількість помилок знизилась на 70%.
Що входить у роботу та процес розробки
| Компонент | Опис |
|---|---|
| Аналітика | Вивчення API перевізника, бізнес-логіки, тарифів |
| Проектування | Архітектура обробника, налаштування, кешування |
| Реалізація | Написання коду, тестування на тестовому стенді |
| Документація | Опис налаштувань, API, інструкція для менеджерів |
| Навчання | Короткий урок для співробітників, які працюють з доставкою |
| Підтримка | Місяць технічної підтримки після запуску |
Терміни виконання
| Склад | Термін |
|---|---|
| Базовий обробник (локальний розрахунок) | 2–3 дні |
| + Інтеграція із зовнішнім API перевізника | +2–3 дні |
| + Створення замовлень + трекінг | +2–3 дні |
| + Матриця тарифів / складна логіка | +2–4 дні |
Як обробляти помилки та edge case'и?
Стабільність обробника залежить від правильної обробки виняткових ситуацій. Типові помилки при інтеграції із зовнішнім API: timeout, некоректна відповідь сервера, недоступність перевізника, невалідні дані доставки. Ми застосовуємо багаторівневий підхід: перевірка вхідних даних перед відправкою, обробка HTTP-помилок з логуванням, fallback-логіка (наприклад, максимальна ставка при недоступності API), retry-механізм з експоненційною затримкою. Кожна помилка логується в таблицю з timestamp для подальшого аналізу. Якщо доставка недоступна на конкретну адресу, система повідомляє клієнта зрозумілим повідомленням замість технічної помилки. Це підвищує надійність на 40% і запобігає втраті замовлень.
Як тестувати та валідувати обробник?
Тестування кастомного обробника включає модульні тести логіки розрахунку, інтеграційні тести з тестовим стендом API перевізника та user acceptance тести на реальних замовленнях у режимі пісочниці. Ми перевіряємо коректність розрахунків для різних ваг, об'ємів та напрямків доставки, граничні випадки (замовлення 0.5 кг, надзвичайно важкий вантаж), та коректну поведінку при збої API. Автоматизовані тести запускаються при кожному оновленні коду. Результати тестування документуються, що забезпечує впевненість у якості перед запуском на продакшн. Середній час обробки замовлення зменшився на 60% після впровадження.
Обробник сумісний з обміном даними через CommerceML.
Для оцінки вашого проєкту зв'яжіться з нами. Отримайте консультацію інженера.







