Налаштування наявності товарів по магазинах 1С-Bitrix
Клієнт вибирає товар на сайті, їде в магазин — і з'ясовується, що там його немає. На складі числиться 3 одиниці, але вони в іншому філіалі. Це випадає, коли на сайті показується сумарний залишок по всіх складах замість актуальної наявності в конкретній точці.
Архітектура багатоскладського обліку
Модуль catalog підтримує склади починаючи з Bitrix 16.x. Залишки по складах зберігаються в b_catalog_store_product:
-
PRODUCT_ID— ID елемента каталога -
STORE_ID— ID складу зb_catalog_store -
AMOUNT— кількість на складу -
QUANTITY_RESERVED— зарезервовано під замовлення
b_catalog_store — це таблиця складів каталога. Вона відрізняється від b_sale_store (торгових точок для самовивозу). Зв'язок «торгова точка → склад» встановлюється через користувацьке поле або вручну — в стандартній схемі Bitrix ці дві сутності розділені.
Сумарний залишок у b_catalog_product.QUANTITY — це агрегат всіх складів. При включеному багатоскладському обліку (CCatalogStore::IsStoreProductQuantityEnable()) поле QUANTITY оновлюється автоматично при зміні b_catalog_store_product.
Прив'язка складу до торгової точки
Стандартне завдання: кожній торговій точці (b_sale_store) відповідає один або кілька складів (b_catalog_store). Створюємо користувацьке поле у b_catalog_store:
CUserTypeEntity::Add([
'ENTITY_ID' => 'CAT_STORE',
'FIELD_NAME' => 'UF_SALE_STORE_ID',
'USER_TYPE_ID' => 'integer',
'MANDATORY' => 'N',
]);
Після цього при запиті наявності по торговій точці фільтруємо b_catalog_store_product через JOIN з b_catalog_store за UF_SALE_STORE_ID.
Відображення наявності на карточці товару
Запит наявності товару по всіх пов'язаних складах:
$availability = \Bitrix\Catalog\StoreProductTable::getList([
'filter' => [
'PRODUCT_ID' => $productId,
'>AMOUNT' => 0,
],
'select' => ['STORE_ID', 'AMOUNT', 'QUANTITY_RESERVED'],
])->fetchAll();
// Отримуємо ID торгових точок через UF_SALE_STORE_ID
$storeIds = array_column($availability, 'STORE_ID');
$saleStores = \Bitrix\Catalog\StoreTable::getList([
'filter' => ['ID' => $storeIds],
'select' => ['ID', 'UF_SALE_STORE_ID'],
])->fetchAll();
Доступна кількість: AMOUNT - QUANTITY_RESERVED. Якщо результат ≤ 0 — товар зарезервований, фізично на складу є, але для продажу недоступний.
Резервування при оформленні замовлення
Коли покупець додає товар у кошик або оформляє замовлення, має створюватися резервація. Це робиться через \Bitrix\Catalog\StoreProductTable::update() з збільшенням QUANTITY_RESERVED. Стандартний механізм Bitrix робить це при зміні статусу замовлення, але не при додаванні в кошик.
Якщо потрібно резервувати вже на етапі кошика — додаємо обробник OnSaleBasketItemAdd:
AddEventHandler('sale', 'OnSaleBasketItemAdd', function(\Bitrix\Main\Event $event) {
$item = $event->getParameter('ENTITY');
// Збільшуємо QUANTITY_RESERVED на складу, прив'язаному до найближчої точки
// з урахуванням геолокації користувача або вибраного ним магазину
});
Синхронізація з 1С
Залишки по складах приходять з 1С через стандартний обмін або через REST API. При обміні через файл CommerceML/XML дані пишуться в b_catalog_store_product через CCatalogStore::UpdateProductQuantity(). При прямому REST — через метод catalog.storeproduct.update.
Важливо: при обміні 1С може присилати повний залишок (перезапис) або дельту. При дельті потрібно захиститися від негативних значень AMOUNT: додати CHECK-constraint на рівні БД або перевірку в коді перед update().
Що ми налаштовуємо
- Перевірку включення багатоскладського обліку та заповнення
b_catalog_store_product - Користувацьке поле
UF_SALE_STORE_IDуb_catalog_storeдля зв'язку зі складами каталога - Відображення наявності по торговим точкам на карточці товару
- Розрахунок доступної кількості з урахуванням
QUANTITY_RESERVED - Обробник резервування при додаванні в кошик (якщо вимагається)
- Схему синхронізації залишків з 1С з захистом від негативних значень







