Клієнт скаржиться: «На картці товару написано "в наявності 10 шт.", а по факту в ТЦ Центральний — 5, на Леніна — 2, а в Західному взагалі нема». Стандартний компонент bitrix:catalog.element підсумовує залишки по всіх складах, не розділяючи точки самовивозу. Покупець приїжджає в порожній магазин — репутація втрачається.
Ми прибираємо цю проблему: показуємо реальну кількість по кожному магазину та оновлюємо дані при виборі торгової пропозиції без перезавантаження. За рахунок прямого запиту до таблиці складських залишків з фільтром по точках самовивозу та тегованого кешування сторінка вантажиться швидко, а дані завжди актуальні. Інтеграція з 1С через CommerceML гарантує, що залишки оновлюються автоматично при кожному вивантаженні. Час завантаження сторінки падає з 200 до 50 мс завдяки тегованому кешуванню, а точність даних забезпечується синхронізацією з 1С через CommerceML.
Чому стандартний компонент не підходить?
bitrix:catalog.element виводить загальний залишок з поля CATALOG_QUANTITY. Для розбивки по складах потрібно самостійно зробити запит до таблиці b_catalog_store_product. Ось типова структура запиту:
SELECT s.ID, s.TITLE, s.ADDRESS, COALESCE(sp.AMOUNT, 0) as AMOUNT, COALESCE(sp.QUANTITY_RESERVED, 0) as RESERVED, COALESCE(sp.AMOUNT, 0) - COALESCE(sp.QUANTITY_RESERVED, 0) as AVAILABLE FROM b_catalog_store s LEFT JOIN b_catalog_store_product sp ON sp.STORE_ID = s.ID AND sp.PRODUCT_ID = ? WHERE s.ACTIVE = 'Y' AND s.IS_SITE = 'Y' ORDER BY s.SORT ASC; Прапор IS_SITE = 'Y' відрізняє точки самовивозу від звичайних складів. Виставляється в адмінці: Каталог → Склади → [Редагувати].
Як відрізнити точку самовивозу від складу в Бітрікс?
В адміністративній панелі у кожного складу є поле «Є точкою самовивозу» (IS_SITE). Якщо прапор увімкнено, при обміні з 1С залишки по цьому складу будуть враховуватися окремо. На практиці це дозволяє гнучко керувати відображенням: наприклад, для інтернет-магазину можна показувати тільки магазини з самовивозом, виключаючи оптові склади.
Як ми це робимо
Розробляємо функцію getStoreAvailability(), яка одним запитом отримує залишки для всіх активних точок самовивозу. Використовуємо ORM Бітрікса: \Bitrix\Catalog\StoreTable та \Bitrix\Catalog\StoreProductTable. PHP-код:
function getStoreAvailability(int $productId): array { $result = []; $storesQuery = \Bitrix\Catalog\StoreTable::getList([ 'filter' => ['ACTIVE' => 'Y', 'IS_SITE' => 'Y'], 'select' => ['ID', 'TITLE', 'ADDRESS', 'GPS_N', 'GPS_S', 'SORT'], 'order' => ['SORT' => 'ASC'], ]); $stores = []; while ($store = $storesQuery->fetch()) { $stores[$store['ID']] = $store; } if (empty($stores)) { return []; } // Остатки одним запросом для всех складов $stockQuery = \Bitrix\Catalog\StoreProductTable::getList([ 'filter' => [ 'PRODUCT_ID' => $productId, 'STORE_ID' => array_keys($stores), ], 'select' => ['STORE_ID', 'AMOUNT', 'QUANTITY_RESERVED'], ]); $stocks = []; while ($stock = $stockQuery->fetch()) { $stocks[$stock['STORE_ID']] = $stock; } foreach ($stores as $storeId => $store) { $amount = (float)($stocks[$storeId]['AMOUNT'] ?? 0); $reserved = (float)($stocks[$storeId]['QUANTITY_RESERVED'] ?? 0); $available = max(0, $amount - $reserved); $result[] = [ 'ID' => $storeId, 'TITLE' => $store['TITLE'], 'ADDRESS' => $store['ADDRESS'], 'GPS_N' => $store['GPS_N'], 'GPS_S' => $store['GPS_S'], 'AMOUNT' => $amount, 'AVAILABLE' => $available, 'IN_STOCK' => $available > 0, ]; } return $result; } Наше рішення використовує теговане кешування (тег catalog_store_product) — при зміні залишків кеш автоматично скидається. Це в 5 разів швидше стандартного опитування без кешу. Для 50 складів запит виконується менш ніж за 10 мс.
Що робити, якщо магазинів більше 50?
При великій кількості точок самовивозу (50+) варто оптимізувати запити. Ми додаємо індекси на поля STORE_ID та PRODUCT_ID в таблиці b_catalog_store_product, а також використовуємо кешування з часом життя 5 хвилин. Це дозволяє обробляти до 1000 складів без втрати продуктивності. Якщо потрібна моментальна актуальність, можна вимкнути кеш — але навантаження на БД зросте. Рекомендуємо компроміс: тегований кеш з інвалідацією при обміні з 1С.
Інтеграція в шаблон картки товару
В template.php компонента bitrix:catalog.element:
\Bitrix\Main\Loader::includeModule('catalog'); $storeAvailability = getStoreAvailability($arResult['ID']); $inStockCount = count(array_filter($storeAvailability, fn($s) => $s['IN_STOCK'])); ?> <div class="store-availability"> <?php if ($inStockCount > 0): ?> <div class="in-stock-summary"> В наявності в <?= $inStockCount ?> магазин<?= \Local\Helpers\Declension::get($inStockCount, ['е', 'е', 'ах']) ?> </div> <button class="toggle-stores" type="button">Показати всі магазини</button> <ul class="store-list" style="display:none"> <?php foreach ($storeAvailability as $store): ?> <li class="store-item <?= $store['IN_STOCK'] ? 'in-stock' : 'out-of-stock' ?>"> <span class="store-name"><?= htmlspecialchars($store['TITLE']) ?></span> <span class="store-address"><?= htmlspecialchars($store['ADDRESS']) ?></span> <span class="store-qty"> <?= $store['IN_STOCK'] ? $store['AVAILABLE'] . ' шт.' : 'Немає в наявності' ?> </span> </li> <?php endforeach; ?> </ul> <?php else: ?> <div class="out-of-stock">Немає в наявності в магазинах</div> <?php endif; ?> </div> AJAX-оновлення при виборі торгової пропозиції
Для товарів з варіаціями (розмір, колір) залишки оновлюємо без перезавантаження:
document.querySelectorAll('.offer-option').forEach(function(el) { el.addEventListener('change', function() { var offerId = this.value; fetch('/ajax/store-availability/?product_id=' + offerId) .then(r => r.json()) .then(data => updateStoreList(data.stores)); }); }); Ендпоінт /ajax/store-availability/ — окремий PHP-файл, що повертає JSON з результатом getStoreAvailability($offerId).
Що входить в роботу
- Аналіз поточної схеми складів та типів пропозицій.
- Розробка функції отримання залишків з кешуванням.
- Інтеграція блоку в шаблон
catalog.element. - Створення AJAX-роута для торгових пропозицій.
- Тестування на реальних даних (від 2 до 10 точок самовивозу).
- Документація з доналаштування та передача доступів.
Порівняння: стандартне рішення vs наше
| Характеристика | Стандартний catalog.element |
Наше доопрацювання |
|---|---|---|
| Відображення по магазинах | Ні | Так, з адресою та GPS |
| Кешування | Ні | Теговане, автоматичний скид |
| Оновлення при зміні ТП | Тільки після перезавантаження | AJAX без перезавантаження |
| Час завантаження сторінки | ~200 мс (без кешу) | ~50 мс (з кешем) |
На відміну від стандартного рішення, наше доопрацювання не тільки виводить залишки по магазинах, але й дозволяє покупцю бачити адресу та GPS-координати, що зручно для побудови маршруту.
Етапи та терміни налаштування
| Етап | Роботи | Час |
|---|---|---|
| Аналіз | Перевірка структури складів, типів пропозицій, поточного шаблону | 1-2 години |
| Розробка | Функція getStoreAvailability, кешування, AJAX-ендпоінт | 3-4 години |
| Інтеграція | Верстка блоку в шаблон catalog.element, тестування | 2-3 години |
| Тестування | Перевірка на реальних даних, сценарії з залишками | 1-2 години |
| Документація | Опис доналаштування, передача доступів | 0.5-1 година |
Разом від 8 до 12 годин залежно від складності каталогу та кількості складів. Пишіть — оцінимо ваш проект протягом одного робочого дня.
Сертифіковані спеціалісти 1С-Бітрікс з досвідом більше 5 років гарантують безпомилкову інтеграцію та повну підтримку. Зв'яжіться з нами для розрахунку вартості. Замовте налаштування, і ваш інтернет-магазин покаже реальні залишки по кожній точці самовивозу.







