Розробка сайту логістичної компанії на 1С-Бітрікс
Сайт логістичної компанії — це не вітрина, а робочий інструмент. Вантажовідправник заходить з конкретним завданням: дізнатися вартість перевезення з точки A в точку B, оформити заявку, відстежити вантаж. Якщо калькулятор не рахує, трекінг не показує статус, а для повторного відправлення треба заново заповнювати 12 полів — клієнт йде до конкурента з нормальним особистим кабінетом. Бітрікс дозволяє зібрати все це, але архітектура має враховувати специфіку логістики з першого дня.
Каталог послуг: інфоблоки під типи перевезень
Логістична компанія пропонує не один продукт, а матрицю послуг: FTL (повне завантаження), LTL (збірний вантаж), warehousing, митне оформлення, last-mile доставка. Кожен тип має свої параметри — обмеження за вагою, габаритами, температурним режимом, географією.
Структура даних:
- Інфоблок «Послуги» — розділи: Автоперевезення, Морські, Залізничні, Авіа, Складські послуги, Митниця
-
Highload-блок «Типи транспорту» — довідник: тент, рефрижератор, контейнер 20', контейнер 40', ізотерм. Поля:
UF_NAME,UF_CAPACITY_KG,UF_VOLUME_M3,UF_PHOTO,UF_DESCRIPTION -
Highload-блок «Маршрути» — пари місто-місто з прив'язкою до типів перевезень. Поля:
UF_FROM_CITY,UF_TO_CITY,UF_TRANSPORT_TYPE,UF_TRANSIT_DAYS,UF_ACTIVE - Highload-блок «Обмеження вантажу» — максимальна вага, габарити, заборонені категорії за типом транспорту
Кожен елемент інфоблоку послуг містить:
| Властивість | Тип | Призначення |
|---|---|---|
| SERVICE_TYPE | L (список) | FTL / LTL / Warehousing / Customs / LastMile |
| TRANSPORT_TYPES | S:Highload (множ.) | Прив'язка до допустимих типів транспорту |
| ROUTE_DIRECTIONS | S:Highload (множ.) | Доступні напрямки |
| MAX_WEIGHT | N | Макс. вага вантажу, кг |
| MAX_VOLUME | N | Макс. об'єм, м³ |
| TEMPERATURE_MODE | L | Звичайний / Холодильник / Морозильник |
| INSURANCE_AVAILABLE | L | Так / Ні |
| CUSTOMS_INCLUDED | L | Так / Ні |
Для SEO ключові сторінки за шаблоном «[тип перевезення] + [маршрут]»: «Автоперевезення Київ — Одеса», «Збірні вантажі з Європи». Ці сторінки генеруються зі зв'язки інфоблоку послуг та Highload-блоку маршрутів через кастомний компонент. URL будується за шаблоном /poslugy/{service-code}/{from}-{to}/, ЧПУ налаштовується через CIBlockElement::GetList з фільтром за властивостями ROUTE_FROM і ROUTE_TO.
Калькулятор вартості перевезення: головна конверсійна точка
Калькулятор — причина, через яку 70% відвідувачів приходять на сайт логістичної компанії. Не форма «залиште заявку, ми передзвонимо», а реальний розрахунок: звідки, куди, що веземо, скільки коштує. Якщо калькулятор не дає ціну — відвідувач не стає лідом.
Архітектура калькулятора складається з трьох шарів.
Шар 1 — фронтенд: багатокрокова форма. Крок 1: звідки → куди (автокомпліт міст через AJAX, дані з Highload-блоку «Міста» або зовнішній API — Google Places для українського ринку). Крок 2: параметри вантажу — вага, об'єм (Д×Ш×В), кількість місць, тип пакування, температурний режим. Крок 3: додаткові опції — страхування, митне оформлення, доставка до дверей. Крок 4: результат — вартість, термін, доступні види транспорту.
Форма реалізується як React-компонент або vanilla JS з покроковою навігацією. Кожен крок — AJAX-валідація на сервері. Автокомпліт міст — окремий endpoint /api/cities/suggest/?q=Киї, який шукає по b_hlbd_cities (Highload-блок) через DataManager::getList() з фільтром ['%UF_NAME' => $query].
Шар 2 — розрахунок відстані. Тарифи залежать від відстані. Два підходи:
Підхід A — попередньо розрахована матриця відстаней у Highload-блоці DistanceMatrix. Поля: UF_FROM_CITY_ID, UF_TO_CITY_ID, UF_DISTANCE_KM, UF_TRANSIT_HOURS. При 300 містах — 90К записів, цілком підйомно. Плюс: миттєва відповідь, не залежить від зовнішніх API. Мінус: потрібно перераховувати при додаванні міст.
Підхід B — розрахунок через зовнішній API в реальному часі. Google Distance Matrix API — для українського ринку зручніший за Yandex.Routing, працює стабільно з усіма населеними пунктами. Запит: дві точки → відстань у км + час у дорозі. Кешування результату в Highload-блок: якщо пара місто-місто вже розрахована і кеш не старший 30 днів — беремо з кешу, інакше — API-запит + збереження.
// Отримання відстані з кешуванням
class DistanceService
{
public static function getDistance(int $fromCityId, int $toCityId): array
{
$cached = DistanceMatrixTable::getList([
'filter' => [
'UF_FROM_CITY_ID' => $fromCityId,
'UF_TO_CITY_ID' => $toCityId,
'>UF_CACHED_AT' => date('Y-m-d', strtotime('-30 days'))
]
])->fetch();
if ($cached) {
return [
'distance_km' => $cached['UF_DISTANCE_KM'],
'transit_hours' => $cached['UF_TRANSIT_HOURS']
];
}
$result = GoogleDistanceMatrixClient::calculate(
Cities::getCoordinates($fromCityId),
Cities::getCoordinates($toCityId)
);
DistanceMatrixTable::add([
'UF_FROM_CITY_ID' => $fromCityId,
'UF_TO_CITY_ID' => $toCityId,
'UF_DISTANCE_KM' => $result['distance'],
'UF_TRANSIT_HOURS' => $result['duration'],
'UF_CACHED_AT' => new DateTime()
]);
return $result;
}
}
Шар 3 — тарифікація. Тарифи зберігаються в Highload-блоці Tariffs:
| Поле | Тип | Опис |
|---|---|---|
| UF_SERVICE_TYPE | список | FTL / LTL / Express |
| UF_TRANSPORT_TYPE | прив'язка | Тип транспорту |
| UF_DISTANCE_FROM | число | Початок діапазону, км |
| UF_DISTANCE_TO | число | Кінець діапазону, км |
| UF_RATE_PER_KM | число | Ставка за км |
| UF_MIN_RATE | число | Мінімальна вартість |
| UF_WEIGHT_COEFF | число | Коефіцієнт за перевагу |
| UF_VOLUME_COEFF | число | Коефіцієнт за об'єм |
Формула розрахунку для LTL: max(distance_km * rate_per_km, min_rate) * weight_coeff * volume_coeff + insurance + customs_fee. Для FTL — простіше: фіксована ставка за км × відстань, без вагових коефіцієнтів (машина цілком).
Менеджер оновлює тарифи через адміністративний інтерфейс Highload-блоку — без залучення розробника. Це критичний момент: тарифи змінюються щотижня, і якщо для оновлення ціни потрібен деплой — система непрацездатна.
Результат калькулятора повертається JSON-відповіддю:
{
"variants": [
{
"transport": "Тент 20т",
"service": "FTL",
"price": 18000,
"currency": "UAH",
"transit_days": 1,
"distance_km": 480
},
{
"transport": "Збірний вантаж",
"service": "LTL",
"price": 4200,
"currency": "UAH",
"transit_days": 3,
"distance_km": 480
}
]
}
Під результатом — кнопка «Оформити заявку», яка переносить усі параметри розрахунку у форму замовлення. Користувачу не потрібно вводити дані повторно.
Відстеження вантажу
Трекінг — друга причина, через яку клієнти повертаються на сайт. Поле введення трекінг-номера на головній сторінці, результат — ланцюжок статусів з датами та поточне місцезнаходження на карті.
Джерело даних — 1С:TMS або 1С:Логістика. Інтеграція через REST API Бітрікса: 1С надсилає оновлення статусу через POST /rest/logistics.shipment.updateStatus з полями tracking_number, status_code, location, timestamp. Бітрікс зберігає статуси в Highload-блоці ShipmentStatuses.
На фронті — AJAX-запит за трекінг-номером. Відповідь містить масив статусів (прийнято, на складі, в дорозі, на митниці, доставлено) та координати останнього відомого місцезнаходження для відображення на Google Maps.
Оновлення в реальному часі — через polling кожні 60 секунд або WebSocket, якщо обсяг трафіку виправдовує складність реалізації.
Клієнтський портал: B2B-кабінет
Особистий кабінет для корпоративних клієнтів — те, що відрізняє серйозну логістичну компанію від «сайту-візитки з калькулятором». Це не просто історія замовлень, а повноцінний робочий інструмент логіста.
Авторизація та ролі. Компанія-клієнт реєструється як юридична особа. Всередині компанії — кілька користувачів з різними ролями. Реалізація через групи користувачів Бітрікса (CGroup) та кастомні поля:
- Адміністратор компанії — бачить усі замовлення, керує користувачами, завантажує документи, бачить фінанси
- Логіст — створює замовлення, відстежує статуси, завантажує ТТН та CMR
- Бухгалтер — доступ тільки до документів: рахунки, акти, податкові накладні
Прив'язка користувача до компанії — через кастомне поле UF_COMPANY_ID в b_user. Перевірка доступу — middleware в init.php, який при кожному запиті до /personal/ перевіряє групу користувача та UF_COMPANY_ID.
Функціональність кабінету:
Історія замовлень — список усіх перевезень компанії з фільтрацією за датою, статусом, напрямком. Дані з Highload-блоку Orders: UF_ORDER_NUMBER, UF_COMPANY_ID, UF_FROM_CITY, UF_TO_CITY, UF_STATUS, UF_CARGO_DESCRIPTION, UF_WEIGHT, UF_VOLUME, UF_PRICE, UF_CREATED_AT. Пагінація через bitrix:system.pagenavigation, фільтрація — AJAX.
Документообіг — кожне замовлення містить набір документів: ТТН, CMR, інвойс, пакувальний лист, страховий поліс. Файли зберігаються як множинна властивість типу «Файл» у прив'язці до замовлення. Завантаження — через кастомний контролер, який перевіряє належність документа до компанії користувача перед видачею файлу. Жодних прямих посилань на /upload/ — тільки авторизований доступ.
// Перевірка доступу до документа
class DocumentController extends Controller
{
public function download(int $orderId, int $fileId): Response
{
$user = $GLOBALS['USER'];
$order = OrdersTable::getById($orderId)->fetch();
if ($order['UF_COMPANY_ID'] !== $user->getUfCompanyId()) {
throw new AccessDeniedException();
}
$file = CFile::GetFileArray($fileId);
return new BinaryFileResponse($file['SRC']);
}
}
Шаблони повторних відправлень. Постійний клієнт відправляє однакові вантажі за однаковими маршрутами. Логіст зберігає замовлення як шаблон, наступного разу — обирає шаблон, змінює дату, підтверджує. Шаблони — окремий Highload-блок ShipmentTemplates з полями, що дублюють структуру замовлення, плюс UF_TEMPLATE_NAME та UF_COMPANY_ID.
Фінансовий розділ — баланс взаєморозрахунків, виставлені рахунки, історія оплат. Дані синхронізуються з 1С через REST API за розкладом (кожні 15 хвилин) або за подією.
Інтеграція з 1С:TMS
Синхронізація замовлень між сайтом та 1С:TMS (або 1С:Управління автотранспортом) — двостороння:
- Сайт → 1С: нове замовлення з сайту надсилається в 1С через REST API. Endpoint на стороні 1С приймає JSON з параметрами замовлення, створює документ «Заявка на перевезення»
-
1С → Сайт: зміна статусу в 1С тригерить webhook на Бітрікс. Обробник оновлює
UF_STATUSу Highload-блоціOrdersта надсилає email/SMS клієнту
Формат обміну — JSON через HTTP REST. XML-обмін через CommerceML для логістики надлишковий — це формат торгівлі, не перевезень.
Карта покриття та автопарк
Інтерактивна карта — Google Maps з кастомним шаром. Маркери складів та хабів з Highload-блоку Warehouses (поля: UF_NAME, UF_ADDRESS, UF_COORDINATES, UF_TYPE, UF_PHOTO). Лінії маршрутів між хабами — google.maps.Polyline з даними з Highload-блоку маршрутів. Клік по хабу — інфовікно з адресою, графіком роботи, доступними послугами.
Автопарк — інфоблок з типами транспорту. Картка машини: фото, вантажопідйомність, об'єм кузова, тип (тент, рефрижератор, контейнеровоз). Вивід через bitrix:news.list з кастомним шаблоном — сітка карток з іконками характеристик.
API для партнерів
REST API для інтеграції з системами партнерів: експедиторів, маркетплейсів, ERP-систем клієнтів. Endpoints:
-
POST /api/v1/orders/create— створення замовлення -
GET /api/v1/orders/{id}/status— статус замовлення -
GET /api/v1/tracking/{number}— трекінг -
POST /api/v1/calculate— розрахунок вартості
Авторизація — API-ключ у заголовку X-Api-Key. Ключі генеруються в адмінці, прив'язані до компанії-партнера. Rate limiting — 100 запитів на хвилину через middleware.
Етапи та терміни
| Масштаб | Терміни |
|---|---|
| Сайт-візитка з калькулятором, до 10 маршрутів | 4-6 тижнів |
| Корпоративний сайт з кабінетом, трекінг, 1С-інтеграція | 10-16 тижнів |
| Платформа з API для партнерів, B2B-портал, повна автоматизація | 16-24 тижні |
Терміни не включають налаштування обміну на стороні 1С — це окремий проєкт з боку 1С-розробника, який виконується паралельно.







