Разработка калькулятора стоимости услуг на 1С-Битрикс
Калькулятор стоимости услуг — это инструмент квалификации: он отвечает на вопрос «сколько это стоит» в момент, когда потенциальный клиент ещё не готов звонить, но уже готов принимать решение. Правильно построенный калькулятор не обещает точную цену — он даёт диапазон, достаточный для того, чтобы клиент понял, укладывается ли это в его бюджет.
Специфика расчёта стоимости услуг
Услуги сложнее товаров: у них нет фиксированной цены. Стоимость зависит от объёма, сложности, сроков, квалификации исполнителя, региона, сезонности. Калькулятор должен учитывать эти переменные, не превращаясь в бесконечную анкету.
Типичные параметры для калькулятора услуг:
- Объём работ — площадь, количество единиц, число часов
- Тип/категория — базовый, стандарт, премиум
- Дополнительные опции — срочность, выезд специалиста, материалы
- География — регион, расстояние
Каждый параметр влияет на итоговую сумму через коэффициент или фиксированную надбавку.
Модель данных: тарифы в HighLoad-блоке
Тарифная таблица для калькулятора услуг хранится в HighLoad-блоке — это производительнее инфоблока и удобнее жёстко прописанных массивов:
// Получение тарифов из HL-блока
$hlblock = \Bitrix\Highloadblock\HighloadBlockTable::getById(SERVICES_TARIFF_HL_ID)->fetch();
$entity = \Bitrix\Highloadblock\HighloadBlockTable::compileEntity($hlblock);
$className = $entity->getDataClass();
$tariffs = $className::getList([
'select' => ['UF_SERVICE_TYPE', 'UF_VOLUME_FROM', 'UF_VOLUME_TO', 'UF_BASE_PRICE', 'UF_PRICE_PER_UNIT'],
'filter' => ['=UF_ACTIVE' => true],
'order' => ['UF_SERVICE_TYPE' => 'ASC', 'UF_VOLUME_FROM' => 'ASC'],
])->fetchAll();
Структура HL-таблицы:
| Поле | Тип | Назначение |
|---|---|---|
UF_SERVICE_TYPE |
Справочник | Тип услуги |
UF_VOLUME_FROM |
Float | Минимальный объём |
UF_VOLUME_TO |
Float | Максимальный объём |
UF_BASE_PRICE |
Float | Базовая стоимость |
UF_PRICE_PER_UNIT |
Float | Стоимость за единицу сверх базы |
UF_COMPLEXITY_COEFFICIENT |
Float | Коэффициент сложности |
Логика расчёта на PHP
Сервисный класс, инкапсулирующий алгоритм расчёта:
namespace MyProject\Services;
class ServiceCostCalculator
{
private array $tariffs;
private array $options;
public function __construct(array $tariffs, array $options)
{
$this->tariffs = $tariffs;
$this->options = $options;
}
public function calculate(string $serviceType, float $volume, array $extras = []): array
{
$tariff = $this->findTariff($serviceType, $volume);
if (!$tariff) {
throw new \InvalidArgumentException("Тариф не найден для объёма {$volume}");
}
$baseCost = $tariff['UF_BASE_PRICE'];
if ($volume > $tariff['UF_VOLUME_FROM']) {
$extra = $volume - $tariff['UF_VOLUME_FROM'];
$baseCost += $extra * $tariff['UF_PRICE_PER_UNIT'];
}
// Применяем коэффициенты дополнительных опций
$optionsCost = 0;
foreach ($extras as $optionKey => $enabled) {
if ($enabled && isset($this->options[$optionKey])) {
$opt = $this->options[$optionKey];
if ($opt['type'] === 'percent') {
$optionsCost += $baseCost * ($opt['value'] / 100);
} else {
$optionsCost += $opt['value'];
}
}
}
$total = $baseCost + $optionsCost;
return [
'base_cost' => round($baseCost, 2),
'options_cost' => round($optionsCost, 2),
'total_min' => round($total * 0.9, 2), // -10% — нижняя граница
'total_max' => round($total * 1.15, 2), // +15% — верхняя граница
'total' => round($total, 2),
'currency' => 'RUB',
];
}
private function findTariff(string $serviceType, float $volume): ?array
{
foreach ($this->tariffs as $tariff) {
if ($tariff['UF_SERVICE_TYPE'] === $serviceType
&& $volume >= $tariff['UF_VOLUME_FROM']
&& $volume <= $tariff['UF_VOLUME_TO']) {
return $tariff;
}
}
return null;
}
}
Отображение диапазона цен
Фиксированная цена для услуг часто невозможна. Калькулятор показывает диапазон:
function updateResult(data) {
const formatPrice = (p) => new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB',
maximumFractionDigits: 0,
}).format(p);
document.getElementById('result-min').textContent = formatPrice(data.total_min);
document.getElementById('result-max').textContent = formatPrice(data.total_max);
document.getElementById('result-note').textContent =
'Точная стоимость определяется после осмотра объекта';
}
Интеграция с CRM: передача расчёта в сделку
После того как пользователь оставил заявку, данные расчёта добавляются в сделку или лид CRM:
// Кастомные поля лида для хранения параметров расчёта
$lead->Add([
'TITLE' => 'Расчёт: ' . $serviceTypeName,
'OPPORTUNITY' => $calculationResult['total'],
'CURRENCY_ID' => 'RUB',
'COMMENTS' => $this->buildCommentsFromParams($params, $calculationResult),
'UF_CALC_PARAMS' => json_encode($params), // JSON параметров
'UF_CALC_RESULT' => json_encode($calculationResult),
]);
Сроки
| Задача | Срок |
|---|---|
| Калькулятор с 5–7 параметрами, линейный расчёт, форма заявки | 5–8 дней |
| Калькулятор с тарифной сеткой из HL-блока, диапазон цен, интеграция с CRM | 2–3 недели |
| Мультиуслуговой калькулятор с выбором услуги, сложными коэффициентами и историей расчётов | 4–6 недель |
Хороший калькулятор стоимости услуг — это не обещание цены, а инструмент квалификации бюджета. Клиент понимает порядок цифр и принимает решение о следующем шаге. Задача — сделать этот шаг максимально лёгким.







