Кейс: Дилерский портал сантехники

Закрытый кабинет дистрибьютора, где единица работы — дилерский заказ салона или организации, а не корзина витрины. Портал проводит закупщика от подбора сантехники до подтверждённого резерва и готовности к отгрузке.

Карточка проекта

Отрасль
Дистрибуция сантехники дилерским салонам, магазинам и монтажным организациям
Основной рынок
Беларусь
Масштаб
2 склада, ~9 000 позиций, ~180 дилерских организаций
Основная проблема
Заказ живёт в таблице, переписке и учёте одновременно: нет общей версии строк, замен и резерва
Ключевое решение
Версионируемая рабочая область заказа: состояния строк, совместимость, аналоги, очередь исключений
Основные пользователи
Закупщик дилера, руководитель дилера, региональный менеджер, контент-менеджер дистрибьютора
Срок внедрения
16 недель до пилота
Технологический стек
Laravel, Inertia, Vue 3, TypeScript, PostgreSQL, Redis, Horizon, S3, обмен с учётной системой
Статус проекта
Внедрён

Отрасль и клиент

Рынок и задача

Клиент — региональный дистрибьютор сантехники в Беларуси. Он работает с дилерскими салонами, розничными магазинами, монтажными организациями и небольшими строительными компаниями. Закупщик дилера собирает заказ на пополнение салона и комплектацию нескольких объектов сразу: санитарная керамика, мебель для ванных, смесители, душевое оборудование, инсталляции, комплектующие и запасные части. Дистрибьютор автозапчастей ведёт подбор автозапчастей по VIN для автосервисов.

Это не закупочный проект объекта для монтажников: там бригада комплектует конкретный узел на объекте. Здесь единица работы — заказ организации у дистрибьютора: договорной ассортимент, кратность упаковки, два склада отпуска и подтверждённый резерв. Когда «интернет-магазин» на деле оказывается бизнес-системой — в интервью Почему бизнесу иногда нужен Laravel, а не WordPress.

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

Масштаб первой версии

Склады2
Позиции каталога~9 000
Дилерские организации~180
Срок до пилота16 нед.
ПоказательЗначение
ГеографияБеларусь
Склады отпуска2
Активные позиции каталога~9 000
Дилерские организации~180
Пользователи у дилеранесколько на организацию, несколько адресов получения
Контур пилотаограниченная группа дилеров, одна товарная группа
Старый канал в пилотетолько как аварийный
Основной процессОт подбора до подтверждённого резерва и готовности к отгрузке

Каталог не равен заказу: дилеру нужна общая версия строк с вычисляемым состоянием, а не ещё одна выгрузка прайса.

Роли

Закупщик дилера

Ищет товары, собирает заказ, устраняет предупреждения, принимает замены и отслеживает статус.

Ограничение

Видит только данные своей организации и разрешённый ассортимент.

Руководитель дилера

Смотрит активные заказы организации, подтверждает внутренне значимые изменения, управляет пользователями.

Ограничение

Не изменяет справочники дистрибьютора.

Региональный менеджер

Разбирает очередь отклонений, предлагает решения внутри заказа, возвращает строки на уточнение.

Ограничение

Не меняет складские остатки вручную; корректные заказы проходят без него.

Контент-менеджер

Ведёт характеристики, связи комплектов, допустимые замены и файлы карточек.

Ограничение

Не подтверждает дилерские заказы.

Складские сотрудники продолжают работать в учётной системе. Портал показывает полученные статусы и не создаёт второй складской интерфейс.

Как было

Заказ существовал сразу в четырёх версиях

Дилер выписывал позиции из каталога, остатки уточнял у менеджера, аналоги согласовывал в мессенджере, итоговый файл отправлял по почте. Через несколько часов часть товара уже была зарезервирована, одна модель снята с поставки, выбранная инсталляция не подходила к клавише смыва. Менеджер собирал заказ заново: артикулы, упаковки, доступность на двух складах, договорной ассортимент. Дилер в это время продолжал править свою таблицу. Решение о замене жило только в переписке.

Семь шагов без общей версии

  1. Дистрибьютор выгружал каталог и остатки.
  2. Дилер копировал позиции в собственную таблицу.
  3. Менеджер вручную проверял артикулы, кратность упаковки и доступность.
  4. Недоступные позиции возвращались дилеру на замену.
  5. Решение фиксировалось в письме или сообщении, но не в исходном заказе.
  6. После очередного изменения проверка повторялась.
  7. Подтверждённый состав заново переносился в учётную систему.

Корневая проблема

Пока заказ жил в таблице, письме и учёте одновременно, ни один участник не видел целостного процесса. Закупщик не понимал, какие остатки доступны именно его организации и когда они будут зарезервированы. Менеджер тратил время на формат данных вместо исключений. Комплект мог быть технически неполным при «правильных» отдельных позициях. Повторный заказ собирался почти с нуля, даже если дилер регулярно закупал одну матрицу.

Центральная сущность продукта — не форма отправки и не каталог, а совместная рабочая область дилерского заказа.

Решение

Заказ объединяет организацию, строки, доступность, упаковку, совместимость, замены, резерв и журнал решений в одной версии.

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

Система проверяет формальные правила и показывает отклонения. Дилер принимает решения по ассортименту. Региональный менеджер вмешивается только там, где автоматического правила недостаточно.

Как работает новый процесс

  1. Закупщик создаёт заказ вручную, из шаблона или повторяет ранее завершённый.
  2. Добавляет товары поиском по артикулу, названию, серии, назначению и характеристикам.
  3. Портал сразу показывает доступность, упаковку, обязательные компоненты и ограничения совместимости.
  4. Для недоступной позиции система предлагает разрешённые аналоги, но не подменяет товар без подтверждения.
  5. Закупщик устраняет предупреждения и отправляет заказ на проверку.
  6. Портал создаёт резерв в учётной системе и фиксирует результат по каждой строке.
  7. Исключения попадают в очередь менеджера: конфликт условий, нет разрешённой замены, раздельная доступность по складам, неполные данные.
  8. Менеджер предлагает решение внутри заказа; дилер принимает или отклоняет его, выбор сохраняется в журнале.
  9. После подтверждения состав версии блокируется и передаётся в учёт.
  10. Дилер видит этапы подготовки и получает уведомление, когда нужно следующее действие.

Система не решает, подходит ли иной дизайн для проекта дилера, не объединяет отгрузки с разных складов без согласования и не подменяет товар только из-за совпадения части характеристик.

Основные сценарии

Повторное пополнение матрицы

Закупщик открывает завершённый заказ, выбирает «Повторить», получает новую версию с текущей доступностью и проходит только изменившиеся строки.

Результат: готовый заказ без ручного копирования артикулов.

Комплектация санузла

Пользователь добавляет базовые позиции. Портал показывает недостающие обязательные компоненты и совместимые варианты. Окончательный выбор дизайна остаётся за дилером.

Результат: проверенный состав комплекта, а не набор несвязанных карточек.

Отсутствующая позиция

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

Результат: решение зафиксировано в заказе и не теряется в переписке.

Частичное подтверждение резерва

Учёт возвращает подтверждение не на всё количество. Портал блокирует финал и предлагает изменить количество, выбрать замену, разделить комплектование или дождаться менеджера.

Результат: решение принимает человек, статус строки остаётся объяснимым.

Контроль после подтверждения

Подтверждённая версия доступна только для чтения. Изменение создаёт новую версию или отдельный запрос. Этапы: «Принят», «Комплектуется», «Готов», «Передан».

Результат: участники смотрят один заказ, без звонков за статусом.

Главный интерфейс: рабочая область заказа

После входа закупщик возвращается в последний активный заказ или в список с явным следующим действием. Сводные графики не являются точкой входа.

Четыре зоны экрана: шапка (организация, адрес получения, способ комплектации, ответственный, общий статус); таблица строк (товар, количество, упаковка, доступность, склад, совместимость, состояние); панель исключений — только то, что мешает подтверждению; история решений.

Главное действие зависит от состояния: «Исправить 3 исключения», затем «Отправить на резерв», затем «Подтвердить заказ». Пользователь не угадывает следующий шаг.

Рабочая область заказа: строки, исключения и следующее действие

Каталог в контексте этого заказа

Пользователь видит разрешённый ассортимент, доступность по складам и документы. Поиск понимает артикул, фрагмент названия и ключевые характеристики. Для объёма первой версии достаточно полнотекста и trigram-индексов PostgreSQL.

Карточка помогает принять закупочное решение: характеристики, варианты серии, наличие, кратность, состав комплекта, обязательные и совместимые компоненты, допустимые замены, инструкция и схема, статус жизненного цикла. Совместимость — явные связи: клавиша к серии инсталляции, мебель к ширине раковины и типу монтажа. Если правило нельзя формализовать надёжно, контент-менеджер ставит предупреждение, а не ложный запрет.

Очередь исключений для менеджера

Большинство корректных заказов проходят без участия менеджера. Главный экран — очередь отклонений: какой заказ остановился, что мешает, сколько ждут решения, какое действие ожидается. Та же логика management by exception, что и очередь отклонений клининговой сети, только единица работы здесь — строка дилерского заказа, а не задание на уборку.

Типы исключений: нет допустимой замены, часть количества на другом складе, изменился статус товара, не совпали данные организации, резерв подтвердился частично. При открытии менеджер попадает к проблемной строке. Предлагая замену, он указывает причину и ключевое отличие; дилер видит сравнение. Молчаливой подмены нет.

Очередь менеджера: только заказы с отклонениями и предложение замены внутри заказа

Бизнес-правила

Состояния и версии

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

Упаковка и совместимость

Количество проверяется по кратности; автоматическое округление требует подтверждения. Совместимость пересчитывается при добавлении и при изменении связанной позиции. Замена — только из утверждённой группы аналогов или после предложения менеджера.

Резерв и права

Резерв имеет срок из учётной системы и считается подтверждённым только после её ответа. Права задаются на уровне организации, роли и подразделений. Пользователь дилера не получает данные другой организации даже прямым запросом к идентификатору заказа. Просмотр документов пишется в журнал аудита. Для привилегированных ролей — двухфакторная аутентификация.

MVP

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

В первой версии

Организации, пользователи, роли и приглашения
Каталог с характеристиками, файлами, доступностью и поиском
Рабочая область заказа с версиями и состояниями строк
Базовые правила совместимости, комплектности и кратности упаковки
Разрешённые замены и подтверждение дилером
Резервирование и передача подтверждённого заказа в учёт
Очередь исключений регионального менеджера
Статусы подготовки, уведомления в портале и по почте
Журнал решений и действий

Осознанно отложено

Сложный конструктор проектных спецификаций по помещениям
Нативное мобильное приложение
Прогнозирование спроса и рекомендации по истории
Публичный каталог для конечных покупателей
Чат в реальном времени
Расширенная аналитика по нескольким системам
Внешнее API для крупных дилерских сетей
Автоматическая обработка претензий и возвратов

ИИ не является ключевой частью первой версии. Правила совместимости и замены требуют объяснимых справочников. Позже модель может помогать нормализовать входящие таблицы или искать похожие товары по неполному описанию — с проверкой сотрудника.

UX, стек и план

Рабочая область вместо витрины

Ценность появляется после выбора товара. Закупщик возвращается в заказ и видит исключения и следующее действие. Цвет статуса относится к строке, а не к рекомендации «купить этот артикул».

Архитектура

Выбран профиль единого операционного B2B-приложения: насыщенные таблицы, фильтры и боковые панели без отдельного frontend-сервиса. Обмен с учётом — обмен каталогом, остатками и резервом с учётом: портал получает номенклатуру, доступность, жизненный цикл товара и результат резервирования; обратно передаёт проверенный заказ и идентификаторы подтверждённой версии. Пакет имеет технический идентификатор и журнал ошибок, повторный запуск не создаёт дубликаты.

Client

  • Inertia
  • Vue 3
  • TypeScript
  • адаптивный веб

Быстрое редактирование строк, локальные фильтры и разбор исключений. Inertia сохраняет единый Laravel-репозиторий, сессионную аутентификацию и серверные правила доступа.

API

  • Laravel
  • модульный монолит

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

Data

  • PostgreSQL
  • организации
  • каталог
  • связи
  • версии заказов

Реляционная модель для заказа и журнала. Полнотекст и trigram закрывают поиск без отдельного поискового движка.

Queue / cache

  • Redis
  • Horizon
  • импорт остатков
  • резерв
  • уведомления

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

Storage

  • S3-совместимое хранилище
  • инструкции
  • схемы
  • изображения

Файлы карточек с проверкой прав организации. Доступ к внутренним документам журналируется.

Infrastructure

  • Docker Compose
  • Nginx
  • PHP-FPM
  • workers
  • Pest
  • Playwright

Одинаковое окружение разработки и production. Pest покрывает правила и права. Playwright — критические маршруты заказа и резерва. Микросервисы, отдельный поиск, WebSocket и Kubernetes в MVP не входят.

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

План на 16 недель

Срок первой рабочей версии и пилота — 16 недель. Внедрение начинается не со всех дилеров и категорий: главный риск — качество справочников и параллельный процесс в таблицах.

0 нед 16 нед пилот
  1. 2 нед
    1

    Подготовка данных

    Одна товарная группа: артикулы, характеристики, упаковки, связи комплектов и допустимые замены. Фиксируется контракт обмена с учётом и владение данными.

  2. 3 нед
    2

    Прототип процесса

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

  3. 6 нед
    3

    Разработка ядра

    Роли, каталог, заказ, версии, проверки и очередь исключений. Интеграция сначала на тестовых пакетах, затем тестовый контур учёта.

  4. 3 нед
    4

    Пилот

    Ограниченная группа дилеров и одна категория. Старый канал — только аварийный. Ежедневный разбор причин, по которым заказ не удалось завершить в портале.

  5. 2 нед
    5

    Стабилизация

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

Метрики

Цифры — результаты пилота на одной товарной категории и сопоставимых типах заказов: повторное пополнение матрицы до запуска и после стабилизации процесса. Заказы, сознательно проведённые по аварийному каналу из-за недоступной категории или длительного сбоя обмена, из сравнения исключались.

МетрикаСостояние доСтало в пилотеКак измеряется
Время сборки типового повторного заказа45–70 минут15–25 минутМедиана от создания черновика до отправки на резерв
Ручные уточнения вне заказа4–7 на заказ1–2Письма, звонки и сообщения по выборке заказов пилота
Повторный ввод строкпочти в каждом заказене требуется для заказов из порталаСравнение источника и записи в учётной системе
Доля заказов без понятного следующего действияне фиксируетсяменее 5% активныхСрез заказов без системного статуса или ответственного
Время обнаружения блокирующего исключенияпосле ручной проверки менеджеромпри добавлении позиции или ответе интеграцииЖурнал событий заказа
Полнота истории решений по заменамзависит от переписки100% замен из порталаАудит подтверждённых версий: автор и подтверждение

Риски и выводы

Риски

РискВероятностьВлияниеСнижение
В справочнике недостаточно характеристик для совместимостиВысокаяВысокоеОдна категория, владелец данных, предупреждение вместо ложного запрета
Остатки обновляются с задержкойСредняяВысокоеПоказывать время снимка, считать резерв подтверждённым только после ответа учёта
Менеджеры продолжают принимать заказы в сообщенияхВысокаяВысокоеПортал как основной канал пилота, исключения только внутри заказа
Дилер воспринимает проверки как препятствиеСредняяСреднееПричина каждого ограничения и конкретное следующее действие
Интеграция возвращает частичные или дублирующиеся ответыСредняяВысокоеИдемпотентность, технические идентификаторы, повторные задания, журнал обмена
Права организации настроены неверноНизкаяВысокоеАвтотесты изоляции, минимальные права, аудит доступа

Развитие после пилота

  1. Шаблоны ассортиментных матриц по типам дилеров.
  2. Проектные заказы с группировкой по помещениям — после устойчивого простого заказа.
  3. Загрузка дилерской таблицы с предварительным сопоставлением артикулов.
  4. API для сетей, которые формируют заказ в собственной системе.
  5. Претензии с привязкой к строке поставки и документам.
  6. Рекомендации комплектов на основе правил и истории, без автоматического применения.
  7. Аналитика причин остановки заказов для справочников и ассортимента.

Как изменилась работа

До

  • заказ жил в таблице, письме и учёте;
  • остатки уточнялись звонком;
  • замены оставались в переписке;
  • менеджер правил формат данных;
  • неполный комплект находили после отгрузки;
  • повторный заказ собирался с нуля;
  • руководитель видел нагрузку, но не типы исключений.

После

  • одна версия заказа с состояниями строк;
  • доступность и упаковка видны при выборе;
  • замена имеет автора и подтверждение;
  • менеджер разбирает короткую очередь отклонений;
  • совместимость проверяется до резерва;
  • повтор идёт из завершённого заказа;
  • подтверждённый состав восстанавливается без поиска файла.

Главный результат — не перенос формы заказа в браузер. Портал создаёт общий операционный контур между дилером и дистрибьютором: состояние каждой позиции объяснимо, следующее действие видно, подтверждённый состав можно восстановить без звонков.

Обратная связь после внедрения

Сжатая цитата из обратной связи после пилотного внедрения. Название компании и имя не указаны из‑за NDA.

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

Менеджер дилерского отдела

Обсудить проект

Нужен похожий контур — обсудим. Услуги на Laravel · Каталог решений.

Связаться