Налаштування пропозиції найближчого магазину за геолокацією 1С-Бітрікс
Функція «знайти найближчий магазин» потрібна рітейлу з мережею офлайн-точок. Користувач дозволяє доступ до геолокації — сайт показує найближчий магазин, його режим роботи, залишки товарів. Розглядаємо реалізацію на базі складського модуля Бітрікса.
Зберігання адрес магазинів
У Бітріксі магазини (склади/торгові точки) зберігаються в таблиці b_catalog_store (модуль catalog). У кожного складу є поля: TITLE, ADDRESS, PHONE, SCHEDULE, GPS_N (широта), GPS_S (довгота), ACTIVE.
Якщо поля GPS_N / GPS_S не заповнені — потрібно геокодувати адреси (через API Яндекса або Google) та зберегти координати. Це робиться один раз для всіх магазинів.
Додати координати магазину програмно:
\Bitrix\Catalog\StoreTable::update($storeId, [
'GPS_N' => 50.4501, // широта
'GPS_S' => 30.5234, // довгота
]);
Обчислення відстані та вибір найближчого
Координати користувача отримуєте через JavaScript navigator.geolocation.getCurrentPosition() та передаєте на сервер. На сервері обчислюєте відстань до кожного складу за формулою Haversine.
Запит із сортуванням за відстанню через SQL (PostgreSQL/MySQL з формулою Haversine):
SELECT id, title, address, gps_n, gps_s,
(6371 * acos(
cos(radians(:lat)) * cos(radians(gps_n)) *
cos(radians(gps_s) - radians(:lng)) +
sin(radians(:lat)) * sin(radians(gps_n))
)) AS distance
FROM b_catalog_store
WHERE active = 'Y' AND gps_n IS NOT NULL
ORDER BY distance ASC
LIMIT 5;
Або PHP-реалізація без прямого SQL, якщо хочете використовувати ORM Бітрікса:
function haversineDistance(
float $lat1, float $lon1,
float $lat2, float $lon2
): float {
$R = 6371; // км
$dLat = deg2rad($lat2 - $lat1);
$dLon = deg2rad($lon2 - $lon1);
$a = sin($dLat/2)**2
+ cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon/2)**2;
return $R * 2 * atan2(sqrt($a), sqrt(1-$a));
}
$stores = \Bitrix\Catalog\StoreTable::getList([
'filter' => ['=ACTIVE' => 'Y', '!=GPS_N' => false],
'select' => ['ID', 'TITLE', 'ADDRESS', 'GPS_N', 'GPS_S', 'SCHEDULE', 'PHONE'],
])->fetchAll();
usort($stores, function($a, $b) use ($userLat, $userLng) {
$dA = haversineDistance($userLat, $userLng, $a['GPS_N'], $a['GPS_S']);
$dB = haversineDistance($userLat, $userLng, $b['GPS_N'], $b['GPS_S']);
return $dA <=> $dB;
});
$nearest = array_slice($stores, 0, 3);
AJAX-ендпоінт для фронтенду
// /local/ajax/nearest-store.php
$lat = (float)$_POST['lat'];
$lng = (float)$_POST['lng'];
// ... вибірка та сортування ...
header('Content-Type: application/json');
echo json_encode([
'nearest' => [
'id' => $nearest[0]['ID'],
'title' => $nearest[0]['TITLE'],
'address' => $nearest[0]['ADDRESS'],
'distance' => round($dist, 1),
'schedule' => $nearest[0]['SCHEDULE'],
'phone' => $nearest[0]['PHONE'],
],
]);
Показ залишків у найближчому магазині
Після визначення магазину можна показувати залишки товару в цій точці прямо в картці товару. Дані з b_catalog_store_product:
$stock = \Bitrix\Catalog\StoreProductTable::getList([
'filter' => [
'=PRODUCT_ID' => $productId,
'=STORE_ID' => $nearestStoreId,
],
'select' => ['AMOUNT'],
])->fetch();
$inStock = $stock && $stock['AMOUNT'] > 0;
UI та UX
Типовий інтерфейс: спливаючий блок у шапці «Найближчий магазин: [Назва], [відстань] км» або віджет на сторінці товару «Наявність у магазинах». Кнопка «Визначити» запускає запит геолокації. Якщо користувач відмовив у доступі — показуєте список магазинів із пошуком за адресою.
Для повноцінної карти — підключаєте Яндекс.Карти JS API або Google Maps API та розставляєте мітки всіх точок.
| Етап | Час |
|---|---|
| Геокодування адрес магазинів | 2–3 год |
| AJAX-ендпоінт з обчисленням відстані | 3–4 год |
| Віджет на сторінці / у шапці | 3–5 год |
| Показ залишків за найближчим складом | 2–3 год |
| Інтеграція карти (опційно) | 4–6 год |







