Розробка калькулятора вартості проєкту на 1С-Бітрікс
Калькулятор вартості проєкту — це інструмент первинної кваліфікації для IT-компаній, агентств, проєктних організацій і студій. Він не дає точну ціну — це неможливо без занурення в завдання — але допомагає клієнту зрозуміти порядок цифр і сегментує вхідний потік: відсіює нецільові запити та підігріває серйозні.
Специфіка розрахунку проєктних робіт
Проєкт — не товар із фіксованою ціною. Вартість залежить від:
- Набору функціональних блоків (що входить до обсягу)
- Складності кожного блоку (від стандартного до кастомного)
- Технологічного стека (швидкість розробки, вартість ліцензій)
- Термінів (терміновий проєкт коштує дорожче)
- Типу відносин (разова розробка, підтримка, аутсорс)
Калькулятор структурує ці змінні в керований опитувальник.
Модель даних: блоки та їхня вартість
Функціональні блоки зберігаються в HL-блоці ProjectBlocks:
| Поле | Тип | Опис |
|---|---|---|
UF_CATEGORY |
Enum | Категорія (Дизайн, Розробка, Інтеграція, SEO…) |
UF_BLOCK_NAME |
String | Назва блоку |
UF_COMPLEXITY |
Enum | simple / standard / complex |
UF_HOURS_MIN |
Int | Мінімум годин |
UF_HOURS_MAX |
Int | Максимум годин |
UF_HOURLY_RATE |
Float | Ставка години для цього типу робіт |
UF_IS_REQUIRED |
Bool | Обов'язковий блок (завжди включений) |
UF_DEPENDS_ON |
String | ID блоку-залежності (не можна обрати без нього) |
PHP-калькулятор із урахуванням залежностей
namespace MyProject\Services\Calculators;
class ProjectCostCalculator
{
private array $blocks;
private array $selectedIds;
private float $urgencyCoeff;
private float $marginPercent;
public function __construct(
array $allBlocks,
array $selectedIds,
string $urgency = 'normal',
float $marginPercent = 30
) {
$this->blocks = $allBlocks;
$this->selectedIds = $this->resolveDependencies($selectedIds, $allBlocks);
$this->urgencyCoeff = match ($urgency) {
'urgent' => 1.5,
'fast' => 1.25,
'normal' => 1.0,
'flexible' => 0.9,
default => 1.0,
};
$this->marginPercent = $marginPercent;
}
public function calculate(): array
{
$breakdown = [];
$totalHoursMin = 0;
$totalHoursMax = 0;
$totalCost = 0;
foreach ($this->selectedIds as $blockId) {
$block = $this->findBlock($blockId);
if (!$block) continue;
$hoursMin = $block['UF_HOURS_MIN'];
$hoursMax = $block['UF_HOURS_MAX'];
$rate = $block['UF_HOURLY_RATE'];
$costMin = $hoursMin * $rate * $this->urgencyCoeff;
$costMax = $hoursMax * $rate * $this->urgencyCoeff;
$totalHoursMin += $hoursMin;
$totalHoursMax += $hoursMax;
$totalCost += ($costMin + $costMax) / 2;
$breakdown[] = [
'id' => $blockId,
'name' => $block['UF_BLOCK_NAME'],
'category' => $block['UF_CATEGORY'],
'hours' => "{$hoursMin}–{$hoursMax}",
'cost_min' => round($costMin),
'cost_max' => round($costMax),
];
}
// Додаємо маржу
$margin = $totalCost * ($this->marginPercent / 100);
$finalCost = $totalCost + $margin;
return [
'breakdown' => $breakdown,
'hours_min' => $totalHoursMin,
'hours_max' => $totalHoursMax,
'cost_min' => round($finalCost * 0.85),
'cost_max' => round($finalCost * 1.2),
'cost_avg' => round($finalCost),
'urgency_coeff' => $this->urgencyCoeff,
'weeks_min' => ceil($totalHoursMin / 40),
'weeks_max' => ceil($totalHoursMax / 40),
];
}
private function resolveDependencies(array $selectedIds, array $blocks): array
{
$resolved = $selectedIds;
foreach ($blocks as $block) {
if (in_array($block['ID'], $selectedIds, true) && !empty($block['UF_DEPENDS_ON'])) {
$depId = (int)$block['UF_DEPENDS_ON'];
if (!in_array($depId, $resolved, true)) {
$resolved[] = $depId;
}
}
// Обов'язкові блоки завжди включені
if ($block['UF_IS_REQUIRED'] && !in_array($block['ID'], $resolved, true)) {
$resolved[] = $block['ID'];
}
}
return array_unique($resolved);
}
}
UX: прапорці з підказками
Інтерфейс калькулятора — набір груп із прапорцями. Кожен прапорець супроводжується коротким описом: клієнт розуміє, що входить до блоку.
// Оновлення підсумку при кожній зміні
document.querySelectorAll('.block-checkbox').forEach(cb => {
cb.addEventListener('change', async () => {
const selected = [...document.querySelectorAll('.block-checkbox:checked')]
.map(el => parseInt(el.value));
const urgency = document.querySelector('[name="urgency"]:checked').value;
const resp = await fetch('/ajax/calculator/project/', {
method: 'POST',
body: new URLSearchParams({
selected: JSON.stringify(selected),
urgency,
sessid: BX.bitrix_sessid(),
}),
});
const data = await resp.json();
updateResultPanel(data);
});
});
Передача брифу до CRM
Результат розрахунку формує структурований бриф:
// Створення угоди в Bitrix24 або ліда в CRM сайту
$comments = "РОЗРАХУНОК ВАРТОСТІ ПРОЄКТУ\n\n";
$comments .= "Обрані блоки:\n";
foreach ($calcResult['breakdown'] as $item) {
$comments .= "— {$item['category']}: {$item['name']} ({$item['hours']} год.)\n";
}
$comments .= "\nПідсумок: {$calcResult['cost_min']} – {$calcResult['cost_max']}\n";
$comments .= "Термін: {$calcResult['weeks_min']} – {$calcResult['weeks_max']} тижнів\n";
$comments .= "Терміновість: {$urgency}\n";
Терміни розробки
| Завдання | Термін |
|---|---|
| Базовий калькулятор (10–15 блоків, проста сума, форма заявки) | 5–8 днів |
| Калькулятор із категоріями, залежностями, коефіцієнтами, передачею до CRM | 2–3 тижні |
| Калькулятор із PDF-брифом, історією розрахунків, A/B-тестами | 4–6 тижнів |
Ключове правило: калькулятор вартості проєкту не повинен давати ціну нижчу за реальну. Краще закласти запас 20–30% зверху та пояснити це «попередньою оцінкою», ніж отримати клієнта із завищеними очікуваннями.







