Розробка віджета вибору пунктів видачі на карті 1С-Бітрікс
При оформленні замовлення користувач повинен вибрати найближчий пункт видачі — на карті, з фільтрами за режимом роботи, типом ПВЗ, відстанню від адреси. Стандартний компонент sale.order.ajax пропонує тільки випадаючий список з адресами. Це працює для 10 пунктів, але стає незручним при 500+. Віджет з картою вирішує цю проблему.
Де живе віджет в архітектурі Бітрікс
Віджет вбудовується в процес оформлення замовлення. Використовуємо подію OnBeforeSaleOrderFinalAction або шаблон компонента sale.checkout.v2 — залежно від того, який checkout використовується на сайті.
Віджет — це окремий JS-компонент, який:
- Завантажує список ПВЗ через AJAX-запит до обробника на сервері.
- Рендерить карту (Yandex.Maps або Leaflet з OpenStreetMap).
- Розставляє мітки ПВЗ на карті.
- За кліком на мітку показує інформацію про ПВЗ.
- При підтвердженні вибору записує ПВЗ в властивість замовлення.
Зберігання даних про пункти видачі
Якщо ПВЗ приходять із служби доставки (CDEK, 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 години виправданий.
Frontend: інтеграція з Yandex.Maps
// Ініціалізація карти
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 / метод | Частота синхронізації |
|---|---|---|
| CDEK | GET /v2/deliverypoints |
1 раз на добу |
| Boxberry | ListPoints (SOAP/REST) |
1 раз на добу |
| Пошта Росії | Tariff.offices |
1 раз на тиждень |
| DPD | getParcelShops |
1 раз на добу |
| Yandex.Delivery | GET /pickup-points |
1 раз на добу |
Агент Бітрікс запускає синхронізацію, оновлює custom_pvz_points через INSERT ... ON DUPLICATE KEY UPDATE, знімає флаг is_active у зниклих пунктів.
Строки
| Етап | Строк |
|---|---|
| Проектування схеми даних, вибір картографічного API | 1–2 дні |
| Серверна частина: зберігання, AJAX-обробник, синхронізація | 3–5 днів |
| Frontend: карта, мітки, кластеризація, вибір ПВЗ | 4–6 днів |
| Інтеграція в checkout (передача в замовлення) | 2–3 дні |
| Розрахунок вартості при виборі ПВЗ | 1–2 дні |
| Тестування + мобільна адаптація | 2–3 дні |
Разом: 2–3 тижні. Якщо потрібна інтеграція з кількома провайдерами доставки одночасно — плюс 3–5 днів на кожного.







