---
metadata:
  - name: generator
    content: Diplodoc Platform v5.19.6
alternate:
  - https://docs.routeq.com/doc/en/vrp/grouping-locations.md
---
> **Documentation Index:** Fetch the complete configuration index at https://docs.routeq.com/doc/en/llms.txt


# Grouping locations and multi-orders

To reduce the time to complete the route, you can combine some orders. You can combine them manually by [grouping locations](#location-groups). If orders are located at the same address (for example, a shopping mall or an apartment building), they can be automatically combined into one [multi-order](#multi-orders). If there are several [closely located orders](#close-locations) on a route, you can set requirements for them to be visited by the same courier or within the same route.

## Order grouping  {#location-groups}

When you build routes, you may need to implement different scenarios:

* Deliver multiple orders by one courier:

  For example, a company needs to have all orders completed by one vehicle, or a courier needs to take an order to a point, get the delivery documents there, and then bring them to the office.

* Transport passengers:

  * Pick up a passenger from one point and transport them to another.
  * Pick up several passengers from one point and transport them to several other points.  
  * Pick up several passengers from several points and transport them to one point.

RouteQ allows grouping such orders. Grouping parameters are set on the **Location_groups** sheet (`options.location_groups` in the API).  

You can specify a name for each group in the `title` field. This doesn't affect routing, but enables you to assign descriptive names to groups. Orders are added to the group by their IDs, `location_ids`. The sequence of orders in the group can be strictly fixed or arbitrary. 

The `ordered` field on the **Location_groups** sheet can take the following values:

* `true`: When planning, the algorithm lines up orders in the sequence defined in `location_ids`. 
* `false` or no value: The order sequence is ignored. By default, the `ordered` value isn't specified.

You can also specify the following properties for order groups: 

* `solid`: The `true` value indicates that the group can't be broken up: orders in it must be delivered without other orders in between. Order sequence within the group isn't fixed. For example, this can be helpful for cargo taxis that deliver cargo from one point to another and can't load new orders until unloading some. Default value: `false`.
* `dependent`: The `true` value specifies indicates the group can't be split: all orders in it must either be completed or (if at least one order can't be delivered) set to unassigned together. Default value: `false`.

**Example 1**

In this example, two vehicles deliver orders across eight locations. Since orders aren't grouped, RouteQ builds the optimal route.

[API request (JSON)](https://courier.yandex.ru/vrs/api/v1/log/request/6059362-e64ef397-be7dd3f-7e93214) ⋅ [API response](https://courier.yandex.ru/vrs/api/v1/result/6059362-e64ef397-be7dd3f-7e93214) ⋅  [View on map](https://yandex.com/courier/mvrp-map#6059362-e64ef397-be7dd3f-7e93214)

**Example 2**

The same as example 1, but orders 7 and 8 are combined into one group. RouteQ assigns these orders to one vehicle. The resulting route is less optimal in terms of metrics, but meets the delivery requirements.

[API request (JSON)](https://courier.yandex.ru/vrs/api/v1/log/request/94446818-ced7911d-8b4de1f4-ff871a1f) ⋅ [API response](https://courier.yandex.ru/vrs/api/v1/result/94446818-ced7911d-8b4de1f4-ff871a1f) ⋅  [View on map](https://yandex.com/courier/mvrp-map#94446818-ced7911d-8b4de1f4-ff871a1f)

**Example 3**

8 orders are divided into 3 groups, each of which includes orders from a single client. It is specified that the groups can't be broken up: on the **Location_groups** sheet, `solid` = `true`. The route doesn't mix the orders of different clients: first, client 1's orders are delivered, then client 2's, and finally, client 3's.

[API request (JSON)](https://courier.yandex.ru/vrs/api/v1/log/request/c02cf0f8-102ab5c1-8365103a-e894ccf0) ⋅ [API response](https://courier.yandex.ru/vrs/api/v1/result/c02cf0f8-102ab5c1-8365103a-e894ccf0) ⋅  [View on map](https://yandex.com/courier/mvrp-map#c02cf0f8-102ab5c1-8365103a-e894ccf0)

**Example 4**

8 orders are divided into 2 groups. On the **Location_groups** sheet, `dependent` = `true`. This means that if at least one order from the group can't be fulfilled, the entire group is set to unassigned.

The total weight of the first group of orders is 250 kg, and the total weight of the second group is 450 kg. Due to the limited load capacity (600 kg), the courier can't deliver two indivisible groups of orders in one route, so the algorithm resets one of the groups.

[API request (JSON)](https://courier.yandex.ru/vrs/api/v1/log/request/eb2f4842-b3209148-6af750af-c6a4ea3a) ⋅ [API response](https://courier.yandex.ru/vrs/api/v1/result/eb2f4842-b3209148-6af750af-c6a4ea3a) ⋅  [View on map](https://yandex.com/courier/mvrp-map#eb2f4842-b3209148-6af750af-c6a4ea3a)

**Example 5**

Eight orders are combined into one group. The **Location_groups** sheet contains values for the following fields:

* `location_ids` indicates a reverse delivery sequence (from the last order to the first one).
* `ordered` = `false`.

As a result, orders are randomly assigned during planning. The `location_ids` sequence is ignored.

[API request (JSON)](https://courier.yandex.ru/vrs/api/v1/log/request/5f58c04-9d0a24d8-a2ba0047-53259cb1) ⋅ [API response](https://courier.yandex.ru/vrs/api/v1/result/5f58c04-9d0a24d8-a2ba0047-53259cb1) ⋅  [View on map](https://yandex.com/courier/mvrp-map#5f58c04-9d0a24d8-a2ba0047-53259cb1)

**Example 6**

The same conditions as in example 5, but the `ordered` field on the **Location_groups** sheet is set to `true`.

As a result, orders are assigned in a strictly defined `location_ids` sequence during planning, from last to first.

[API request (JSON)](https://courier.yandex.ru/vrs/api/v1/log/request/ee10d1f9-abdc727d-dbb2706f-e34cc419) ⋅ [API response](https://courier.yandex.ru/vrs/api/v1/result/ee10d1f9-abdc727d-dbb2706f-e34cc419) ⋅  [View on map](https://yandex.com/courier/mvrp-map#ee10d1f9-abdc727d-dbb2706f-e34cc419)

## Multi-orders  {#multi-orders}

Orders located at the same address can be automatically combined into one multi-order. The combining algorithm takes into account geographical proximity and the possibility to deliver the orders at the same time and with one vehicle or courier, as well as tags, carrying capacity, and delivery priority.

To ensure that orders located at the same address are combined into one multi-order (taking into account other restrictions), set the option `merge_multiorders` = `true`. In this case, orders can be combined into one multi-order even if there is a waiting time between them (by default, the option `wait_in_multiorders` is `true`).

To make it so the multi-order can't be divided, set `options.force_merge_multiorders` = `true`. In this case, all orders to the same address will be delivered by the same vehicle, and if that's not possible, the entire multi-order will be moved to unassigned. Default value: `false`.

By default, orders that are delivered to different clients (with different `client_id`'s) at the same address are counted as a single stop. To make them count as separate stops, set `options.merge_multiorders_of_different_clients` = `false`. The number of stops can be used to calculate the [route cost](https://docs.routeq.com/doc/en/vrp/properties-of-vehicles-cost.md#custom-route-cost). The option doesn't affect the [handling time](https://docs.routeq.com/doc/en/vrp/properties-of-orders.md#multi-orders) calculation: the `location.shared_service_duration_s` time for document handover or parking is calculated based on the longest time among all of the orders within the multi-order.

The proximity of the orders is determined by the `multiorder_radius_m` option (1 m by default). The value should not be too high so that orders located in neighboring buildings do not get combined into a multi-order. In such cases, it is better to use the [Delivery with vehicle parking before the walking part of the route](https://docs.routeq.com/doc/en/vrp/supported-use-cases.md#vehicle-walking-courier) scenario for planning.

By default, time for parking or delivering documents `shared_service_duration_s` is tracked once for the entire multi-order. However, if there is a waiting time between orders (orders have different time windows and the courier completes the handover of one order before starting the next one), the handling time `shared_service_duration_s` can be tracked separately for each order. To do this, disable the waiting option `options.wait_in_multiorders` = `false`. To take into account the time `shared_service_duration_s` separately for a specific order, disable the option `location.can_be_merged` = `false` for that order. Learn more about order time tracking in [Handover time](https://docs.routeq.com/doc/en/vrp/properties-of-orders.md#order-service-duration-delivery).

During planning, the algorithm will try to reduce the number of return visits to multi-order addresses. The API response includes the following metrics:

- `multiorders_extra_points`: The number of multi-order addresses which couriers visited more than once.
- `multiorders_extra_visits`: The number of return visits to multi-order addresses.
- `multiorders_extra_vehicles`: The number of couriers who revisited multi-order addresses.

You can apply the following penalties for return visits:

- `options.penalty.multiorders.per_extra_point`: For each multi-order address which had to be visited again.
- `options.penalty.multiorders.per_extra_visit`: For each return visit to a multi-order address.
- `options.penalty.multiorders.per_extra_vehicle`: For each courier who returns to a multi-order address.

**Example 1**

The vehicle delivers three orders. Orders 1 and 2 are delivered to the same address and combined in a multi-order.

[API request (JSON)](https://courier.yandex.ru/vrs/api/v1/log/request/c493eed8-42754094-af37202e-e88a8faa) ⋅ [API response](https://courier.yandex.ru/vrs/api/v1/result/c493eed8-42754094-af37202e-e88a8faa) ⋅  [View on map](https://yandex.com/courier/mvrp-map#c493eed8-42754094-af37202e-e88a8faa)

**Example 2.1**

The vehicle delivers three orders. Orders 1 and 2 are delivered to the same address and combined in a multi-order. By default, `wait_in_multiorders` = `true`, and the handling time is tracked once. There is a waiting time due to the difference in time windows between these orders, and orders 1 and 2 aren't visually combined into one multi-order, but order 2 has the parameter `multi_order` = `true` in the API response.

[API request (JSON)](https://courier.yandex.ru/vrs/api/v1/log/request/ba6f0221-b0515e43-9857de34-cc4ec301) ⋅ [API response](https://courier.yandex.ru/vrs/api/v1/result/ba6f0221-b0515e43-9857de34-cc4ec301) ⋅  [View on map](https://yandex.com/courier/mvrp-map#ba6f0221-b0515e43-9857de34-cc4ec301)

**Example 2.2**

The same orders are delivered as in example 2.1, but the option `wait_in_multiorders` = `false`. Orders 1 and 2 weren't combined into one multi-order (`multi_order` = `false` for order 2), and the service time is tracked separately for each order.

[API request (JSON)](https://courier.yandex.ru/vrs/api/v1/log/request/f2361e42-494d6c7b-a09a3c80-aec59232) ⋅ [API response](https://courier.yandex.ru/vrs/api/v1/result/f2361e42-494d6c7b-a09a3c80-aec59232) ⋅  [View on map](https://yandex.com/courier/mvrp-map#f2361e42-494d6c7b-a09a3c80-aec59232)

**Example 3**

Orders 1, 2, and 3 have to to be delivered to the same address. Order 4 has to be delivered to a different address. Each order weighs 500 kg. The carrying capacity of the car is only 1200 kg, so the car makes two runs. It first delivers orders 1 and 2, and then delivers orders 3 and 4.

The algorithm combined orders 1 and 2 into a multi-order, despite the fact that `merge_multiorders` = `false` (by default). Since it took 2 runs to deliver order 3, the penalty is the following: 10 units for the address that had to be revisited, and 1000 units for the return visit to the multi-order address.

[API request (JSON)](https://courier.yandex.ru/vrs/api/v1/log/request/d82187ae-2a9f1540-bb229bd-d2dc4384) ⋅ [API response](https://courier.yandex.ru/vrs/api/v1/result/d82187ae-2a9f1540-bb229bd-d2dc4384) ⋅  [View on map](https://yandex.com/courier/mvrp-map#d82187ae-2a9f1540-bb229bd-d2dc4384)


## Nearby orders {#close-locations}

If you want to limit the number of couriers or routes that go to closely located orders, combine such orders into groups. To do this, go to the **Options** sheet and set the following parameters:

- `close_location_groups_radius_m`: Maximum distance at which orders are considered close to each other, in meters. The default is 0.
- `penalty.close_location_groups.per_extra_point`: Penalty for each point the courier visits more than once.
- `penalty.close_location_groups.per_extra_vehicle`: Penalty for each additional courier who visits a group of closely located orders.
- `penalty.close_location_groups.per_extra_visit`: Penalty for each additional visit to a group of closely located orders.

If the parameter `close_location_groups_radius_m` > 0, we recommend grouping closely located orders only at the [sequence post-optimization](https://docs.routeq.com/doc/en/vrp/post-optimization.md) stage. To do this, set `options.post_optimization` = `true` and `options.close_locations_during_post_optimization_only` = `true` (the default is `false`).

To set restrictions for a courier on visiting closely located orders, go to the **Vehicles** sheet and set the following parameters:

- `close_locations.routing_mode`: Transportation method for determining the proximity of orders (the same for all orders in the solution).
- `close_locations.search_radius_m`: Distance between two orders for the selected transportation method (the orders are considered closely located and are subject to the restrictions).
- `close_locations.soft_search_radius_m`: If the value of this parameter exceeds the value of the corresponding `close_locations.search_radius_m`, orders at a distance from `search_radius_m` to `soft_search_radius_m` are also subject to penalties, but their size decreases linearly depending on the distance. For example, at the distance (`search_radius_m` + `soft_search_radius_m`) / 2, a penalty with a weight of 0.5 applies.
- `close_locations.duration_till_service_s.value` and `close_locations.duration_till_service_s.penalty`: The maximum time (in seconds) between handling two closely located orders and the penalty for violating the restriction.
- `close_locations.distance_till_service_m.value` and `close_locations.distance_till_service_m.penalty`: The maximum distance (in meters) between handling two closely located orders and the penalty for violating the restriction.


{% cut "Example of using the settings of nearby orders" %}

```json
 {
 ...
     "vehicles": [{
         ...
         "close_locations": [
             {
                 "routing_mode": "driving",
                 "search_radius_m": 400,
                 "soft_search_radius_m": 500,
                 "distance_till_service_m": {
                     "penalty": 0.02,
                     "value": 1500
                 }
             },
             {
                 "routing_mode": "driving",
                 "search_radius_m": 100,
                 "soft_search_radius_m": 160,
                 "duration_till_service_s": {
                     "penalty": 0.02,
                     "value": 1500
                 }
             }
         ],
         ...
     },
     ...
     ],
 ...
 }
```
{% endcut %}

{% note alert %}

If the `walking_courier` parameter is not specified for the courier on the **Vehicle** sheet, then you can't set the transportation method in `close_locations.routing_mode`. Instead, the courier's [transportation method](https://docs.routeq.com/doc/en/vrp/properties-of-vehicles.md#routing-mode) is used by default. If the `walking_courier` parameter is set, then you can specify the value of `close_locations.routing_mode` as `walking` or as the courier's transportation method.

{% endnote %}

{% include [warehouse-feedback](_includes/feedback-81845556eeea.md) %}

