Резервы товаров в Битрикс первыми дают сбой, когда интернет-магазин работает на общем складе с розницей или опт-отделом через 1С. Пока обмен идет батчами раз в 15-20 минут, менеджер в 1С видит одно количество, покупатель на сайте в это же время оформляет заказ на тот же остаток, и товар продан дважды. Разбираю, как резервирование устроено внутри Битрикс, где на практике рвется синхронизация с 1С УТ и как настроить выгрузку резервов, чтобы остатки на сайте и в учетной системе не расходились.
Как Битрикс резервирует товар на складе
Битрикс резервирует товар на уровне модуля «Каталог» со включенным количественным учетом. Как только опция активна, для каждой позиции на складе появляется поле QUANTITY_RESERVED в таблице b_catalog_store_product, отдельное от физического остатка QUANTITY. Товар при этом никуда не списывается, просто помечается занятым под конкретный заказ.
Момент, когда происходит резерв, задается не в каталоге, а в статусах заказов. В разделе «Магазин» -> «Настройки» -> «Статусы заказов» у каждого статуса можно включить флаги «Резервировать», «Разрезервировать» и «Списывать». Обычно резерв ставлю на статусе «Принят» или «Оплачен», а списание, то есть фактическое уменьшение остатка, происходит на статусе «Выполнен» или «Отгружен».
Отдельно есть мягкий резерв корзины: если включена опция резервирования на время оформления заказа, товар временно занимается уже в момент добавления в корзину, а не после подтверждения заказа. Время жизни такого резерва обычно ставлю на 20-30 минут: меньше не успевают оплатить картой через Т‑Банк или другой эквайринг, больше остаток зря простаивает на популярных позициях.
Если складов несколько, распределение резерва идет по приоритету, заданному в модуле «Склады»: система сначала пытается закрыть заказ с самого приоритетного склада, и только при нехватке переходит к следующему. Для интеграции с 1С этот момент критичен: если 1С ждет резерв в разрезе одного склада, а Битрикс раскидал заказ по трем, на стороне учетной системы возникает путаница, которую программисты 1С обычно списывают на ошибку сайта.
Где резерв повисает на практике
По опыту нескольких интеграций проблемы почти всегда одни и те же.
- Заказ отменили в обход стандартного API, прямым запросом в базу или через самописный скрипт без вызова методов OrderManager. Резерв в этом случае не снимается и висит на остатке, пока кто-то вручную не пересчитает склад.
- В статусах настроили резервирование, но забыли настроить возврат остатка при отмене или отказе. Частая ошибка на этапе первичной настройки магазина, которую находят только когда остатки на витрине начинают расходиться с реальными.
- Обмен с 1С идет батчами раз в 15-30 минут, и в моменты пиковой нагрузки, распродажи или запуска лимитированной коллекции, два-три заказа успевают уйти на один и тот же остаток.
- Резерв путается между складами, когда позиции одного заказа лежат на разных складах, а на стороне 1С резерв привязан к одному регистру.
На одном проекте с общим складом розницы и сайта при потоке от 300 заказов в день такой овербукинг случался 2-3 раза в неделю. Для одежды с ограниченными размерами каждый такой случай оборачивался отменой заказа и недовольным клиентом, а менеджеры тратили время на разбор, кому в итоге достанется последняя пара.
Настройка резервирования перед выгрузкой в 1С
Прежде чем городить обмен резервами, стоит проверить базовую настройку самого Битрикс. Обычно прохожу по такому списку:
- включен количественный учет в каталоге, иначе резерв технически невозможен;
- включено резервирование в настройках магазина, задано время жизни резерва в корзине;
- в каждом статусе заказа явно прописано, когда резервировать, когда списывать, когда возвращать остаток;
- настроен приоритет складов и понятно, что делает система при нехватке товара на приоритетном складе;
- включено протоколирование ошибок обмена в технических настройках модуля обмена с 1С.
Без последнего пункта расхождения между сайтом и 1С придется искать вслепую, а на живом магазине это недели переписки между разработчиком сайта и программистом 1С с взаимными обвинениями.
Бесплатный материал
🎁 Полезный скрипт в подарок
Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.
Без спама. Отписка в 1 клик.
Что 1С должна знать о резерве сайта
Резерв в связке Битрикс и 1С УТ работает на двух уровнях, и их полезно разделять.
Первый, мягкий резерв корзины, существует только внутри Битрикс, пока покупатель заполняет форму заказа. 1С про него знать не обязана: заказ еще не подтвержден, и если человек закрыл вкладку, резерв снимется сам через 20-30 минут.
Второй уровень начинается, когда заказ подтвержден и передается по обмену CommerceML в 1С. Там на основании данных заказа создается документ «Заказ клиента», и при его проведении 1С резервирует товар на своей стороне. Именно этот резерв важен, если склад общий с розницей или опт-отделом: пока документ не долетел и не проведен, продавец в торговом зале или менеджер по опту физически может продать тот же товар.
Проблема почти всегда в задержке. Стандартный обмен работает по расписанию, обычно раз в 15-30 минут, и это окно между оформлением заказа на сайте и появлением резерва в 1С на потоке заказов и общем складе становится источником овербукинга.
Быстрая синхронизация резервов через REST и HTTP-сервис 1С
Вместо того чтобы ждать очередного тика расписания, можно отправлять резерв в 1С сразу при сохранении заказа через событие Битрикс REST и HTTP-сервис на стороне 1С.
AddEventHandler("sale", "OnSaleOrderSaved", "PushReserveTo1C");
function PushReserveTo1C($order)
{
if (!$order->isNew()) {
return;
}
$items = [];
foreach ($order->getBasket() as $basketItem) {
$items[] = [
'PRODUCT_ID' => $basketItem->getProductId(),
'QUANTITY' => $basketItem->getQuantity(),
'STORE_ID' => $basketItem->getField('RESERVE_ID'),
];
}
$payload = json_encode([
'ORDER_ID' => $order->getId(),
'ITEMS' => $items,
]);
$ch = curl_init('https://1c.example.ru/ut/hs/reserve/push');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
]);
curl_exec($ch);
curl_close($ch);
}
На стороне 1С публикуется HTTP-сервис, который принимает такой пакет и пишет данные в регистр сведений «Резервы сайта», после чего пересчитывает доступный остаток для продажи в рознице. Таймаут в примере намеренно короткий: если 1С недоступна, запись о резерве уходит в очередь и повторяется штатным агентом обмена, чтобы резерв не потерялся при сетевом сбое.
Какой способ синхронизации выбрать
| Способ | Задержка | Сложность внедрения | Когда достаточно |
|---|---|---|---|
| Типовой обмен CommerceML по расписанию | 15-30 минут | низкая, все из коробки | склады сайта и розницы разделены физически |
| REST-событие и HTTP-сервис 1С | 1-5 секунд | средняя, код с обеих сторон | общий склад с розницей, распродажи, лимитированные позиции |
| Оркестрация через n8n между Bitrix REST и HTTP-сервисом 1С | 1-10 секунд | средняя, но проще поддерживать без правки продакшен-кода | нужны алерты, ретраи и логирование сверх голой передачи данных |
Для разовой передачи резерва хватает обработчика события на PHP, такую доработку с обеих сторон обычно оцениваю от 20 000 ₽. Если нужны повторные попытки при сбоях, уведомления менеджерам и понятный лог без погружения в код при каждом изменении логики, собираю цепочку в n8n, это отдельная работа от 25 000 ₽. Если требуется полноценная интеграция под ключ с учетом версии 1С УТ и структуры складов конкретного клиента, обычно беру разработку интеграции между Битрикс и 1С отдельным проектом, потому что итоговая логика в каждом случае своя.
Как проверять, что резервы не разошлись
После запуска синхронизации первые пару недель держу отдельный агент сверки: раз в час скрипт берет QUANTITY_RESERVED по каждому SKU из Битрикс, запрашивает те же цифры через GET у HTTP-сервиса 1С и сравнивает. Расхождения пишутся в лог, а при разнице больше 5 позиций уходит уведомление в Telegram через бота на aiogram, который дергает оба API и присылает список артикулов с расхождением прямо в рабочий чат.
Когда расхождений не появляется 2-3 недели подряд, частоту сверки снижаю до нескольких раз в сутки, это уже контроль на случай сбоя обмена, а не поиск ошибок в логике.
Интернет-магазин под ключ
Интернет-магазин
от 80 000 ₽
Подробнее →Частые вопросы
Что делать, если резерв в Битрикс завис и не снимается после отмены заказа?
Обычно причина в отмене заказа в обход стандартного API: прямой SQL-запрос или самописный скрипт без вызова методов OrderManager. Лечится агентом, который раз в сутки сверяет заказы в статусе «отменен» или «отказ» с ненулевым резервом и принудительно возвращает остаток через CCatalogStoreProduct::UpdateReserve. Дальше нужно найти место в коде, где отмена идет мимо стандартной логики заказов, и переписать через штатный API.
Нужно ли резервировать товар в 1С, если у сайта отдельный склад от розницы?
Если склады физически не пересекаются, гнаться за секундной синхронизацией не имеет смысла: обычного обмена раз в 15-30 минут достаточно, потому что один и тот же остаток не может продаться дважды на разных складах.
Как часто должен идти обмен резервами между Битрикс и 1С?
Зависит от общего склада и трафика. При раздельных складах хватает штатного расписания обмена. При общем складе с розницей и потоке от 50 заказов в день в час пик критичные позиции, лимитированные или с низким остатком, я перевожу на событийную синхронизацию через REST, а остальной каталог оставляю на батч.
Можно ли резервировать товар не в 1С УТ, а в 1С Розница?
Логика та же, меняется структура HTTP-сервиса и имя регистра на стороне 1С. В Рознице резерв обычно завязан на документ «Резервирование товаров», в УТ на «Заказ клиента». Схема с событием OnSaleOrderSaved и вызовом HTTP-сервиса из Битрикс от этого не меняется.