Дилерский доступ - свои цены, свой каталог, документы
Открываем дилерам свои цены и свой каталог, не заводя второй сайт: группа, тип цены, права на разделы и закрытые документы.
Механика
Дилерская цена - это не скидка, а отдельный тип цены. У товара их может быть несколько: розница, опт, дилер, и каждый тип виден только тем группам пользователей, которым он разрешён. Витрина показывает ту цену, которая доступна текущему посетителю, и код для этого писать не нужно.
Права на тип цены и права на товар - разные вещи. Первое решает, какую цену увидит покупатель; второе - увидит ли он товар вообще. Дилерский ассортимент обычно требует и того, и другого: часть позиций рознице не показывают вовсе.
Дилер появляется не сам. Заявку на дилерство подтверждает менеджер, и только после этого учётная запись попадает в нужную группу. Автоматическое зачисление по галочке в форме превращает дилерские цены в публичные за неделю.
Документы - отдельный слой. Прайсы, сертификаты и договоры лежат вне открытого каталога и отдаются скриптом с проверкой прав, иначе ссылка на дилерский прайс уходит в поиск и перестаёт быть дилерской.
Наконец, кэш. Витрина с разными ценами для разных групп обязана кэшироваться с учётом группы, иначе розничный покупатель однажды увидит дилерскую цену - и это самая дорогая ошибка во всей задаче.
Стоит заранее решить, что дилер видит в личном кабинете. Обычно это его заказы, его документы и его условия, а не общий раздел с чужими данными; и чем раньше это описано словами, тем меньше потом переделок в правах и в шаблонах кабинета.
Шаги
- Завести группу дилеров и тип цены, доступный только ей.
- Настроить права на тип цены и проверить их на трёх ролях.
- Скрыть от розницы те разделы и товары, которые ей не предназначены.
- Разделить кэш витрины по группам пользователей.
- Отдавать документы дилера через скрипт с проверкой прав.
- Сделать заявку на дилерство с подтверждением менеджером.
Код
Заводим тип цены с правами:
\Bitrix\Main\Loader::includeModule('catalog');$priceTypeId = \Bitrix\Catalog\GroupTable::add(['NAME' => 'DEALER', 'BASE' => 'N', 'SORT' => 200])->getId();// право на чтение этого типа цены выдаётся конкретной группе пользователей\Bitrix\Catalog\GroupAccessTable::add(['CATALOG_GROUP_ID' => $priceTypeId, 'GROUP_ID' => $dealerGroupId, 'ACCESS' => 'Y']);Дилерская цена - это тип цены с правом на группу. Права задаются один раз, и дальше платформа сама решает, какую цену показать конкретному посетителю.
Показываем доступную цену на витрине:
'PRICE_CODE' => ['BASE', 'DEALER'], // перечисляем оба типа'USE_PRICE_COUNT' => 'N',// компонент покажет ту цену, которая доступна текущей группе пользователя// если доступны обе - показывают минимальную или ту, что задана порядкомВитрина показывает ту цену, которую видит группа. Оба типа перечисляют в параметрах вызова, а выбор между ними платформа делает по правам и по порядку сортировки типов.
Скрываем часть каталога от розницы:
$filter = ['IBLOCK_ID' => 12, 'ACTIVE' => 'Y'];if (!in_array($dealerGroupId, $USER->GetUserGroupArray())) { $filter['!PROPERTY_DEALER_ONLY_VALUE'] = 'Y'; // рознице этих позиций не видно}// то же самое делают правами на разделы: они надёжнее фильтра в кодеЧасть товаров и разделов дилерам показывают отдельно. Фильтр в коде проще, а права на разделы надёжнее: их невозможно обойти прямой ссылкой на карточку товара из поисковой выдачи.
Разделяем кэш по группам:
$groups = $USER->GetUserGroupArray();sort($groups);$cache->initCache(3600, 'catalog_' . $sectionId . '_' . implode('_', $groups), '/vendor/catalog');// без группы в ключе первый же дилер оставит свою цену в кэше для всехКэш витрины обязан учитывать группу пользователя. Это самая дорогая ошибка всей задачи: розничный покупатель, увидевший дилерскую цену, запомнит её и придёт с ней прямо в отдел продаж.
Отдаём документы с проверкой прав:
if (!in_array($dealerGroupId, $USER->GetUserGroupArray())) { \Bitrix\Main\Application::getInstance()->getContext()->getResponse()->setStatus('403 Forbidden'); return;}header('X-Accel-Redirect: /protected/price-dealer.xlsx'); // файл вне корня сайтаheader('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');header('Content-Disposition: attachment; filename="price-dealer.xlsx"');// скачивание закрытых документов полезно писать в журнал: кто и когда забиралПрайсы и договоры отдают с проверкой прав. Файл при этом лежит вне открытого каталога: проверка в коде бессмысленна, пока к документу ведёт прямая ссылка.
Принимаем заявку на дилерство:
$id = DealerRequestTable::add(['USER_ID' => $USER->GetID(), 'COMPANY' => $company, 'INN' => $inn, 'STATUS' => 'new'])->getId();\Bitrix\Main\Mail\Event::send(['EVENT_NAME' => 'DEALER_REQUEST', 'LID' => SITE_ID, 'C_FIELDS' => ['ID' => $id, 'COMPANY' => $company]]);// в группу дилеров пользователя добавляет менеджер, а не формаCUser::SetUserGroup($userId, array_merge($USER->GetUserGroupArray(), [$dealerGroupId]));// этот вызов живёт в обработчике подтверждения заявки, а не в самой формеЗаявку подтверждает человек, а не форма. Проверка реквизитов и решение о дилерских условиях - это работа отдела продаж, и автоматизировать её значит раздать оптовые цены всем желающим. Форма только собирает данные и уведомляет менеджера, а зачисление в группу остаётся отдельным осознанным действием.
Ограничения
Отдельного внимания требует поведение при выходе из учётной записи. Дилер, закрывший вкладку и вернувшийся гостем, обязан увидеть розничные цены и сокращённый каталог сразу, а не после сброса кэша; проверять это стоит на живом браузере, а не на словах.
Фасетный индекс собирается по ценам, доступным всем. Фильтр по цене на витрине с разными типами цен работает не так очевидно, как кажется, и его поведение стоит проверить на всех трёх ролях до запуска.
Обмен с учётной системой должен знать про новый тип цены. Иначе дилерские цены либо не приезжают вовсе, либо перетирают розничные, и обнаруживается это после первой же ночной выгрузки.
Скачивание закрытых документов полезно записывать в журнал. Вопрос «кто выгрузил дилерский прайс перед уходом к конкуренту» задают редко, но ответ на него должен существовать, и взять его больше неоткуда.
Налоги и валюта у дилерских цен бывают своими. Цена без налога для юридического лица - обычное требование, и его закладывают в тип цены заранее, а не считают в шаблоне.
Дилерский раздел живёт дольше, чем кажется. Его условия меняются, дилеры приходят и уходят, поэтому список группы и правила стоит держать в порядке, а не разбираться в них через два года по обрывкам кода. Полезно раз в квартал пересматривать состав группы вместе с отделом продаж: там почти всегда находятся учётные записи, которым дилерские цены давно не полагаются.
Типичные проблемы
Розничный покупатель увидел дилерскую цену.
Кэш витрины собран без учёта групп пользователя. В ключ кэша обязательно добавляют состав групп.
Дилер видит розничную цену.
Право на тип цены не выдано его группе или тип не перечислен в вызове компонента. Проверяют и права, и параметры.
Закрытый прайс нашёлся в поиске.
Файл лежит в открытом каталоге, а проверка прав стоит только на странице. Такие файлы держат вне корня сайта.
Дилерами стали все, кто заполнил форму.
Форма сама добавляет пользователя в группу. Решение принимает менеджер после проверки реквизитов.
После обмена дилерские цены пропали.
Выгрузка не знает про новый тип цены и заполняет только базовый. Тип цены добавляют в настройки обмена.
Частые вопросы
Чем тип цены лучше скидки для дилеров?
Он не пересчитывается правилами корзины и виден только своей группе. Скидка при этом остаётся инструментом акций.
Как скрыть товары от розницы?
Правами на разделы, а не фильтром в шаблоне. Фильтр обходится прямой ссылкой на карточку.
Нужен ли отдельный сайт для дилеров?
Обычно нет: группа, тип цены и права закрывают задачу. Второй сайт нужен, если отличается всё, включая вёрстку.
Как проверить настройку?
Открыть каталог тремя способами: гостем, розничным покупателем и дилером. Только это и доказывает, что права работают.
Что делать с ушедшим дилером?
Убирать из группы: цена и документы закроются сами. Учётную запись при этом обычно оставляют.
Смежное
-
Цены, скидки и купоны - оглавление подтемы
-
Типы цен: розница и опт, права групп, цена по количеству - механика самих типов цены
-
Права на инфоблок и заказы: выдача из интерфейса и кодом - как скрыть часть каталога
-
Свои страницы личного кабинета: раздел, меню, права, данные - свой раздел кабинета для дилера
-
Отдача файла с проверкой прав: закрытые каталоги, заголовки, ссылки - как отдавать документы
-
Каталог и продажи - устройство магазина целиком
-
Группы пользователей: назначение, срок действия, автоматизация - выдача группы дилера и её срок
-
Заказ для юрлица: тип плательщика, реквизиты, счёт - оформление заказа организацией