У оптовых продаж есть устойчивая картина: клиент звонит менеджеру, менеджер открывает 1С, смотрит цену по соглашению, проверяет остаток, выставляет счёт. Пятьдесят клиентов — пятьдесят таких разговоров в неделю, и половина из них о том, что уже знает система. Личный кабинет нужен не для красоты, а чтобы эта половина перестала занимать человека.
Но B2B-кабинет сильно отличается от «истории заказов» в розничном магазине. Там достаточно показать, что человек купил. Здесь приходится вытаскивать из учёта то, что обычный обмен каталогом вообще не передаёт. Разберём по порядку, какие данные нужны и откуда каждое берётся.
Чем оптовая витрина отличается от розничной
Четыре отличия, из которых вырастает вся техническая часть:
- Цена у каждого клиента своя — по типу цен или по индивидуальному соглашению
- Товар продаётся кратно упаковке, а не поштучно
- Есть отсрочка платежа, а значит долг и кредитный лимит
- Заказы повторяются: тот же набор позиций раз в месяц
Каждый пункт — это отдельный разговор с тем, кто ведёт учёт. Ни один из них нельзя закрыть «настройками в админке»: данные живут в учётной системе, и задача сайта — правильно их получить и правильно показать.
Своя цена: типы цен и соглашения
В 1С цена товара — не одно число. Есть виды цен: закупочная, розничная, оптовая, дилерская, и их может быть десяток. В «Управлении торговлей» поверх этого лежат соглашения об условиях продаж, где конкретному контрагенту назначается вид цены и скидка.
Хорошая новость: несколько типов цен обмен передаёт штатно. В offers.xml у предложения лежит блок <Цены>, и внутри может быть несколько элементов <Цена>, каждый со своим <ИдТипаЦены>. Типы цен описаны в классификаторе из import.xml, так что сайт знает их названия и валюту. Как устроен сам протокол, мы разбирали в статье про обмен по CommerceML.
Дальше на сайте появляется справочник ценовых групп: контрагент привязан к группе, группа — к типу цен из 1С. Пользователь авторизовался, система определила его группу и показала нужную колонку. Выглядит просто, но здесь два подводных камня.
Если скидка в учёте считается не типом цены, а процентом по соглашению или условием «от объёма», обменом она не приедет. Такую цену придётся либо запрашивать у 1С на лету, либо договариваться, что для сайта в учёте заводится отдельный вид цены.
Второй камень — НДС. В выгрузке у цены есть признак, включён налог или нет. Если на сайте часть типов цен приезжает с НДС, а часть без, и это не учтено, итог в корзине разойдётся со счётом из 1С на двадцать процентов. Проверять нужно на первом же тестовом обмене, а не после запуска.
Кто есть кто: пользователь и контрагент
В розничном магазине один аккаунт — один покупатель. В опте у одной компании обычно несколько сотрудников: снабженец заказывает, руководитель смотрит документы, бухгалтер — акты сверки. Значит, у аккаунта появляется два уровня: пользователь и контрагент, к которому он привязан.
Связь делается по тому же механизму, что и товары: GUID контрагента из 1С пишется в поле внешнего кода на сайте. Привязывать по ИНН соблазнительно, но ненадёжно — у одной компании бывает несколько контрагентов в учёте, с разными договорами и условиями.
Регистрация в таком кабинете не бывает мгновенной. Человек оставляет заявку с ИНН и контактами, менеджер сопоставляет её с контрагентом в учёте и подтверждает. Автоматически это делать нельзя: ошибка привязки означает, что чужой человек увидит чужие цены и чужой долг.
Долг и лимит: то, чего обмен не умеет
Здесь заканчивается CommerceML. Формат описывает товары, цены, остатки и заказы — и ничего про взаиморасчёты. Сальдо по контрагенту, просроченную задолженность и кредитный лимит придётся забирать иначе.
Рабочих вариантов два. Первый — HTTP-сервис в 1С: программист 1С публикует метод, который по GUID контрагента возвращает JSON с долгом, лимитом и датой ближайшего платежа. Это аккуратнее всего, потому что логику расчёта пишет тот, кто понимает учёт. Второй — OData-интерфейс, который публикуется вместе с базой и даёт доступ к регистрам напрямую. Работает без доработки конфигурации, но запросы получаются тяжёлыми, а структура регистров завязана на версию конфигурации и может поехать при обновлении.
Что бы вы ни выбрали, кабинет нельзя делать так, чтобы каждое открытие страницы дёргало 1С. Опубликованная база обычно не рассчитана на нагрузку с сайта: двадцать одновременных запросов — и менеджеры жалуются, что учёт встал. Правильная схема — короткий кеш на стороне сайта и показ времени, на которое данные актуальны.
- Долг и лимит кешируются на несколько минут, рядом подпись «данные на 14:35»
- Запрос к 1С идёт с таймаутом, при недоступности показывается последнее известное значение
- Обновление по кнопке — с защитой от частых нажатий
- Падение 1С не ломает кабинет: каталог и заказы работают дальше
Кратность, упаковки и округление
Классическая ошибка переноса розничной логики в опт: поле количества, в которое можно вписать любое число. В учёте товар лежит в коробках по 12 штук, минимальная партия — коробка, а клиент заказал 7. Менеджер потом звонит и переспрашивает — ровно та работа, которую кабинет должен был убрать.
В выгрузке у товара есть базовая единица измерения и могут быть упаковки с коэффициентом. Эти данные нужно донести до корзины: шаг количества равен кратности, минимум — минимальной партии, а рядом с полем написано, что это за единица. Если упаковок несколько, выбор упаковки — это выбор, а не вычисление: клиент решает, берёт он коробками или паллетами.
Проверка, которая отлавливает почти все ошибки с единицами: соберите тестовый заказ в кабинете и выставьте счёт на него же из 1С вручную. Суммы и количества должны совпасть символ в символ. Расхождение на одну позицию означает, что на бою оно будет на каждой.
Повторный заказ и шаблоны закупки
Это самая недооценённая функция и при этом самая востребованная. Оптовый клиент редко покупает что-то новое: он берёт тот же набор, что в прошлом месяце, с поправкой на пару позиций. Кнопка «повторить заказ», которая складывает прошлый состав в корзину, экономит ему больше времени, чем любой умный поиск.
Нюанс в том, что состав прошлого заказа мог устареть: позиция снята с производства, цена изменилась, остатка нет. Правильное поведение — перенести в корзину то, что доступно, и честно перечислить, что не перенеслось и почему. Молча выкинуть позицию хуже, чем показать её с пометкой.
Следующий шаг — сохранённые списки закупки: клиент собирает свою номенклатуру один раз и дальше заказывает из неё, проставляя количества. Для компаний, которые берут одно и то же каждую неделю, это превращает заказ в двухминутное дело. Такие сценарии мы закладываем в каталоги и порталы, где корзина вообще может быть не корзиной, а запросом коммерческого предложения.
Документы: что отдавать и в каком виде
Запрос «хочу скачивать счета из кабинета» звучит безобидно, а на деле развилка. Можно печатать счёт на стороне сайта по данным заказа — быстро, но это будет похожий документ, а не тот же самый, что в учёте. Можно забирать печатную форму из 1С — тогда документ подлинный, но нужен метод, который её отдаёт, и место, где файл хранится.
Практичный компромисс: счёт на оплату генерирует сайт сразу после оформления, а закрывающие документы и акт сверки приходят из учёта по запросу, с задержкой. Первое нужно клиенту немедленно, второе — раз в месяц, и ждать минуту там никто не против.
Отдельно: прайс-лист в Excel. Его просят почти всегда, и он должен собираться по ценовой группе того, кто его скачивает, иначе смысла нет. Генерировать такой файл на каждый клик тяжело — собирайте по расписанию или в фоне, с уведомлением о готовности.
Где такие кабинеты ломаются
- Кеш страниц отдаёт персональные цены чужому пользователю — личные разделы нужно исключать из полностраничного кеша полностью
- Разделы кабинета попадают в индекс: закрывайте в robots.txt и ставьте noindex, иначе в выдаче появятся технические страницы
- Цены видны неавторизованным — решается не скрытием через CSS, а тем, что сервер их не отдаёт
- Нет ограничения частоты запросов: один скрипт выкачивает весь прайс через кабинет за полчаса
- Сотрудник уволился, доступ остался — нужна возможность отключить пользователя, не трогая контрагента
- Заказ из кабинета уходит в 1С без указания соглашения, и менеджер переоформляет его вручную
Последний пункт обиднее всего: технически всё работает, а экономии нет, потому что заказ всё равно проходит через руки. При проектировании обмена заказами из кабинета нужно сразу решить, какие реквизиты в них подставляются — договор, соглашение, склад отгрузки, вид оплаты, — чтобы документ в учёте создавался готовым к проведению.
С чего начинать
Не с дизайна кабинета. Сначала — три вопроса к тому, кто ведёт учёт: как у вас назначается цена клиенту, где лежит долг, и готовы ли мы публиковать базу для запросов с сайта. Ответы на них определяют, будет ли проект простым расширением обмена или отдельной интеграцией со своей строкой в смете.
Полезный порядок внедрения: сначала авторизация, своя цена и история заказов — это закрывает большую часть звонков. Потом повторный заказ и списки закупки. Долг, лимиты и документы — третьим этапом, когда понятно, что кабинетом вообще пользуются. Так проект можно запустить за несколько недель, а не ждать полгода полной версии.
Мы делаем оптовые кабинеты на 1С-Битрикс и на своих решениях, подключаем их к учёту через интеграцию с 1С и к облачному складу через обмен с МойСклад, где долг и взаиморасчёты доступны через обычное API без доработок. Если кабинет нужен вместе с новой витриной, смотрите разработку интернет-магазина — там он считается частью проекта, а не доработкой после запуска.