Налаштування тарифів і сезонних цін на проживання в 1С-Бітрікс
Ціноутворення в готелі влаштоване складніше, ніж в інтернет-магазині. Один номер може коштувати по-різному залежно від дати заїзду, тривалості проживання, дня тижня, типу харчування та каналу продажу. Стандартний механізм цін 1С-Бітрікс (b_catalog_price) розрахований на фіксовані прайс-типи, а не на матрицю «дата × тариф × тривалість проживання». Потрібна кастомна модель.
Модель тарифів
Тарифи зберігаються в таблиці bl_room_rates:
CREATE TABLE bl_room_rates (
id SERIAL PRIMARY KEY,
room_type_id INT NOT NULL,
rate_code VARCHAR(64) NOT NULL,
rate_name VARCHAR(255) NOT NULL,
meal_plan VARCHAR(20) DEFAULT 'RO', -- RO, BB, HB, FB
cancellation VARCHAR(20) DEFAULT 'free',-- free, non_refundable, 48h
min_nights SMALLINT DEFAULT 1,
max_nights SMALLINT,
active BOOLEAN DEFAULT true
);
Сезонні ціни — у bl_room_rate_prices:
CREATE TABLE bl_room_rate_prices (
id SERIAL PRIMARY KEY,
rate_id INT REFERENCES bl_room_rates(id),
date_from DATE NOT NULL,
date_to DATE NOT NULL,
price_night NUMERIC(10,2) NOT NULL,
occupancy SMALLINT DEFAULT 2, -- для якої кількості гостей (1, 2, 3...)
day_mask SMALLINT DEFAULT 127 -- бітова маска днів: пн=1, вт=2, ср=4...
);
CREATE INDEX idx_rate_prices_dates ON bl_room_rate_prices(rate_id, date_from, date_to);
day_mask дозволяє задати різні ціни на вихідні та будні в рамках одного сезону. Біт 64 = неділя, 32 = субота і т.д. Маска 127 = всі дні.
Розрахунок вартості проживання
При запиті на конкретні дати потрібно порахувати ціну для кожної ночі окремо (різні ночі можуть потрапити в різні цінові періоди) і підсумувати:
public function calculatePrice(int $rateId, \DateTime $dateFrom, \DateTime $dateTo, int $occupancy): float
{
$total = 0.0;
$current = clone $dateFrom;
while ($current < $dateTo) {
$dayBit = pow(2, (int)$current->format('N') - 1); // 1=пн, 7=нд
$priceRow = \Bitrix\Main\Application::getConnection()->query(
"SELECT price_night FROM bl_room_rate_prices
WHERE rate_id = ?
AND date_from <= ?
AND date_to > ?
AND occupancy <= ?
AND (day_mask & ?) > 0
ORDER BY occupancy DESC
LIMIT 1",
[$rateId, $current->format('Y-m-d'), $current->format('Y-m-d'), $occupancy, $dayBit]
)->fetch();
if (!$priceRow) {
throw new \RuntimeException('Немає ціни для дати ' . $current->format('Y-m-d'));
}
$total += (float)$priceRow['price_night'];
$current->modify('+1 day');
}
return $total;
}
Правила мінімального проживання
Обмеження щодо мінімальної та максимальної кількості ночей часто задаються не на рівні тарифу в цілому, а на конкретні періоди. Таблиця bl_room_min_stay:
CREATE TABLE bl_room_min_stay (
room_type_id INT NOT NULL,
date_from DATE NOT NULL,
date_to DATE NOT NULL,
min_nights SMALLINT NOT NULL DEFAULT 1,
max_nights SMALLINT
);
На новорічні свята мінімальний строк = 4 ночі, у звичайний час = 1. При відображенні форми бронювання перевіряємо обмеження і показуємо користувачу попередження, якщо він вибрав неприпустимий діапазон.
Доплати за додаткових гостей
Базова ціна розрахована на двох гостей. За третього та четвертого гостя — доплата. Зберігається в bl_room_rate_extra_guest:
| rate_id | guest_num | price_per_night |
|---|---|---|
| 1 | 3 | 800.00 |
| 1 | 4 | 800.00 |
При розрахунку вартості для 3 гостей: базова ціна + (кількість ночей × доплата).
Адміністративний інтерфейс управління цінами
У /bitrix/admin/ створюємо розділ «Тарифи і ціни». Ключові функції:
- Список тарифів за типами номерів із можливістю ввімкнути/вимкнути
- Ціновий календар — таблиця з датами по горизонталі і тарифами по вертикалі, редагування через клік
- Копіювання періоду — скопіювати ціни минулого року на поточний із застосуванням коефіцієнта (наприклад ×1.1)
- Масове оновлення — змінити ціни для діапазону дат і набору тарифів за один запит
Інтеграція з формою бронювання
На сайті форма бронювання при виборі дат робить AJAX-запит до контролера RatesController::getAvailableAction. Контролер:
- Перевіряє доступність номерів через
bl_room_booking - Завантажує доступні тарифи з
bl_room_rates - Рахує ціну для кожного тарифу через
calculatePrice() - Повертає JSON із варіантами: тариф, умови скасування, тип харчування, підсумкова ціна
Користувач бачить кілька варіантів бронювання і вибирає відповідний.
Терміни
| Етап | Термін |
|---|---|
| Проєктування і створення схеми БД | 2 дні |
| Клас розрахунку вартості | 2 дні |
| AJAX-контролер для форми | 1 день |
| Адміністративний інтерфейс | 3–4 дні |
| Тестування граничних випадків | 2 дні |
| Разом | 10–12 днів |







