Периодическое допланирование маршрута

Допланирование — это добавление заказов в спланированный ранее маршрут. Задача допланирования возникает в следующих случаях:

  • часть заказов уже распределена по маршрутам, но появились новые заказы;
  • курьер выезжает в рейс с частью заказов, чтобы уменьшить время простоя, а новые заказы добавляются в маршрут позднее.

Если допланирование применяется часто, его желательно автоматизировать.

Примечание

Данный сценарий реализуется только через запросы API.

В новую задачу планирования передается:

  • общий список заказов (старые и новые заказы);
  • маршрут, полученный на предыдущей итерации планирования, и настройки, определяющие возможность изменения этого маршрута;
  • текущее местоположение курьера (при необходимости).

Задача допланирования может возникнуть в разные моменты времени и при различных условиях:

  • Вариант 1: курьер находится на складе, порядок уже распределенных заказов фиксирован, новые заказы добавляются в конец маршрута:

  • Вариант 2: курьер находится на складе, порядок уже распределенных заказов не фиксирован, новые заказы добавляются в любом порядке:

  • Вариант 3: курьер в пути, порядок уже распределенных заказов фиксирован, новые заказы добавляются в конец маршрута:

  • Вариант 4: курьер в пути, часть заказов уже выполнена, порядок оставшихся заказов не фиксирован, новые заказы добавляются в оставшуюся часть маршрута в любом порядке:

 — новый заказ.

 — заказ в фиксированном порядке.

 — заказ без фиксированного порядка.

Во всех вариантах возможен заезд на дополнительный склад в середине маршрута.

Как реализовать сценарий

При начальном планировании маршрутов нужно продумать:

  • наличие в автомобиле свободного места для новых заказов (указать меньшую вместимость);
  • наличие свободного времени (указать уменьшенное время смены курьера);

При допланировании все дополнительные ограничения, введенные на первой итерации с целью искусственно загрузить автомобили не полностью, необходимо снять.

В запросе для допланирования в объекте locations нужно передать общий список заказов — тех, которые уже были запланированы ранее и которые нужно допланировать.

Также в запрос нужно включить объект initial_routes с данными о первоначально спланированных рейсах. Эти данные можно скопировать из объекта result.routes в ответе API для первой задачи планирования. Для каждого рейса нужно передать объекты:

  • route — массив остановок в рейсе;
  • run_number — номер рейса;
  • shift — смена курьера;
  • vehicle_id — идентификатор курьера.

Фиксация порядка заказов

Если ранее спланированный рейс нужно сохранить без изменений, в объекте initial_routes укажите для него признак immutable = true. Если нельзя менять порядок остановок в рейсе, укажите признак fixed_order = true.

Если нужно сохранить без изменений не весь рейс, а часть (последовательность остановок, идущих подряд), укажите для каждой из этих остановок признак node.value.fixed_position = true.

Чтобы заказ был доставлен тем курьером, который был запланирован первоначально, укажите для заказа fixed_vehicle = true, чтобы заказ был оставлен в той же смене — fixed_shift = true, в том же рейсе — fixed_run = true. Если ни один из перечисленных выше признаков не указан, новые заказы могут быть перемешаны со старыми в произвольном порядке.

Если используется передача местоположения курьеров (точка с типом courier), то признак immutable не работает. Вместо него нужно фиксировать положение каждой точки в initial_routes с помощью параметра node.value.fixed_position = true, а признак immutable нужно убрать.

Готовность заказов

При планировании алгоритм учитывает только параметры, которые вы передаете в запросе API. Время запуска запроса не учитывается. Поэтому при неправильно заданных параметрах алгоритм может спланировать маршрут, который начинается в прошлом. Например, вы указали временное окно склада (ресторана) с 9:00 до 21:00. Если вы отправляете запрос на планирование в 9:30, алгоритм может построить маршрут с выездом курьера в 9:20. Чтобы этого не происходило, используйте один из способов:

  • Каждый раз, когда отправляете запрос на планирование, указывайте время начала работы склада равным времени планирования: например, если запрос будет отправлен в 9:30, укажите время работы склада с 9:30 до 21:00.

  • Для каждого заказа указывайте время готовности depot_ready_time. Это время должно быть в будущем (не в прошлом).

Учет доставленных заказов

Если на момент допланирования часть заказов уже были доставлены, укажите время их посещения в полях:

  • actual_arrival_time_s — время прибытия на заказ;
  • actual_service_start_time_s — время начала обслуживания заказа;
  • actual_departure_time_s — время отъезда с заказа.

Если эти параметры указаны для какого-то заказа, то их необходимо указывать и для всех предшествующих заказов. Если для заказа указаны указаны actual_arrival_time_s и actual_departure_time_s, то необходимо указать также node.value.fixed_position = true.

Также можно использовать поля arrival_time_s и departure_time_s. Эти поля нужно либо указывать для всех точек в рейсе, либо не указывать ни у одной. Время прибытия и отъезда должны быть уникальными для всех заказов. Поэтому мультизаказы при допланировании лучше не использовать. Если смена курьера начинается позже, чем время посещения его первого заказа, при допланировании возникнет ошибка.

Пример
{
    "initial_routes": [
        {
            "route": [
                {
                    "arrival_time_s": 24562,
                    "departure_time_s": 24562,
                    "node": {
                        "value": {
                            "fixed_position": true;
                            ...
                        }
                        ...
                    }
                },
                {
                    "arrival_time_s": 24680,
                    "departure_time_s": 24860,
                    "node": {
                        "value": {
                            "fixed_position": true;
                            ...
                        }
                        ...
                    }
                }
                ...
            ],
            "run_number": 1,
            "shift": {
                "id": "shift_id"
            },
            "vehicle_id": "vehicle1"
        },
        {
            "route": [
                {
                    "actual_arrival_time_s": 31572,
                    "actual_departure_time_s": 31572,
                    "actual_service_start_time_s": 31572,
                    "arrival_time_s": 31572,
                    "departure_time_s": 31572,
                    "node": {
                        "value": {
                            "fixed_position": true;
                            ...
                        }
                        ...
                    }
                },
                {
                    "actual_arrival_time_s": 31740,
                    "actual_departure_time_s": 31920,
                    "actual_service_start_time_s": 31740,
                    "arrival_time_s": 31740,
                    "departure_time_s": 31920,
                    "node": {
                        "value": {
                            "fixed_position": true;
                            ...
                        }
                        ...
                    }
                },
                ...
            ],
            "run_number": 2,
            "shift": {
                "id": "shift_id"
            },
            "vehicle_id": "vehicle1"
        },
        ...
    ]
}

Загруженные заказы

Идентификаторы заказов, которые были загружены в автомобиль до выезда со склада, нужно перечислить в поле loaded_orders для точки node с типом depot. Если нового заказа нет в списке loaded_orders, курьеру будет запланирован дополнительный заезд на склад для загрузки этого заказа. Если loaded_orders не задано, считается, что на складе были загружены все заказы.

Заказ может быть загружен в автомобиль при первом планировании, но при допланировании он может попасть в нераспределенные. При этом заказ будет занимать место в автомобиле. Чтобы алгоритм мог учитывать это, укажите для заказа признак keep_in_vehicle = true.

Примечание

Если число заказов с учетом допланирования превышает возможности доставки имеющимися курьерами в заданные временные окна, часть заказов могут остаться нераспределенными. Если заказ обязательно должен быть доставлен, укажите для него undroppable = true.

Распределение заказов на свободных курьеров

Если вы хотите распределять новые заказы только на тех курьеров, которые уже закончили свои предыдущие маршруты, при планировании указывайте, что по окончании маршрута курьер должен вернуться на склад. Укажите координаты склада с помощьью метода nodes для узлов depot (склад).

Чтобы запретить добавлять заказы каким-то избранным курьерам, воспользуйтесь функциональностью тегов. Подробнее об этом см. в разделе Теги автомобиля.

Равномерная загрузка курьеров

При планировании алгоритм может распределять нагрузку между курьерами равномерно: по количеству доставленных заказов, по времени маршрута, по длине маршрута. Для этого используйте опцию балансировки.

При использовании этой опции во все запросы допланирования в течение дня нужно передавать все предыдущие заказы и маршруты (initial_routes).

Текущее местоположение курьера

Если курьер в пути, при допланировании важно учитывать его текущее местоположение. Текущее положение курьера задается в блоке initial_routes в отдельной точке node с типом type = courier. Координаты курьера в этой точке можно указать одним из способов:

  • в поле value.location_id указать идентификатор последнего посещенного курьером заказа. Координаты этого заказа считаются текущими координатами курьера;

    Пример указания положения курьера на последнем выполненном заказе
    "initial_routes": [
        {
            "route": [
                ...
                {
                    "arrival_time_s": 35000,
                    "departure_time_s": 35000,
                    "node": {
                        "type": "courier",
                        "value": {
                            "location_id": "Order 5"
                        }
                    }
                },   
                ...
            ]
        }
    ],
    ...
    "locations": [
        ...
    ]    
    
  • в поле value.location_id указать идентификатор точки и добавить эту точку с координатами курьера в блок locations.

    Пример указания положения курьера в точке с координатами
    "initial_routes": [
        {
            "route": [
                ...
                {
                    "arrival_time_s": 35000,
                    "departure_time_s": 35000,
                    "node": {
                        "type": "courier",
                        "value": {
                            "location_id": "Courier Position"
                        }
                    }
                },   
                ...
            ]
        }
    ],   
    ...
    "locations": [
        ...
        {
            "id": "Courier Position",
            "point": {
                "lat": "61.67259",
                "lon": "50.82052"
            },
            "time_window": "18:00 - 20:00"
        }      
    ] 
    

Значение поля value.location_id должно быть текстовым, поэтому все идентификаторы заказов и складов в маршруте также должны быть текстовыми.

Если вы хотите указать время нахождения курьера в этой точке, его можно передать в полях actual_arrival_time_s и actual_departure_time_s. В таком случае эти поля должны быть указаны и для всех предшествующих точек в маршруте, см. Учет доставленных заказов. Значение actual_arrival_time_s для точки положения курьера должно быть больше или равно actual_departure_time_s для предшествующего заказа.

В полях arrival_time_s и departure_time_s для точки положения курьера нужно указать текущее время отправки запроса на допланирование.

Примеры

Пример 1. Первое планирование

В первом планировании курьер забирает со склада и доставляет 10 заказов: Order 3 → Order 5 → Order 9 → Order 1 → Order 2 → Order 8 → Order 10 → Order 6 → Order 4 → Order 7.

Запрос API (JSON)Ответ APIОткрыть на карте

Пример 2.1. Допланирование без точки положения курьера

Первое планирование как в примере 1. В допланировании добавлены еще 4 заказа. К моменту допланирования курьер уже доставил первые два заказа. Чтобы обозначить это, в объекте initial_routes для склада и первых двух заказов указано fixed_position = true.

Порядок доставки остальных заказов в новом решении изменился: Order 3 → Order 5 → Order 9 → Order 12 → Order 11 → Order 13 → Order 1 → Order 2 → Order 8 → Order 10 → Order 14 → Order 6 → Order 4 → Order 7.

Запрос API (JSON)Ответ APIОткрыть на карте

Пример 2.2. Допланирование с указанием положения курьера на последнем выполненном заказе

Первое планирование как в примере 1. В допланировании добавлены еще 4 заказа. К моменту допланирования курьер уже доставил первые два заказа. Чтобы обозначить это, в объекте initial_routes для склада и первых двух заказов указано fixed_position = true и добавлена точка с позицией курьера type = courier, в которой указан последний выполненный заказ Order 5.

Порядок доставки остальных заказов в новом решении изменился: Order 3 → Order 5 → Order 11 → Order 12 → Order 9 → Order 13 → Order 1 → Order 2 → Order 8 → Order 10 → Order 14 → Order 6 → Order 4 → Order 7.

Запрос API (JSON)Ответ APIОткрыть на карте

Пример 2.3. Допланирование с указанием положения курьера в отдельной точке с координатами

Первое планирование как в примере 1. В допланировании добавлены еще 4 заказа. К моменту допланирования курьер уже доставил первые два заказа. Чтобы обозначить это, в объекте initial_routes для склада и первых двух заказов указано fixed_position = true. Текущее положение курьера задано точкой Courier Position.

Порядок доставки остальных заказов в новом решении изменился: Order 3 → Order 5 → Order 11 → Order 12 → Order 9 → Order 7 → Order 4 → Order 6 → Order 14 → Order 8 → Order 2 → Order 1 → Order 13 → Order 10.

Запрос API (JSON)Ответ APIОткрыть на карте

Написать в службу поддержки