Setting up courier delivery route optimization in 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Configuring Courier Delivery Route Optimization in 1C-Bitrix

Route optimization — the traveling salesman problem: there are N delivery addresses and a courier, the goal is to visit all with minimal mileage. Bitrix doesn't solve this problem itself, but serves as a data source for orders. Optimized routes are built by external services (Yandex.Routing, Google OR-Tools, Routific) and passed back as courier tasks.

Preparing delivery data

To build a route, you need a list of addresses with coordinates and time windows. Addresses are taken from order properties:

$deliveries = \Bitrix\Sale\OrderTable::getList([
    'filter' => [
        'STATUS_ID' => 'TD',  // status "to be delivered today"
        '>=DATE_STATUS' => new \Bitrix\Main\Type\Date(),
    ],
    'select' => ['ID'],
])->fetchAll();

$points = [];
foreach ($deliveries as $row) {
    $order = \Bitrix\Sale\Order::load($row['ID']);
    $props = $order->getPropertyCollection();

    $points[] = [
        'order_id'       => $row['ID'],
        'address'        => $props->getItemByOrderPropertyCode('ADDRESS')?->getValue(),
        'lat'            => $props->getItemByOrderPropertyCode('LAT')?->getValue(),
        'lon'            => $props->getItemByOrderPropertyCode('LON')?->getValue(),
        'time_from'      => $props->getItemByOrderPropertyCode('DELIVERY_TIME_FROM')?->getValue(),
        'time_to'        => $props->getItemByOrderPropertyCode('DELIVERY_TIME_TO')?->getValue(),
        'weight'         => $this->getOrderWeight($order),
    ];
}

Coordinates (LAT/LON) must be obtained during checkout — through geocoding via Yandex or Google API based on entered address. Save them in custom order properties.

Geocoding addresses during checkout

When filling in an address in the order form — AJAX request to geocoder:

fetch(`https://geocode-maps.yandex.ru/1.x/?apikey=KEY&format=json&geocode=${encodeURIComponent(address)}`)
    .then(r => r.json())
    .then(data => {
        const pos = data.response.GeoObjectCollection.featureMember[0]?.GeoObject?.Point?.pos;
        if (pos) {
            const [lon, lat] = pos.split(' ');
            document.getElementById('lat-field').value = lat;
            document.getElementById('lon-field').value = lon;
        }
    });

Coordinates are saved to hidden form fields and included in order properties.

Integration with route optimization service

After collecting points, send them to the optimizer API. Example with Yandex.Routing (details — separate service):

$httpClient = new \Bitrix\Main\Web\HttpClient();
$response = $httpClient->post(
    'https://courier.yandex.ru/api/v1/companies/{company_id}/routes',
    json_encode(['vehicles' => $vehicles, 'orders' => $points]),
    ['Authorization' => 'Bearer ' . YANDEX_COURIER_API_KEY]
);

$routes = json_decode($response, true);

Returned routes contain an ordered list of points for each courier. Save them in bl_courier_routes and assign to couriers through CRM tasks or mobile application.

Displaying route to courier

Create a mobile page or send the courier a link to the route in Google Maps or Yandex.Maps with waypoints. Format for Google Maps:

https://www.google.com/maps/dir/DEPOT_LAT,DEPOT_LON/STOP1_LAT,STOP1_LON/STOP2_LAT,STOP2_LON/...

Generate this link from bl_courier_routes data and send to courier via SMS or email.

What we configure

  • Custom order properties LAT, LON, DELIVERY_TIME_FROM, DELIVERY_TIME_TO
  • Address geocoding during checkout via JavaScript + Yandex/Google API
  • Agent for collecting delivery points and sending requests to route optimizer
  • bl_courier_routes table for storing optimized routes
  • Route link generation and distribution to couriers