Development of a calculator with dynamic price loading for 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
    1173
  • 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
    745
  • 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

Developing a Calculator with Dynamic Price Loading in 1C-Bitrix

A calculator with dynamic price loading differs from a static one in that its prices are fetched from the Bitrix catalogue in real time, not hardcoded in JavaScript. This means: if the price of steel changes, the metal structures calculator immediately uses the new prices — without any code changes. This is exactly where most implementations fail: either prices are cached too aggressively (stale data for hours), or an AJAX request is made to the database on every slider movement (unnecessary load).

Where to Get Prices: Catalogue API

Prices in Bitrix are stored in the b_catalog_price table. Each product can have multiple prices (retail, wholesale, special) — the price type is determined by CATALOG_GROUP_ID. To load prices into a calculator, the API is used:

// Fetch prices for a set of products
$prices = \Bitrix\Catalog\PriceTable::getList([
    'filter' => [
        'PRODUCT_ID' => $productIds,
        'CATALOG_GROUP_ID' => 1, // retail price
    ],
    'select' => ['PRODUCT_ID', 'PRICE', 'CURRENCY'],
])->fetchAll();

For a calculator that works with trade offers (SKUs), bear in mind that the price is stored at the trade offer level (b_catalog_price.PRODUCT_ID = trade offer ID), not at the parent product level.

Dynamic Loading Architecture

The correct approach for a calculator with live prices:

  1. Initialisation. On page load — fetch the initial prices for all required items. Not via AJAX — but PHP rendering into data- attributes or a JSON object in <script>. The first render is fast, with no extra requests.

  2. In-browser recalculation. The user changes parameters — JavaScript recalculates the cost using the already-loaded prices. No network request.

  3. Price refresh on trigger. Optional: if prices may change during a session (exchange-traded goods, currency-based prices), a periodic AJAX request to refresh prices is added — once every 5–10 minutes, not on every interaction.

// Initialise prices from PHP
const calcPrices = <?= json_encode($pricesData) ?>;

// Recalculate when parameters change (no AJAX)
function recalculate() {
    const materialId = document.getElementById('material').value;
    const quantity = parseFloat(document.getElementById('quantity').value);
    const pricePerUnit = calcPrices[materialId]?.price ?? 0;

    document.getElementById('total').textContent =
        formatPrice(pricePerUnit * quantity);
}

Prices with Discounts and User Groups

For authenticated users in the "Wholesale" group, the price must be fetched from the corresponding price type (CATALOG_GROUP_ID = 2). When the calculator initialises, the server-side determines the user's group and returns the appropriate set of prices.

The cumulative discount and cart rule mechanisms are not applied here — the calculator works with list prices. If prices including discounts are needed, they must be calculated via CCatalogProduct::GetOptimalPrice, which is significantly slower and requires caching.

Price Caching

Prices from the catalogue are cached on the server with Bitrix tagged cache:

$cache = \Bitrix\Main\Data\Cache::createInstance();
$cacheKey = 'calc_prices_' . md5(serialize($productIds));

if ($cache->initCache(3600, $cacheKey, '/calc/prices/')) {
    $prices = $cache->getVars();
} elseif ($cache->startDataCache()) {
    $prices = fetchPricesFromDB($productIds);
    $cache->endDataCache($prices);
    // invalidation tag — triggered when a catalogue price is updated
    \Bitrix\Main\Data\TaggedCache::clearByTag('catalog_price_' . $productId);
}

A TTL of 3600 seconds (1 hour) is a sensible balance for most catalogues. For exchange-traded goods — 60–300 seconds.

Case Study: Metal Products Calculator with Live Prices

Client — a metal trading company. Catalogue: 3,000 items, prices updated daily via an export from 1C. Calculator: the user selects the product type (angle bar, channel bar, pipe), steel grade, and length — and receives the price per tonne and the total cost.

Problem with the original implementation: prices were hardcoded in a JSON file updated manually when the price list changed. There were situations where the calculator was showing week-old prices.

New implementation: prices are fetched from b_catalog_price on the first page render (PHP → JSON in <script>). The tagged cache is invalidated by a Bitrix agent 30 minutes after the 1C import completes. Users always see current prices with a delay of no more than 30 minutes after the price list is updated — acceptable for this business.

Development Timeline

  • Calculator with catalogue price loading, without personalisation — 3–6 days
    • Group prices (wholesale, dealers) — +1–2 days
    • Dynamic in-session price refresh — +1 day
    • Stock integration (warehouse availability) — +2–3 days