Разработка виджета выбора пунктов выдачи на карте 1С-Битрикс
При оформлении заказа пользователь должен выбрать ближайший пункт выдачи — на карте, с фильтрами по режиму работы, типу ПВЗ, расстоянию от адреса. Стандартный компонент sale.order.ajax предлагает только выпадающий список с адресами. Это работает для 10 пунктов, но становится неудобным при 500+. Виджет с картой решает эту проблему.
Где живёт виджет в архитектуре Битрикс
Виджет встраивается в процесс оформления заказа. Используем событие OnBeforeSaleOrderFinalAction или шаблон компонента sale.checkout.v2 — в зависимости от того, какой checkout используется на сайте.
Виджет — это отдельный JS-компонент, который:
- Загружает список ПВЗ через AJAX-запрос к обработчику на сервере.
- Рендерит карту (Яндекс.Карты или Leaflet с OpenStreetMap).
- Расставляет метки ПВЗ на карте.
- По клику на метку показывает информацию о ПВЗ.
- При подтверждении выбора записывает ПВЗ в свойство заказа.
Хранение данных о пунктах выдачи
Если ПВЗ приходят из службы доставки (СДЭК, Boxberry, Почта России) — данные синхронизируются периодически. Структура:
CREATE TABLE custom_pvz_points (
id SERIAL PRIMARY KEY,
provider VARCHAR(50) NOT NULL, -- 'cdek', 'boxberry', 'pochta'
external_id VARCHAR(100) NOT NULL,
name VARCHAR(255) NOT NULL,
address TEXT NOT NULL,
city VARCHAR(100),
lat DECIMAL(10,8) NOT NULL,
lng DECIMAL(11,8) NOT NULL,
schedule JSON,
phone VARCHAR(50),
is_active TINYINT DEFAULT 1,
synced_at DATETIME,
INDEX idx_city (city),
INDEX idx_coords (lat, lng),
UNIQUE KEY uk_provider_ext (provider, external_id)
);
Синхронизация запускается через агент Битрикс (\Bitrix\Main\Agent) раз в сутки или по запросу из административной панели.
Серверный обработчик (AJAX-endpoint)
Запросы от виджета обрабатываются через /bitrix/services/main/ajax.php или local/ajax/pvz.php. Обработчик принимает параметры: город, координаты центра карты, радиус, провайдер доставки.
// Получаем ПВЗ в радиусе N км от координат
$lat = (float)$_REQUEST['lat'];
$lng = (float)$_REQUEST['lng'];
$radius = (int)($_REQUEST['radius'] ?? 10); // км
// Формула Haversine в SQL
$sql = "
SELECT *, (
6371 * ACOS(
COS(RADIANS({$lat})) * COS(RADIANS(lat))
* COS(RADIANS(lng) - RADIANS({$lng}))
+ SIN(RADIANS({$lat})) * SIN(RADIANS(lat))
)
) AS distance
FROM custom_pvz_points
WHERE is_active = 1
HAVING distance <= {$radius}
ORDER BY distance
LIMIT 100
";
Результат кешируется через \Bitrix\Main\Data\Cache с ключом по городу и провайдеру. Список ПВЗ меняется раз в сутки — кеш на 12–24 часа оправдан.
Фронтенд: интеграция с Яндекс.Картами
// Инициализация карты
ymaps.ready(function() {
const map = new ymaps.Map('pvz-map', {
center: [userLat, userLng],
zoom: 12,
controls: ['zoomControl', 'geolocationControl']
});
// Кластеризация меток при большом числе ПВЗ
const clusterer = new ymaps.Clusterer({
preset: 'islands#invertedDarkBlueClusterIcons',
groupByCoordinates: false,
});
points.forEach(pvz => {
const placemark = new ymaps.Placemark(
[pvz.lat, pvz.lng],
{
balloonContentHeader: pvz.name,
balloonContentBody: `${pvz.address}<br>${pvz.schedule}`,
hintContent: pvz.name,
},
{ preset: 'islands#darkBlueIcon' }
);
placemark.events.add('click', function() {
selectPvz(pvz);
});
clusterer.add(placemark);
});
map.geoObjects.add(clusterer);
});
При выборе ПВЗ через selectPvz() заполняются скрытые поля формы заказа — адрес доставки и внешний ID пункта. Эти данные передаются в свойство заказа DELIVERY_LOCATION или кастомное свойство UF_PVZ_ID.
Геолокация пользователя
При открытии виджета запрашиваем координаты пользователя через navigator.geolocation.getCurrentPosition(). Если разрешение не выдано — определяем город через IP (сервис ip-api.com или встроенный геолокатор Битрикс \Bitrix\Main\Web\IpTools). Карта центрируется на найденном городе.
Интеграция с расчётом стоимости доставки
После выбора ПВЗ виджет обновляет стоимость доставки. Запрос к обработчику, который вызывает \Bitrix\Sale\Delivery\Services\Manager::calculateDelivery() с выбранным пунктом — возвращает стоимость и срок. Данные показываются рядом с адресом ПВЗ ещё до подтверждения.
Синхронизация с провайдерами
| Провайдер | API / метод | Частота синхронизации |
|---|---|---|
| СДЭК | GET /v2/deliverypoints |
1 раз в сутки |
| Boxberry | ListPoints (SOAP/REST) |
1 раз в сутки |
| Почта России | Tariff.offices |
1 раз в неделю |
| DPD | getParcelShops |
1 раз в сутки |
| Яндекс.Доставка | GET /pickup-points |
1 раз в сутки |
Агент Битрикс запускает синхронизацию, обновляет custom_pvz_points через INSERT ... ON DUPLICATE KEY UPDATE, снимает флаг is_active у исчезнувших пунктов.
Сроки
| Этап | Срок |
|---|---|
| Проектирование схемы данных, выбор картографического API | 1–2 дня |
| Серверная часть: хранение, AJAX-обработчик, синхронизация | 3–5 дней |
| Фронтенд: карта, метки, кластеризация, выбор ПВЗ | 4–6 дней |
| Интеграция в checkout (передача в заказ) | 2–3 дня |
| Расчёт стоимости при выборе ПВЗ | 1–2 дня |
| Тестирование + мобильная адаптация | 2–3 дня |
Итого: 2–3 недели. Если нужна интеграция с несколькими провайдерами доставки одновременно — плюс 3–5 дней на каждого.







