Налаштування триггера поступлення товару на склад 1С-Bitrix
Товар закінчується, користувач натискає «Повідомити про поступлення» і... нічого. Лист ніколи не приходить, тому що ніхто не налаштував зв'язок між подією поповнення складу та списком очікування. Це частий кейс: форма підписки є, склад поповнюється, але автоматика не запущена.
Де зберігаються залишки та як вони оновлюються
В Bitrix залишки товарів живуть у двох місцях залежно від конфігурації:
Простий каталог (без складського обліку): поле CATALOG_QUANTITY у b_catalog_product. Оновлюється напрямко через CCatalogProduct::Update() або через обмін з 1С.
Багатоскладський облік (модуль catalog + склади): таблиця b_catalog_store_product з полями PRODUCT_ID, STORE_ID, AMOUNT. Загальний залишок агрегується. При обміні 1С через модуль sale.crm.lead або через стандартний обмін дані пишуться в b_catalog_store_product.
Подія зміни залишку — OnProductUpdate у модулі catalog. Вона спрацьовує при будь-якій зміні записи в b_catalog_product, включаючи кількість:
AddEventHandler('catalog', 'OnProductUpdate', function($id, $fields) {
if (isset($fields['QUANTITY']) && $fields['QUANTITY'] > 0) {
// Товар поступив на склад — була нульова позиція
checkAndNotifyWaitlist($id);
}
});
Проблема: OnProductUpdate спрацьовує при будь-якій зміні продукту, не тільки при поповненні складу. Щоб відфільтрувати саме подію «з'явився з нуля», потрібно порівняти попереднє значення. До PHP-события дані ще в БД, тому читаємо старе значення в OnBeforeProductUpdate:
AddEventHandler('catalog', 'OnBeforeProductUpdate', function($id, &$fields) {
$old = \Bitrix\Catalog\ProductTable::getByPrimary($id, ['select' => ['QUANTITY']])->fetch();
$fields['_OLD_QUANTITY'] = (float)($old['QUANTITY'] ?? 0);
});
Зберігання підписок на поступлення
Модуль catalog не має вбудованого механізму «повідомити про поступлення». Потрібна власна таблиця:
CREATE TABLE bl_stock_notify (
id SERIAL PRIMARY KEY,
product_id INT NOT NULL,
user_id INT,
email VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
notified_at TIMESTAMP,
UNIQUE (product_id, email)
);
Форма на сайті пише в цю таблицю. Унікальний ключ (product_id, email) захищає від дублів при повторних підписках.
Обробник поповнення
function checkAndNotifyWaitlist(int $productId): void
{
$connection = \Bitrix\Main\Application::getConnection();
$waitlist = $connection->query(
"SELECT * FROM bl_stock_notify WHERE product_id = {$productId} AND notified_at IS NULL"
)->fetchAll();
if (empty($waitlist)) {
return;
}
$product = \CIBlockElement::GetByID($productId)->GetNextElement();
$name = $product->GetField('NAME');
$url = $product->GetField('DETAIL_PAGE_URL');
foreach ($waitlist as $row) {
\Bitrix\Main\Mail\Event::send([
'EVENT_NAME' => 'STOCK_ARRIVED',
'LID' => SITE_ID,
'C_FIELDS' => [
'EMAIL' => $row['email'],
'PRODUCT_NAME' => $name,
'PRODUCT_URL' => 'https://' . $_SERVER['SERVER_NAME'] . $url,
],
]);
$connection->queryExecute(
"UPDATE bl_stock_notify SET notified_at = NOW() WHERE id = {$row['id']}"
);
}
}
Інтеграція з багатоскладським обліком
При багатоскладському обліку подія OnProductUpdate не спрацьовує при зміні b_catalog_store_product. Для складських операцій потрібно підписатися на события модулю catalog глибшого рівня — або використовувати хук після запису документа складського обліку через \Bitrix\Catalog\Document\DocumentTable.
Альтернативний підхід: агент, який кожні 5 хвилин перевіряє b_catalog_store_product на появу ненульових залишків за товарами з листа очікування. Менш елегантно, але працює стабільніше при нестандартних схемах оновлення залишків (наприклад, при прямому UPDATE через 1С-коннектор).
Що ми налаштовуємо
- Обробники
OnBeforeProductUpdateтаOnProductUpdateз перевіркою переходу «0 → N» - Таблицю
bl_stock_notifyта форму підписки на сайті - Шаблон листа
STOCK_ARRIVEDв адміністративному розділі поштових подій - Для багатоскладської конфігурації — агент або обробник документів складу
- Логіку часткового поступлення: якщо прийшло 2 одиниці, а підписалось 10 — повідомити всіх або перших двох?







