Покупатель добавляет в корзину последнюю единицу товара, оплачивает — а на складе её уже нет: только что эту же позицию продали в рознице через RetailCRM. Магазин отменяет заказ, извиняется, теряет клиента и деньги на возврате. Это классический оверселлинг, и растёт он из одной причины — остатки в RetailCRM, на складах и на витрине 1С-Битрикс живут порознь и обновляются с задержкой. Настроенная синхронизация складов и остатков превращает этот хаос в предсказуемый обмен, где каждое число имеет владельца, а витрина всегда показывает то, что реально можно продать.
Ниже — практическая схема синхронизации остатков и резервов между RetailCRM и 1С-Битрикс: как выбрать источник истины, как сопоставить склады, как считать доступный остаток с учётом резервов и страхового запаса, чем обмениваться в реальном времени, а что гонять пакетно, и как построить обмен так, чтобы сбой приводил к недопродаже, а не к оверселлингу. Это выжимка из наших проектов по интеграции RetailCRM с интернет-магазином — без теории ради теории.
Коротко
- У каждого остатка должен быть ровно один владелец — учётная система (RetailCRM или 1С), а витрина Битрикса только отображает данные и создаёт резервы под заказы.
- Покупателю показывайте доступный остаток (физический минус резервы минус страховой запас), а не физический — иначе оверселлинг.
- Склады RetailCRM и Битрикса нужно явно сопоставить (маппинг) и договориться, как агрегировать остатки по зонам для витрины.
- Базовый обмен — пакетно по расписанию, критичные и дефицитные SKU — событийно через вебхуки RetailCRM, близко к реальному времени.
- Заложите режим деградации: если остатки устарели, прячьте «Купить» или переводите в предзаказ, чтобы сбой давал недопродажу, а не оверселлинг.
Зачем синхронизировать остатки RetailCRM и Битрикс
RetailCRM — это система управления заказами и клиентами, к которой в омниканальной торговле часто сходятся все каналы продаж: сайт, розница, маркетплейсы, телефонные и мессенджерные заказы. 1С-Битрикс в этой связке чаще всего играет роль витрины — интернет-магазина, который принимает онлайн-заказы. Проблема в том, что оба этих контура оперируют одними и теми же физическими товарами, лежащими на общих складах. Пока продажи идут только через один канал, рассинхрон незаметен. Как только каналов становится два и больше, любая задержка в обмене превращается в пересортицу и отменённые заказы.
Смысл синхронизации не в том, чтобы «перекачивать числа туда-сюда», а в том, чтобы построить единую, согласованную картину наличия товара. Витрина должна показывать покупателю реалистичное наличие, RetailCRM — видеть заказы с сайта и корректно резервировать под них товар, а склад — не уходить в минус из-за того, что одну единицу продали дважды. Хорошо настроенный обмен решает сразу несколько бизнес-задач.
- Меньше оверселлинга. Витрина не продаёт то, чего уже нет, потому что учитывает резервы и продажи из других каналов.
- Меньше недопродаж. Товар, который появился на складе, быстро становится доступным для покупки на сайте, а не «висит» скрытым до следующего ручного обновления.
- Корректные резервы. Заказ с сайта сразу уменьшает доступный остаток во всех каналах, а его отмена — возвращает товар в оборот.
- Единая аналитика. Руководитель видит реальную оборачиваемость и дефицит по каждому складу, а не искажённую картину из-за задержек обмена.
Важно с самого начала понимать, что синхронизация остатков — это не «фича, которую включают галочкой», а инженерная задача про согласованность распределённых данных. У вас есть несколько систем, каждая из которых меняет остаток, и между ними всегда будет задержка передачи. Вся дальнейшая работа сводится к тому, чтобы эту задержку сделать предсказуемой и безопасной. Смежные вопросы товарной синхронизации мы разбираем в статье про интеграцию магазина с RetailCRM.
Архитектура обмена: кто с кем говорит
Прежде чем настраивать что-либо в админке, нужно нарисовать схему потоков данных. В типовом проекте участников трое: складской учёт (это может быть 1С или сам склад в RetailCRM), RetailCRM как ядро обработки заказов и витрина на 1С-Битрикс. Стрелки между ними — это конкретные обмены, у каждого из которых есть направление, содержимое и частота.
Чаще всего встречаются две базовые конфигурации. В первой складской учёт ведётся в 1С: 1С отдаёт остатки в RetailCRM, RetailCRM агрегирует и отдаёт доступные остатки на витрину Битрикса, а витрина возвращает в RetailCRM заказы, которые превращаются в резервы. Во второй конфигурации склад ведётся прямо в RetailCRM (например, у небольшой розницы без полноценной 1С): тогда RetailCRM — единственный источник остатков, а Битрикс с ней обменивается напрямую. От выбранной конфигурации зависит, куда направлены стрелки и кто кому «начальник» по каждому виду данных.
Ключевой вывод из этой схемы: обмен остатками почти всегда однонаправленный «вниз» (от учёта к витрине), а обмен заказами — «вверх» (от витрины к учёту). Витрина не должна пытаться «поправить» остаток в учётной системе — она только сообщает о новых заказах, а всё остальное считает учёт. Если вы поймали себя на том, что Битрикс где-то перезаписывает остаток в RetailCRM, это почти наверняка ошибка проектирования, которая рано или поздно приведёт к затиранию правильных данных.
Единый источник истины по остаткам
Самое важное архитектурное решение принимается в самом начале и звучит просто: у каждого числа остатка есть ровно одна система-владелец. Эта система — единственная, кто имеет право изменять остаток по существу; все остальные получают его копию и не спорят с ней. В теории распределённых систем это называют «источником истины» (source of truth), и без него любая синхронизация превращается в перетягивание каната, где две системы по очереди затирают числа друг друга.
Выбор источника истины зависит от того, где реально ведётся складской учёт:
| Сценарий | Источник истины по остатку | Роль Битрикса |
|---|---|---|
| Складской учёт в 1С | 1С (через RetailCRM как ретранслятор) | Витрина: отображает, создаёт резервы |
| Склад ведётся в RetailCRM | RetailCRM | Витрина: отображает, создаёт резервы |
| Отдельная WMS / несколько складов | WMS или 1С, RetailCRM агрегирует | Витрина: показывает агрегат |
| Только сайт, без учётной системы | Битрикс (редкий случай) | И витрина, и учёт остатка |
Обратите внимание на последнюю строку: единственный случай, когда Битрикс сам владеет остатком, — это магазин вообще без внешнего учёта. Как только появляется RetailCRM или 1С, витрина отдаёт им право на остаток. Резерв — отдельная сущность: им обычно владеет RetailCRM как ядро обработки заказов, потому что именно она видит заказы из всех каналов сразу и может свести резервы в одну картину. Битрикс сообщает о своих заказах, а RetailCRM превращает их в резервы и уже в таком виде транслирует обратно на витрину.
Когда складов несколько и остатки нужно агрегировать по хитрой логике, задача усложняется — этому посвящён отдельный материал про обмен остатками при нескольких складах и WMS. Но принцип «один владелец на одно число» остаётся неизменным даже там.
Склады, зоны и маппинг между системами
В RetailCRM склады — это отдельные сущности (магазины/склады), у каждого свой набор остатков по товарам. В 1С-Битрикс склады тоже есть — это либо склады модуля «Торговый каталог», либо, в простых магазинах, единый виртуальный склад. Чтобы обмен работал, каждому складу RetailCRM должен быть однозначно сопоставлен склад (или зона) в Битриксе. Это соответствие называют маппингом складов, и оно — фундамент всей синхронизации мультисклада.
Маппинг решает несколько практических вопросов сразу. Во-первых, он определяет, куда «приземлится» остаток конкретного склада RetailCRM на витрине. Во-вторых, он задаёт логику агрегации: показывать ли покупателю сумму по всем складам, остаток ближайшего к нему склада или остаток одного «онлайн-склада», с которого идёт отгрузка интернет-заказов. В-третьих, маппинг привязывает резервы: заказ с сайта должен резервировать товар именно на том складе, откуда он будет отгружен.
- Опишите склады в обеих системах. Выпишите список складов RetailCRM (их коды и назначение) и складов Битрикса. Убедитесь, что физически они означают одно и то же.
- Постройте таблицу соответствия. Каждому складу RetailCRM — свой склад Битрикса. Один-к-одному по возможности; если несколько складов RetailCRM отгружают онлайн-заказы, решите, объединять ли их в одну зону.
- Определите логику витрины. Что видит покупатель: сумму остатков, остаток «онлайн-склада» или наличие по регионам. Это влияет на то, какие склады участвуют в расчёте доступного остатка.
- Зафиксируйте склад отгрузки. Договоритесь, на каком складе создаётся резерв под интернет-заказ, чтобы он не «висел» на складе, с которого товар не отгружают.
- Проверьте новые склады. Заложите правило: при появлении нового склада в RetailCRM обмен не должен молча его игнорировать — либо автоматический маппинг по коду, либо явное уведомление.
Частая ошибка на этом этапе — сопоставлять склады по названию, которое люди могут переименовать. Гораздо надёжнее привязываться к внутренним кодам (символьным идентификаторам) складов: они стабильны и переживают переименования. Если в RetailCRM склад имеет код main, а в Битриксе ему соответствует склад с внешним кодом (полем XML_ID) retailcrm-main, обмен всегда найдёт нужную пару, даже если витринное название склада поменяют в админке.
Резервы: как они «съедают» остаток
Резерв — это обещание. Когда покупатель оформляет заказ, товар физически ещё лежит на складе, но продавать его повторно уже нельзя: он «забронирован» под этот заказ. Резерв уменьшает доступный остаток, не трогая физический, и снимается в одном из двух случаев: либо заказ отгружается (тогда уменьшается физический остаток, а резерв исчезает), либо заказ отменяется (тогда резерв исчезает, а физический остаётся). Именно вокруг резервов ломается больше всего интеграций, потому что резерв — это состояние, которое живёт во времени и меняется по событиям.
В связке RetailCRM + Битрикс резервами должна владеть одна система, и обычно это RetailCRM. Логика такая: заказ с любого канала (сайт, розница, маркетплейс, телефон) попадает в RetailCRM, она создаёт резерв, вычитает его из доступного остатка и транслирует уже уменьшенный доступный остаток обратно на витрину. Так витрина автоматически «узнаёт», что кто-то другой уже забронировал товар, даже если заказ был не с сайта.
Главное правило работы с резервами при синхронизации: резерв меняется только по событиям, а не пакетной перезаписью. Если обмен просто раз в 15 минут перезаписывает все остатки числами из учёта, он рискует затереть свежий резерв, созданный минуту назад под новый заказ. Поэтому события «заказ создан», «заказ отменён», «заказ отгружен» должны обрабатываться отдельным, событийным каналом, а пакетный обмен должен передавать уже посчитанный доступный остаток, а не «сырой» физический, который витрина попытается интерпретировать сама.
Доступный остаток: формула для витрины
Всё, что обсуждалось выше, сходится в одном числе, которое видит покупатель, — доступном остатке. Это то количество, которое магазин готов продать прямо сейчас, не рискуя не выполнить заказ. Считается оно по простой, но важной формуле:
Разберём слагаемые. Физический остаток берётся из источника истины (1С или RetailCRM). Резервы — это сумма броней под неотгруженные заказы всех каналов, ими владеет RetailCRM. Страховой запас (safety stock) — необязательный, но полезный буфер: количество, которое вы намеренно не продаёте онлайн, чтобы застраховаться от мелкой пересортицы, задержек обмена и одновременных продаж в рознице. Для дефицитных и ходовых позиций страховой запас в 1–2 единицы заметно снижает риск оверселлинга.
Важный вопрос — где именно считается эта формула. Есть два подхода. В первом доступный остаток считает RetailCRM и отдаёт на витрину уже готовое число — Битрикс просто показывает. Это надёжнее, потому что резервы всех каналов сведены в одном месте. Во втором витрина получает физический остаток и резервы отдельно и считает доступный сама — это гибче, но требует, чтобы Битрикс всегда имел свежие данные по резервам, иначе его расчёт разъедется с реальностью. В большинстве проектов мы выбираем первый подход: считать доступный остаток на стороне RetailCRM, а Битриксу отдавать готовую цифру.
| Где показывать | Какой остаток | Почему |
|---|---|---|
| Карточка товара, каталог | Доступный | Покупатель должен видеть то, что реально купит |
| Кнопка «Купить» | Доступный > 0 | Иначе примете заказ на отсутствующий товар |
| Админка, отчёты | Физический + резервы | Менеджеру нужна полная картина склада |
| Мультисклад/самовывоз | Доступный по складу | Наличие в конкретной точке выдачи |
Направления и частота обмена
Не все данные нужно синхронизировать с одинаковой скоростью. Пытаться гонять всё в реальном времени дорого и избыточно, а обмениваться всем раз в час — опасно для дефицитных позиций. Правильный подход — разделить обмены по критичности и назначить каждому свою частоту и механизм. Механизмов два: пакетный обмен по расписанию (агент или крон дёргает синхронизацию через равные интервалы) и событийный обмен через вебхуки (RetailCRM сама уведомляет витрину об изменении в момент, когда оно произошло).
| Данные | Направление | Механизм и частота |
|---|---|---|
| Остатки массово (весь каталог) | Учёт → Битрикс | Пакетно, раз в 10–30 минут |
| Остаток критичных/дефицитных SKU | Учёт → Битрикс | Событийно, вебхук, близко к реальному времени |
| Новый заказ с сайта | Битрикс → RetailCRM | Событийно, сразу при оформлении |
| Смена статуса заказа (отгрузка, отмена) | RetailCRM → Битрикс | Событийно, вебхук |
| Каталог товаров, цены | Учёт → Битрикс | Пакетно, раз в несколько часов или ночью |
Такое разделение даёт лучший баланс скорости и нагрузки. Основная масса остатков спокойно живёт на пакетном обмене раз в 10–30 минут — за это время редкий товар успеет уйти в критический дефицит. А вот дефицитные и ходовые позиции, где на счету каждая единица, обновляются событийно: как только их остаток меняется в учёте, вебхук почти мгновенно докатывает новое число до витрины. Заказы всегда идут событийно в обе стороны — новый заказ немедленно уходит в RetailCRM и создаёт резерв, а смена его статуса возвращается на витрину.
Реализация в 1С-Битрикс
Теперь конкретика по платформе. RetailCRM предоставляет официальный модуль для 1С-Битрикс (устанавливается через Marketplace), который закрывает базовый обмен: выгрузку заказов на сторону RetailCRM, загрузку статусов обратно и синхронизацию остатков. Для типового магазина с одним складом этого часто достаточно. Настройка модуля живёт в разделе «Настройки → RetailCRM» (или в отдельном пункте меню админки после установки) и включает сопоставление статусов, типов доставки, оплат, а также складов и остатков.
Как только появляются мультисклад, страховой запас, своя логика доступного остатка или высокие требования к скорости, поверх модуля нужна доработка. Вот из чего она обычно состоит на стороне Битрикса.
- Обработчики событий заказа. На события модуля продаж (
OnSaleOrderSavedи родственные) вешается код, который формирует и отправляет заказ в RetailCRM через её API сразу при оформлении, а не ждёт следующего пакетного цикла. - Приёмник вебхуков. Отдельный публичный скрипт-эндпоинт, который принимает уведомления RetailCRM об изменении остатка или статуса заказа, проверяет подпись/токен и точечно обновляет нужный товар в инфоблоке.
- Агент пакетной синхронизации. Штатный агент Битрикса или задание в кроне, которое раз в N минут запрашивает у RetailCRM остатки по складам и обновляет их в каталоге, подчищая пропущенные вебхуки.
- Слой расчёта доступного остатка. Функция, которая по маппингу складов агрегирует остатки, вычитает страховой запас и записывает итоговое число в поле количества товара (или торгового предложения).
- Управление доступностью. Логика, которая при доступном остатке ≤ 0 переводит товар в статус «нет в наличии», скрывает «Купить» или показывает предзаказ — в зависимости от бизнес-правил.
Технически остаток в 1С-Битрикс хранится либо в свойстве количества товара торгового каталога (CATALOG_QUANTITY), либо, при включённом складском учёте, в остатках по складам (таблицы складского учёта модуля Catalog). Если вы используете складской учёт Битрикса, обновлять нужно остатки конкретных складов через API модуля каталога, а витрина сама просуммирует их по правилам вывода. Если складской учёт выключен и вам достаточно одного числа, проще писать агрегированный доступный остаток прямо в количество товара. Выбор зависит от того, нужен ли покупателю разрез по складам (самовывоз, регионы) или хватает единой цифры наличия. Общие принципы связки каталога и учётной системы мы разбираем в статье про интеграцию магазина с 1С.
API RetailCRM: склады и остатки
Для нетиповых сценариев обмен идёт напрямую через REST-API RetailCRM, а не только через модуль. Знать основные точки входа полезно, чтобы понимать, чем именно оперирует интеграция и где искать проблему. API RetailCRM работает по HTTP, ответы приходят в JSON, авторизация — по API-ключу с ограниченными правами (ключ стоит выпускать с минимально необходимыми доступами).
- Справочник складов. Метод получения списка складов (stores/inventories reference) отдаёт коды и параметры складов — по ним строится маппинг на склады Битрикса.
- Получение остатков. Метод выгрузки остатков по товарам и складам — основа пакетного обмена «сверху вниз». Поддерживает фильтрацию и пагинацию, чтобы не тащить весь каталог одним запросом.
- Загрузка остатков. Метод, которым внешняя система (например, 1С или сам Битрикс, если он владеет складом) записывает остатки в RetailCRM. В типовой связке используется реже — обычно остатками кормят RetailCRM из учёта.
- Заказы. Создание и изменение заказов — через них с витрины уходят новые заказы, которые RetailCRM превращает в резервы.
- Вебхуки (уведомления). Настраиваются в RetailCRM и шлют POST-запросы на ваш эндпоинт при изменении заказа или остатка — основа событийного обмена.
При работе с API важно уважать лимиты запросов. RetailCRM ограничивает частоту обращений, и «жадный» обмен, который дёргает API в цикле по каждому товару, быстро упрётся в потолок и начнёт получать ошибки. Правильная практика — пакетные запросы с пагинацией, экспоненциальные повторы при временных ошибках и очередь на стороне Битрикса, которая сглаживает всплески. Так обмен остаётся быстрым, но не «долбит» API и не рискует быть придушенным лимитами в самый неподходящий момент.
Пересортица и оверселлинг: как избежать
Пересортица — это расхождение между тем, что система думает о наличии, и тем, что реально на складе. В контексте синхронизации она рождается из нескольких типичных ситуаций, и каждую из них можно закрыть системно.
- Гонка продаж между каналами. Последнюю единицу одновременно покупают на сайте и в рознице. Лечится страховым запасом и событийным обменом резервов: как только RetailCRM создала резерв под розничную продажу, доступный остаток на витрине уменьшается почти мгновенно.
- Затирание резерва пакетным обменом. Плановая синхронизация перезаписала остаток «сырым» физическим числом и стёрла свежий резерв. Лечится тем, что пакетный обмен передаёт уже посчитанный доступный остаток, а резервы меняются только событийно.
- Ошибки маппинга складов. Резерв создался на одном складе, а остаток витрины считался по другому. Лечится строгим соответствием складов по кодам и единой логикой агрегации.
- Задержка или потеря вебхука. Уведомление об изменении остатка не дошло, витрина показывает старое число. Лечится подстраховкой пакетным обменом и мониторингом свежести данных.
- Отрицательные остатки. Обмен записал остаток меньше нуля из-за рассинхрона, а витрина показала «−3». Лечится нормализацией: любое отрицательное значение доступного остатка трактуется как ноль.
Отдельно стоит сказать про оверселлинг — частный, но самый болезненный случай пересортицы, когда продано больше, чем есть. Он всегда дороже недопродажи: недопродажа — это упущенная выгода, а оверселлинг — это отменённый заказ, испорченное впечатление клиента, расходы на возврат и, в худшем случае, репутационный ущерб. Поэтому во всех спорных ситуациях интеграцию проектируют так, чтобы ошибка склонялась в сторону недопродажи. Показать «нет в наличии» на товар, который на самом деле есть, — неприятно, но переживаемо. Продать то, чего нет, — гораздо хуже.
Мультисклад и что показывать покупателю
Когда складов несколько, добавляется вопрос: какое наличие видит покупатель? Здесь нет единственно верного ответа — всё зависит от бизнес-модели. Разберём основные стратегии.
- Суммарный остаток. Витрина показывает сумму доступных остатков по всем складам, откуда идёт отгрузка онлайн-заказов. Просто и понятно, подходит, когда отгрузка централизована и покупателю неважно, с какого склада приедет товар.
- Остаток «онлайн-склада». Один склад помечен как источник для интернет-магазина, и витрина показывает только его наличие. Удобно, когда розничные склады не должны участвовать в онлайн-продажах.
- Наличие по регионам и точкам. Покупатель выбирает город или пункт самовывоза и видит остаток конкретной точки. Самый сложный, но и самый честный вариант для сетей с самовывозом.
- Наличие с признаком «под заказ». Если на ближнем складе товара нет, но есть на дальнем, показывается увеличенный срок доставки вместо «нет в наличии». Спасает продажи, но требует аккуратной логики сроков.
Какую бы стратегию вы ни выбрали, за ней стоит один и тот же механизм: маппинг складов определяет, какие склады участвуют в расчёте, слой агрегации сводит их остатки по выбранному правилу, а страховой запас и вычет резервов защищают от оверселлинга. Мультисклад не меняет принципов — он лишь усложняет правило агрегации. Детально сценарии нескольких складов и связку с WMS мы разбираем в отдельной статье про обмен остатками при нескольких складах.
Отказоустойчивость и режим деградации
Любой обмен рано или поздно сломается: упадёт сеть, зависнет API, агент не отработает, вебхук потеряется. Вопрос не в том, случится ли сбой, а в том, что произойдёт с витриной, пока он длится. Плохой сценарий — витрина молча продолжает показывать старые остатки и принимать заказы на товар, которого нет: сбой обмена превращается в оверселлинг. Хороший сценарий — витрина замечает, что данные устарели, и переходит в безопасный режим.
Механика проста. Каждому обновлению остатка присваивается метка времени последней успешной синхронизации. Витрина знает, насколько «свежи» данные по каждому товару. Если возраст данных превышает заданный порог (например, час для дефицитных позиций), товар автоматически переводится в осторожный режим: кнопка «Купить» прячется, показывается «уточняйте наличие» или товар переводится в предзаказ. Так временный сбой обмена приводит к недопродаже нескольких заказов, а не к десяткам отменённых из-за оверселлинга.
| Ситуация | Без защиты | С режимом деградации |
|---|---|---|
| Обмен встал на 2 часа | Продажи по устаревшим остаткам → оверселлинг | Дефицитные скрыты, ходовые в предзаказ |
| Вебхук потерялся | Витрина не знает о продаже | Пакетный обмен подчистит в след. цикл |
| API RetailCRM недоступно | Обмен падает с ошибкой, тишина | Алерт команде, витрина в safe-режиме |
| Отрицательный остаток | «−3 шт» на витрине | Нормализуется в ноль, «нет в наличии» |
Режим деградации — это не «перестраховка ради перестраховки», а прямое следствие бизнес-приоритета: недопродажа дешевле оверселлинга. Заложите его в проект с самого начала, потому что дописывать отказоустойчивость постфактум, после первого крупного сбоя в высокий сезон, всегда дороже и болезненнее.
Мониторинг, логи и сверка
Синхронизацию нельзя настроить один раз и забыть — за ней нужно наблюдать, потому что данные постоянно расходятся по мелочи, и задача мониторинга в том, чтобы ловить расхождения до того, как они станут заметны покупателям. Три уровня контроля закрывают большинство проблем.
- Логи обмена. Каждый пакетный цикл и каждый вебхук пишет в лог: что пришло, что обновилось, сколько заняло, были ли ошибки. Без логов разбор инцидента превращается в гадание. Лог должен позволять ответить на вопрос «когда последний раз обновлялся остаток товара X и каким числом».
- Мониторинг свежести. Автоматическая проверка, что обмен вообще идёт: если последняя успешная синхронизация была слишком давно, команде уходит алерт. Это ловит «тихие» сбои, когда всё выглядит рабочим, но данные не обновляются.
- Периодическая сверка. Раз в сутки или чаще фоновая задача сравнивает остатки в RetailCRM и в Битриксе и выдаёт список расхождений. Небольшие расхождения ожидаемы из-за задержек, но систематические — сигнал о баге в маппинге или логике резервов.
Отдельно полезно завести дашборд ключевых метрик: доля заказов, отменённых из-за отсутствия товара (прямой индикатор оверселлинга), средний возраст данных об остатках, число сработавших вебхуков против ожидаемого. Эти цифры показывают здоровье интеграции лучше, чем субъективное «вроде работает». Если доля отмен из-за отсутствия товара растёт — где-то в цепочке синхронизации завёлся рассинхрон, и его видно на графике раньше, чем в жалобах клиентов.
Частые ошибки
- Не назначили единый источник истины — две системы одновременно пишут остаток и по очереди затирают числа друг друга.
- Показывают на витрине физический остаток вместо доступного — резервы не учтены, и последнюю единицу продают дважды.
- Пакетный обмен перезаписывает остаток «сырым» физическим числом и стирает свежие резервы под только что оформленные заказы.
- Сопоставили склады по названию, а не по коду — после переименования склада в админке маппинг ломается, и остатки уезжают не туда.
- Полагаются только на вебхуки без подстраховки пакетным обменом — один потерянный вебхук оставляет витрину с неверным остатком надолго.
- Забыли про зависшие резервы неоплаченных заказов — доступный остаток искусственно занижен, магазин недопродаёт живой товар.
- Нет режима деградации — при сбое обмена витрина спокойно принимает заказы на отсутствующий товар, и сбой оборачивается волной отмен.
- Обмен не идемпотентный — повторный вебхук или перезапуск задачи после сбоя портит данные, дублирует заказы или задваивает списание.
- Игнорируют лимиты API RetailCRM — «жадный» обмен по одному товару упирается в потолок запросов и начинает получать ошибки в час пик.
- Отрицательные остатки не нормализуются в ноль — покупатель видит «−2 шт», а система принимает заказ на минусовое количество.
Чек-лист внедрения
Сведём всё в практический список, по которому удобно принимать готовность синхронизации перед запуском:
- Источник истины назначен. Для остатка и для резерва явно определена система-владелец, регламент зафиксирован письменно, запись настроена только в одной системе на каждое число.
- Маппинг складов построен. Каждому складу RetailCRM сопоставлен склад Битрикса по стабильному коду, определён склад отгрузки онлайн-заказов и правило агрегации для витрины.
- Доступный остаток считается верно. Формула «физический минус резервы минус страховой запас» реализована, отрицательные значения нормализуются в ноль, витрина показывает доступный, а не физический.
- Резервы работают событийно. Заказ создаёт резерв, отгрузка списывает физический остаток, отмена возвращает товар; зависшие резервы неоплаченных заказов снимаются по таймауту.
- Частоты обмена настроены. Массовые остатки — пакетно, критичные SKU и заказы — событийно через вебхуки, событийный обмен подстрахован пакетным.
- API используется бережно. Запросы пакетные с пагинацией, есть повторы при временных ошибках, обмен идемпотентен, лимиты RetailCRM соблюдаются.
- Режим деградации включён. При устаревании данных витрина прячет «Купить» или переводит в предзаказ; сбой обмена приводит к недопродаже, а не к оверселлингу.
- Мониторинг настроен. Есть логи обмена, алерты на «тихие» сбои, суточная сверка остатков и дашборд с долей отмен из-за отсутствия товара.
Вывод
Синхронизация складов и остатков RetailCRM с 1С-Битрикс — это не про «перекачку чисел», а про согласованность данных между системами, каждая из которых меняет наличие товара. Назначьте единый источник истины, сопоставьте склады по стабильным кодам, показывайте покупателю доступный остаток с учётом резервов и страхового запаса, разделите обмены по критичности и заложите режим деградации. Сделайте эти вещи — и витрина перестанет продавать то, чего нет, а сбой обмена обернётся мелкой недопродажей вместо волны отменённых заказов и потерянных клиентов.