Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

Обмен 1С с b2b-порталом: шесть мест, где он рвётся уже после приёмки

Дата публикации: 22-09-2026 04:00:00

Что происходит с обменом сайта и 1С после запуска, когда в него попадают реальные заказы, цены и остатки? Разбор шести проблем на живом проекте — для разработчиков, интеграторов и владельцев e-commerce-проектов.

Основное содержимое страницы с новостью.

Обмен с 1С обычно принимают в тот день, когда на витрине впервые появились товары. Каталог приехал, картинки на месте, тестовый заказ упал в учёт, всё работает, подписываем акт. Проблемы начинаются через месяц, и выглядят они не как падение. У части позиций вместо цены ноль. Менеджер не находит заказ по номеру, который видит в 1С. В учёте с утра лежат две копии ночных заказов, и никто не знает, какая настоящая.

Дальше разбор по живому проекту: b2b-портал оптового поставщика отделочных материалов, около полутора тысяч позиций, три бренда, тридцать человек в офисе. Каталог, цены, остатки и заказы ходят между сайтом и 1С по расписанию. Портал писали мы целиком, обмен тоже, так что грабли ниже собственные, а не пересказанные с чужих конференций.

Речь не про то, как поднять обмен. Про то, что с ним происходит потом, когда через него пошли настоящие данные и настоящие люди.

Больше не нужно искать и обзванивать каждое диджитал-агентство
Создайте конкурс на workspace.ru – получите предложения от участников CMS Magazine по цене и срокам. Это бесплатно и займет 5 минут. В каталоге 15 617 диджитал-агентств, готовых вам помочь – выберите и сэкономьте до 30%.
Создать конкурс →

Протокол это самая простая часть

Штатный протокол обмена 1С с сайтом открытый, его придумали «1С» и «1С-Битрикс», и он занимает полторы страницы. Инициатор всегда 1С, сайт только отвечает.

Выгрузка каталога идёт четырьмя шагами. Сначала 1c_exchange.php?type=catalog&mode=checkauth, в ответ три строки: success, имя cookie, значение cookie. Дальше mode=init, и сайт сообщает два своих условия: zip=yes или zip=no и file_limit=<число байт>, то есть максимальный размер куска, который он готов принять за один запрос. Потом mode=file&filename=... с содержимым в POST, и наконец mode=import&filename=..., на который сайт отвечает либо progress (повтори тот же запрос ещё раз), либо success. На любой ошибке первая строка ответа failure, ниже текст.

Заказы ездят обратно почти так же: type=sale&mode=query отдаёт заказы сайта в 1С, после успешной записи 1С стучит mode=success, а изменения заказов уезжают на сайт через mode=file.

Сеанс целиком:

   1С                                       сайт
    |  type=catalog&mode=checkauth  ------>  |
    |  <------  success / имя cookie / значение cookie
    |  type=catalog&mode=init       ------>  |
    |  <------  zip=yes|no / file_limit=<байт>
    |  type=catalog&mode=file       ------>  |  POST, кусками по file_limit
    |  <------  success                      |
    |  type=catalog&mode=import     ------>  |
    |  <------  progress   (повторить тот же запрос)
    |  type=catalog&mode=import     ------>  |
    |  <------  success                      |
    |                                        |
    |  type=sale&mode=query         ------>  |  заказы с сайта в 1С
    |  type=sale&mode=success       ------>  |
    |  type=sale&mode=file          ------>  |  статусы заказов обратно на сайт

Инициатор всегда слева. Со стороны сайта не начинается ни один шаг: если обмен встал, кнопки «запустить» у вас нет, есть расписание в 1С и человек, который до неё дойдёт.

Вот и весь протокол. Три слова в ответе, четыре режима, XML по стандарту CommerceML 2. Этой части посвящена половина статей про интеграцию с 1С, и именно она почти никогда не ломается.

Ломается всё, что протокол не описывает: что значит пришедшее значение, сколько раз можно повторить сеанс, какое поле чьё. Дальше шесть таких мест, все с настоящими симптомами.

Пустое значение это не значение

Симптом: на карточках товара вместо цены ноль. Причём вчера цена была.

Механизм. В 1С у части номенклатуры базовая цена просто не заполнена: позиция заводится под заказ, цену ставит менеджер руками при согласовании. В выгрузку такая позиция всё равно попадает, и приезжает она с нулём. На стороне сайта стоит обычный на вид код:

$item->price = (float) $offer['ЦенаЗаЕдиницу'];
$item->save();

Он честно записывает то, что приехало. Ноль перетирает цену, которую туда положили руками или предыдущей выгрузкой, и витрина показывает товар по нулю.

Неочевидное здесь вот что. Обмен молча смешивает три разных состояния, которые для бизнеса означают противоположные вещи:

  • поля не было в файле вообще (1С про него ничего не сказала),

  • поле пришло пустым (в 1С оно не заполнено),

  • поле пришло нулём, и ноль это настоящая цена (акция, подарок, сопутствующий товар за рубль).

Пока код читает (float), все три превращаются в 0.0. Починка не в том, чтобы дописать if ($price > 0), хотя мы именно так и сделали в первый час: это заплатка, которая на следующей неделе выстрелит на позиции, которую действительно отдают бесплатно.

Правильный вопрос звучит иначе: кто хозяин каждого поля. Цена закупки, розничная цена, остаток, название, картинка, описание могут приходить из разных мест, и часть полей редактирует менеджер на сайте. Как только это записано (хоть таблицей в вики, хоть константой в коде), поведение при пустом значении становится очевидным: у поля, чей источник 1С, пустое значение означает «очистить», у поля, чей источник сайт, оно означает «не трогать».

И отдельно про проверку. После правки мы не написали «готово», а посчитали результат на боевом: цена появилась у семи карточек из восьми, а у восьмой её нет и в самой 1С. Восьмая это не недоделка, это ровно тот случай, ради которого правило и пишется. Без такого счёта вы не знаете, починили вы что-нибудь или просто перестали видеть симптом.

Симптом: менеджер берёт номер заказа из 1С, вбивает его в поиск на портале и не находит ничего. Заказ при этом есть и открывается по прямой ссылке.

Номер хранился с пробелом на конце. Пробел приехал вместе с данными и лёг в базу как есть, а поиск ищет по точному совпадению.

Такие вещи живут в бэклоге месяцами, потому что не горят: система работает, данные целы, всего-то пробел. А на деле это отказ поиска для человека, который ищет заказы двадцать раз в день.

Из 1С регулярно приезжают концевые пробелы, неразрывный пробел вместо обычного, разный регистр в артикулах, двойные пробелы в названиях. Это не аномалия: поля заполняют люди в интерфейсе, у которого нет валидации.

Лечится нормализацией на границе, и только там. Один слой на входе обмена, который для каждого строкового поля решает, что с ним делать:

function normalizeCode(string $raw): string {
    $s = str_replace("\xC2\xA0", ' ', $raw);   // NBSP из 1С
    $s = preg_replace('/\s+/u', ' ', $s);
    return mb_strtoupper(trim($s));
}

Важно не размазать это по коду. Соблазн большой: поправить поиск, чтобы он делал TRIM на лету. Через полгода TRIM будет в семи местах, в восьмом его забудут, и ошибка вернётся уже как «поиск иногда не находит». Нормализованное значение хранится в отдельной колонке, оригинал остаётся рядом нетронутым: он нужен, когда придёт время выгружать данные обратно в 1С, где ждут ровно ту строку, которую оттуда и прислали.

Повтор обмена это норма, а не исключение

Симптом: за ночь в учёт попала вторая копия заказов.

Причина у нас оказалась скучной: крон запускал выгрузку дважды. Но дело не в кроне. Дело в том, что двойной запуск вообще не должен приводить к дублям, и протокол прямым текстом это подразумевает: ответ progress означает «пришли этот же запрос ещё раз», и таких повторов на большом каталоге десятки. Сеанс обмена в принципе не бывает одноразовым.

Список поводов для повтора длиннее, чем кажется: 1С не получила ответ из-за таймаута и переспросила, сеанс не уложился в окно и наложился на следующий, админ нажал «обменяться сейчас» поверх расписания, файл поехал кусками по file_limit и часть кусков доехала дважды. Ни один из них не поломка.

Значит, идемпотентность нужна не как приятное свойство, а как условие работоспособности. У нас это два простых правила.

Первое: внешний идентификатор из 1С (Ид, тот самый GUID) участвует в уникальном ключе, и запись идёт через upsert, а не через insert:

insert into orders (guid_1c, number, total)
values (:guid, :number, :total)
on conflict (guid_1c) do update
   set number = excluded.number,
       total  = excluded.total;

Второе: на время сеанса берётся блокировка, и второй запуск не встаёт в очередь, а сразу уходит. В PostgreSQL это pg_try_advisory_lock, и он лучше файла-флага ровно тем, что снимается сам при падении процесса. Флаг в файле после падения остаётся лежать, и обмен встаёт до утра, а вы об этом узнаёте от клиента.

Проверяли по факту: в ночь на восьмое сентября выгрузка стартовала один раз. Не «должна стартовать», а стартовала, по журналу запусков.

Ключ это GUID, и он не один

На витрине три бренда: основной и два отдельных, со своими каталогами и своими ценами. Обмен у каждого свой.

Обычная ошибка при таком раскладе: искать номенклатуру по артикулу или наименованию. Артикул кажется естественным ключом: короткий, человекочитаемый, и почти всегда работает. А потом у двух брендов совпадают артикулы, и один товар начинает перетирать другой вместе с ценой и остатком.

Настоящий ключ в обмене один: Ид из CommerceML, то есть GUID объекта в конкретной базе 1С. Ключевое слово «в конкретной»: у второго бренда своя база, и GUID той же по сути позиции там другой. Как только баз становится больше одной, нужна таблица соответствий (внешняя система, внешний ключ, наш объект), и именно её мы дописывали, подключая второй бренд.

Заодно это ответ на вопрос со стадии оценки: «почему второй бренд стоит почти как первый, обмен-то тот же». С первым брендом ключ один и его можно не осознавать. Со вторым появляется сущность «внешняя система», и её надо протащить через весь обмен: цены, остатки, заказы, поиск дублей.

Статусы заказа приходят позже, чем ждёт менеджер

Это место я считаю самым неочевидным, потому что тут ломается не код, а ожидания, и починить его правкой нельзя.

В протоколе прямым текстом сказано: состояния заказа по оплате и по отгрузке выгружаются на сайт только при полном выполнении операции. Полная оплата, полная отгрузка. До этого момента заказ на сайте считается неоплаченным и неотгруженным. Там же оговорка: заказ, по которому уже прошла оплата или отгрузка, при попытке изменить его в 1С на сайт как изменённый не загрузится.

Теперь представьте оптовый заказ на сорок позиций. Половину отгрузили сегодня, остальное на следующей неделе. В 1С картина честная, в кабинете клиента по-прежнему «в работе», и всё это время он звонит менеджеру. А дизайнер к этому моменту уже нарисовал прогресс отгрузки, потому что заказчик попросил. Нарисовать можно, данных под это нет.

Выходов ровно два, и оба надо обсуждать до вёрстки кабинета, а не после. Либо интерфейс честно показывает то, что даёт протокол: два состояния, без промежуточных. Либо заводится второй канал, отдельная выгрузка по расписанию с реализациями по заказу, и это уже доработка на стороне 1С, то есть чужие часы, чужой подрядчик и чужие сроки.

Общий принцип: прежде чем обещать в интерфейсе поле, проверьте, что оно есть в источнике и приезжает тогда, когда нужно. В смете обмена эта проверка стоит час, а после сдачи макетов она стоит переделку кабинета.

Обмен кончается не в базе, а на экране

Последний случай красивый именно тем, что обмен в нём отработал идеально.

Данные второго бренда приехали, импорт закончился успехом, в базе всё на месте. Витрина при этом не собралась: сборка страницы отменилась из-за занятой очереди, и на главной просто не появилось восемь направлений каталога. С точки зрения всех логов обмена ничего не произошло, success на месте.

Если между 1С и глазами покупателя стоит кэш, статическая сборка, поисковый индекс или CDN, то «импорт завершён» не значит «человек видит товар». Каждый такой слой это ещё одно место, где данные могут остановиться, и на любом из них нет ошибки: кэш не сломался, он просто старый.

Поэтому финальную проверку мы делаем не по логу импорта, а с той стороны, с которой на портал смотрит клиент. Запрос к витрине, счёт того, что на ней видно, сравнение с тем, что в базе. Восемь направлений на месте, 279 карточек из 383 с розничной ценой, семь из восьми с восстановленной ценой. Числа скучные, но именно они отличают «обмен работает» от «обмен вроде работает».

Чем принимать обмен

Если свести всё это в чеклист приёмки, выйдет пять пунктов, и ни один не звучит как «данные приехали».

  1. Для каждого поля записано, чьё оно: 1С или сайта. Пустое значение из 1С не перетирает поле, которым владеет сайт.

  2. Все строковые поля нормализуются на входе, в одном месте, оригинал сохраняется рядом.

  3. Обмен идемпотентен, повторный запуск проверен руками: запустили дважды, дублей нет.

  4. Ключ сопоставления это GUID, для каждой внешней базы свой, через таблицу соответствий.

  5. Проверка идёт со стороны витрины и в числах, а не по строке success в логе.

Плюс шестой, не технический: у обмена должен быть человек, который смотрит на эти числа каждый день. Обмен с 1С не относится к системам, которые настроил и забыл. Он ломается тихо, без падений и алертов, и обнаруживается обычно менеджером, который час ищет заказ по номеру с пробелом.

Схожие новости

#Наименование новостиТональностьИнформативностьДата публикации
1Один канал больше не опора: как бизнес диверсифицирует продажи в e-commerce010.4221-09-2026
2 Сайты, которые продают: как увеличить продажи и привлечь клиентов 06.8526-08-2026
3Ловушка дебиторки в 1С:УНФ: почему ваши менеджеры кредитуют клиентов и как это остановить-16.3325-08-2026
4 Как быстро начать продавать онлайн? Нашли белорусский сервис, который помогает войти в e-commerce 5718-02-2026
5ЭПД за 3 секунды: как избавить логистов от двойной работы в 1С:УНФ при оформлении накладных08.7428-08-2026
6Бизнес сможет увеличить сбыт после интеграции портала поставщиков и "Росэлторга"0015-02-2021
7Два года за два месяца: как адаптировать бизнес к новым реалиям0017-06-2020
8Битрикс24: Что это? Какие задачи решает Битрикс24 — полный гайд для новичков06.9121-09-2026
9Как не убить свой стартап? Разбираем типичные ошибки начинающих предпринимателей0017-01-2020
10Можно ли в 1С назвать товар не так, как в накладной? Разбираемся если товар маркированный06.9409-08-2026

Классификация: Мнения. Схожих патентов: 0. Схожих новостей: 10. Тональность: 0. Информативность: 8.93. Источник: feeds.feedburner.com.