Низкие остатки - пороги, отчёт закупщику, поведение витрины
Настраиваем контроль кончающегося товара: пороги остатка, отчёт закупщику, поведение витрины при нуле и проверку после каждого обмена с учётной системой.
Что нужно знать заранее
Единый порог для всего каталога работает плохо. Для расходников пять штук - это почти ноль, а для дорогой техники пять штук на складе означают спокойный запас на месяц вперёд.
Поэтому порог делают двухуровневым. Общее значение задаётся настройкой проекта, а у отдельных позиций и категорий появляется собственный порог в свойстве товара.
Поведение витрины при нулевом остатке - решение бизнеса, а не разработчика. Товар можно скрыть, оставить с пометкой об отсутствии или продавать под заказ с увеличенным сроком доставки.
Шаги
- Договориться с заказчиком об общем пороге и о позициях с особыми условиями.
- Завести свойство товара под индивидуальный порог и заполнить его для этих позиций.
- Собирать список позиций ниже порога заданием по расписанию после обмена.
- Отправлять отчёт закупщику файлом или сообщением с прямыми ссылками на товары.
- Настроить поведение витрины при нуле и проверить его глазами покупателя.
Решение
Собираем товары ниже общего порога:
\Bitrix\Main\Loader::includeModule('catalog');$threshold = (int)\Bitrix\Main\Config\Option::get('vendor.shop', 'low_stock', 5);$rs = \CIBlockElement::GetList(['CATALOG_QUANTITY' => 'ASC'], ['IBLOCK_ID' => $iblockId, 'ACTIVE' => 'Y', '<=CATALOG_QUANTITY' => $threshold], false, ['nTopCount' => 500], ['ID', 'NAME', 'CATALOG_QUANTITY', 'PROPERTY_MIN_STOCK']);Выборка сразу забирает и остаток, и индивидуальный порог позиции. Один запрос вместо двух заметно экономит время на каталоге в десятки тысяч товаров с торговыми предложениями.
Учитываем индивидуальный порог позиции:
$low = [];while ($row = $rs->Fetch()) { $own = (int)($row['PROPERTY_MIN_STOCK_VALUE'] ?? 0); $limit = $own > 0 ? $own : $threshold; // своё значение важнее общего if ((float)$row['CATALOG_QUANTITY'] <= $limit) { $low[] = $row; }}printf("позиций ниже порога: %d\n", count($low));Отправляем отчёт закупщику:
$lines = array_map(static fn($r) => sprintf('%s - остаток %s (ID %d)', $r['NAME'], $r['CATALOG_QUANTITY'], $r['ID']), array_slice($low, 0, 30));\CEvent::Send('VENDOR_LOW_STOCK', SITE_ID, ['EMAIL' => 'zakupki@example.com', 'LIST' => implode("\n", $lines), 'TOTAL' => count($low)]);// в письмо кладут первые тридцать строк, полный список прикладывают файломОтчёт полезен только со ссылками на карточки товаров. Список названий заставляет закупщика искать позиции руками, и через неделю такой отчёт перестают открывать вовсе.
Настраиваем поведение витрины при нуле:
\CCatalogProduct::Update($productId, [ 'QUANTITY_TRACE' => 'Y', // остаток списывается при заказе 'CAN_BUY_ZERO' => 'N', // продавать при нуле нельзя 'SUBSCRIBE' => 'Y', // покупателю предлагают подписку на поступление]);Проверяем остатки после обмена:
\Bitrix\Main\EventManager::getInstance()->addEventHandler('catalog', 'OnSuccessCatalogImport1C', [LowStock::class, 'check']);// обмен меняет остатки пачками, и проверку логично вешать на его завершение// событие срабатывает по окончании каждого файла выгрузки, а не раз за сеансТипичные проблемы
Отчёт по остаткам приходит с сотнями позиций.
Порог задан одним числом для всего каталога без учёта оборачиваемости позиций. Для расходников и для дорогой техники пороги задают отдельными значениями.
Покупатели заказывают товар, которого нет на складе.
У товара выключено списание остатка либо разрешена покупка при нуле. Поведение при нулевом остатке настраивают осознанно и проверяют на витрине.
Отчёт приходит до обмена и показывает вчерашние числа.
Проверка висит на расписании и не связана с завершением обмена с учётной системой. Её вешают на событие окончания обмена, а не на фиксированное время.
Закупщик перестал открывать письмо об остатках.
В письме одни названия без ссылок и без указания, что именно изменилось. В отчёт добавляют ссылки на карточки и отмечают позиции, ушедшие в ноль впервые.
Товар с остатком у одного склада считается отсутствующим.
Проверка смотрит общий остаток, а витрина показывает наличие по конкретному складу. Правила подсчёта наличия держат одинаковыми в отчёте и на витрине.
Частые вопросы
Какой порог выбрать по умолчанию?
Тот, при котором закупка успевает приехать до нуля с запасом. Число зависит от срока поставки и от скорости продаж конкретной группы товаров.
Где хранить индивидуальный порог?
В свойстве товара или в свойстве раздела для целой группы позиций. Общий порог остаётся в настройках и работает для всех остальных товаров.
Скрывать товар без остатка или оставлять?
Это решение бизнеса: скрытие бережёт покупателя от разочарования, показ сохраняет позиции в поиске. Компромисс - оставить карточку с пометкой и подпиской на поступление.
Как часто присылать отчёт?
Раз в день после основного обмена и по запросу закупщика. Более частые письма превращаются в шум и перестают читаться.
Считать остаток по всем складам сразу?
Так, как считает витрина: иначе отчёт и сайт будут спорить между собой. Если наличие показывается по складу, отчёт тоже собирают по складам.
Смежное
- Склады и остатки - оглавление подтемы
- Склады и остатки: выгрузка, вывод наличия, фильтр по складу - как устроено наличие на витрине
- Остаток товара не тот: разбор причин - когда числа расходятся
- Товары под заказ: продажа при нулевом остатке и сроки - продажа при нуле
- Подписка на поступление товара: уведомление о наличии - что предложить покупателю
- Остатки из 1С: сопоставление складов и приём количества - откуда приезжают остатки
- Аудит каталога: товары без цены, картинок, дубли артикулов - соседняя регулярная проверка
- Каталог и продажи - устройство каталога целиком