Development of a service cost calculator on 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Development of a Service Cost Calculator on 1C-Bitrix

A service cost calculator is a qualification tool: it answers the question "how much does this cost" at the moment when a potential client is not yet ready to call, but is already ready to make a decision. A well-built calculator does not promise an exact price — it gives a range sufficient for the client to understand whether it fits their budget.

Specifics of service cost calculation

Services are more complex than goods: they have no fixed price. The cost depends on volume, complexity, deadlines, contractor qualifications, region, and seasonality. The calculator must account for these variables without turning into an endless questionnaire.

Typical parameters for a service calculator:

  • Volume of work — area, number of units, number of hours
  • Type/category — basic, standard, premium
  • Additional options — urgency, specialist on-site visit, materials
  • Geography — region, distance

Each parameter affects the total sum through a coefficient or a fixed surcharge.

Data model: rates in a HighLoad block

The rate table for a service calculator is stored in a HighLoad block — this is more performant than an info block and more convenient than hard-coded arrays:

// Fetching rates from an HL block
$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 table structure:

Field Type Purpose
UF_SERVICE_TYPE Reference Service type
UF_VOLUME_FROM Float Minimum volume
UF_VOLUME_TO Float Maximum volume
UF_BASE_PRICE Float Base cost
UF_PRICE_PER_UNIT Float Cost per unit above the base
UF_COMPLEXITY_COEFFICIENT Float Complexity coefficient

Calculation logic in PHP

A service class encapsulating the calculation algorithm:

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("Tariff not found for volume {$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'];
        }

        // Apply coefficients of additional options
        $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% — lower bound
            'total_max'    => round($total * 1.15, 2),  // +15% — upper bound
            '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;
    }
}

Displaying a price range

A fixed price for services is often impossible. The calculator shows a range:

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 =
        'Exact cost is determined after an on-site inspection';
}

CRM integration: passing the calculation to a deal

After the user submits a request, the calculation data is added to a deal or CRM lead:

// Custom lead fields to store calculation parameters
$lead->Add([
    'TITLE'       => 'Calculation: ' . $serviceTypeName,
    'OPPORTUNITY' => $calculationResult['total'],
    'CURRENCY_ID' => 'RUB',
    'COMMENTS'    => $this->buildCommentsFromParams($params, $calculationResult),
    'UF_CALC_PARAMS' => json_encode($params), // JSON of parameters
    'UF_CALC_RESULT' => json_encode($calculationResult),
]);

Timelines

Task Timeline
Calculator with 5–7 parameters, linear calculation, request form 5–8 days
Calculator with a rate grid from an HL block, price range, CRM integration 2–3 weeks
Multi-service calculator with service selection, complex coefficients, and calculation history 4–6 weeks

A good service cost calculator is not a price promise — it is a budget qualification tool. The client understands the ballpark figure and makes a decision about the next step. The task is to make that step as easy as possible.