Разработка кастомного обработчика службы доставки 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Разработка кастомного обработчика службы доставки 1С-Битрикс
Средняя
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    747
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Разработка кастомного обработчика службы доставки 1С-Битрикс

Когда готовых модулей для нужного перевозчика не существует, API службы доставки принципиально отличается от стандартных паттернов, или бизнес-логика расчёта настолько специфична, что ни один существующий обработчик не подходит — разрабатывается кастомный обработчик. Это не экзотика: собственный транспортный отдел, калькулятор с фрахтованием, региональный перевозчик без готового модуля.

Базовая архитектура обработчика

Обработчик доставки в Битрикс наследует от \Bitrix\Sale\Delivery\Services\Base и реализует несколько ключевых методов:

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

Логика расчёта: собственный тариф

Типичный кастомный расчёт — комбинация фиксированной базовой ставки и переменной части (по весу, объёму, расстоянию):

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

    // Скидка при заказе от 10 000 руб.
    if ($order->getPrice() >= 10000) {
        $price *= 0.9;
    }

    // Минимальная стоимость доставки
    return max($price, $basePrice);
}

private function getVolumeWeight(Shipment $shipment): float
{
    // Объёмный вес по формуле Д×Ш×В / 5000
    // Размеры берём из настроек или из свойств товаров
    $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/')) { // 5 минут
        return $cache->getVars();
    }

    $price = $this->apiCalc($shipment)['price'];

    $cache->startDataCache();
    $cache->endDataCache($price);

    return (float)$price;
}

Регистрация обработчика

// 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 строк: город отправки × город получения). Обработчик при расчёте ищет строку матрицы по парам городов, применяет тарифные коэффициенты. При отсутствии прямого маршрута — отображает сообщение «Свяжитесь с менеджером для расчёта доставки».

Сроки

Состав Срок
Базовый обработчик (локальный расчёт) 2–3 дня
+ Интеграция с внешним API перевозчика +2–3 дня
+ Создание заказов + трекинг +2–3 дня
+ Матрица тарифов / сложная логика +2–4 дня