Ezeden изнутри: цены, остатки и B2B, которые работают по правилам
Магазин с тысячами товаров от нескольких поставщиков невозможно вести вручную, а одна ошибочная цифра в прайсе поставщика может отправить товар в продажу в убыток. Хаб Ezeden превращает цены, остатки, аксессуары и условия для компаний в правила, которые менеджер задаёт один раз и проверяет до того, как они сработают.
Задача
Ezeden продаёт тысячи товаров от многих поставщиков, и вручную вести цены и остатки такого каталога невозможно. Закупочные цены приходят в евро, долларах и гривнах, в прайсах поставщиков бывают ошибки, а остатки поставщика отстают от реальности. Компаниям нужны свои цены и нормальное коммерческое предложение. Нужна была система, в которой владелец один раз задаёт политику - наценку, округление, сколько товара придержать, - а программа применяет её к каждому товару. Всё необычное при этом останавливается и ждёт человека.
Цены: правила вместо таблиц
Наценка задаётся правилами. Правило действует на весь каталог, бренд, категорию с подкатегориями, поставщика, диапазон закупочной цены, группу вариантов или один товар, а его формула - процент, фиксированная сумма или минимальная маржа. Если подходят несколько правил, побеждает более приоритетное, при равном приоритете - более узкое.
У каждого канала продаж - витрины и маркетплейсов - может быть своя поправка в процентах. Официальный курс Национального банка Украины загружается каждый день, поверх него можно задать коэффициент, а ручной курс можно ввести в любой момент. Цены можно не округлять или округлять до целых гривен, до ,99 или до десятков - по умолчанию и для отдельного правила.
Перед сохранением правила предпросмотр показывает все товары, которые оно затронет, с текущей и новой ценой. В карточке товара вкладка цен отвечает на вопрос “почему такая цена”: какое правило, какой курс, какая поправка канала - по шагам. Каждое изменение остаётся в истории товара с автором: правило, курс, менеджер или прайс поставщика.
Удержание подозрительных скачков
Если цена должна измениться больше чем на заданный порог - по умолчанию 30 %, - изменение не применяется. Оно ждёт в очереди со старым и новым значением, пока менеджер его не подтвердит или не отклонит. Так ловятся и битый прайс поставщика, и опечатка в правиле, и резкое движение валюты; курс, который скакнул слишком сильно, удерживается точно так же. Менеджер может и сам задать цену и закрепить её, чтобы правила и курс её больше не трогали.
Акции с честной старой ценой
У акции есть цена и сроки, для всех каналов или для одного, а на витрине идёт обратный отсчёт. Зачёркнутая цена - это самая низкая публичная цена за 30 дней до начала акции, она же подписана под ценой как “предыдущая цена”. Если цену подняли незадолго до скидки, это не скидка, и ничего не зачёркивается. Акция отсчитывается от дня, когда она началась, даже если её сумма в гривнах потом меняется вместе с курсом евро, поэтому скидка 25 % так и показывается как 25 %.
Остатки: журнал, а не цифра
Хаб ведёт журнал: последнюю цифру, которую прислал источник, и каждое движение после неё - приход, списание, возврат, резерв. Продать можно физический остаток минус активные резервы.
Заказ сразу резервирует товар. Отгрузка списывает резерв, отмена снимает его, а неоплаченный онлайн-заказ освобождает товар сам через заданное число часов.
У каждого канала может быть свой буфер: канал придерживает фиксированное количество или процент и имеет порог, ниже которого считает, что товара нет. Проверка корзины и резерв заказа идут по одному правилу, так что покупатель не сможет заказать больше, чем канал вправе продать. На импорте стоит страховка: если источник за один прогон вдруг обнуляет большую часть товаров, импорт удерживается, а не опустошает магазин.
У каждого товара один из пяти статусов: в наличии; ожидается поставка (сейчас нет, но магазин держит его в постоянном наличии); под заказ (нет, но можно заказать у производителя); нет в наличии; снят с производства. Можно ли заказать товар, указывается один раз для поставщика или бренда, а на товарах отмечаются только исключения. У снятой с производства модели вместо кнопки “Купить” показываются аналоги.
Совместимые аксессуары по характеристикам
Связи между товарами и аксессуарами строятся правилами, а не вбиваются вручную. Правило читается как фраза: товары из этой выборки подходят к товарам из той, когда совпадают вот эти характеристики - есть общее значение, не меньше, не больше или отличаются не более чем на допуск. Единицы пересчитываются, так что миллиметры и сантиметры сравниваются правильно, а правило, сравнивающее несравнимое, не сохранится.
Связи пересобираются каждую ночь, а предпросмотр показывает, что правило найдёт для одного артикула. Связи, созданные менеджером, никогда не перезаписываются, а сгенерированную пару, с которой менеджер не согласен, можно вычеркнуть навсегда. Товары, по которым правило не может решить из-за пустой характеристики, попадают в очередь. По желанию - по умолчанию это выключено - ИИ может поискать недостающий факт в документации производителя, но найденное ждёт менеджера, и что к чему подходит, ИИ не решает никогда.
Кабинет для компаний
У покупателя могут быть персональные цены: он может входить в группу цен - дилер, партнёр и так далее - и иметь собственные условия на бренд, категорию или товар. Действует самое конкретное условие, и цена никогда не выше публичной. На витрине она подписана “Ваша цена”, и та же сумма попадает в корзину и в заказ.
Компания работает в кабинете как организация с реквизитами, адресами доставки и сотрудниками в ролях: владелец ведёт карточку компании, закупщик оформляет заказы, наблюдатель только видит историю.
Коммерческое предложение покупатель запрашивает из корзины, или менеджер составляет его в админке. Каждый выпуск - зафиксированная версия со сроком действия и своим PDF. Покупатель принимает или отклоняет КП в кабинете, а принятое превращается в заказ по ценам из предложения. Если в этот момент товара не хватает, КП остаётся принятым, недостача записывается, и оно ждёт в очереди менеджера, пока товар не поступит.
За этим не нужно следить
Каждые пять минут проверяются база данных, очереди, упавшие задачи, коннекторы, задержки импорта, место на диске, поиск, витрина и резервные копии. Проблема открывает оповещение на почту и в Telegram, ухудшение поднимает его уровень, а восстановление тоже сообщается. Каждый сотрудник в пару кликов подключает свои чаты в Telegram и выбирает, что получать, - новые заказы, отчёты импорта, оповещения, утреннюю сводку, - и может ограничить это рабочими часами; то, что пришло вне них, не теряется, а доставляется позже.
База данных и исходные фото и документы каждую ночь копируются в отдельное объектное хранилище и хранятся не меньше 30 дней. Раз в квартал проводится проверочное восстановление во временную копию, не задевая работающий магазин, а настоящее восстановление можно запустить с экрана админки и отменить.
Рабочее место менеджера
На главном экране - только очереди задач, в которых что-то ждёт: удержанные цены, новые заказы, неудачные оплаты, отзывы, переводы, удержанные импорты, и каждая роль видит только свои. Все таблицы админки живые: когда импорт, фоновая задача или другой менеджер что-то меняют, каждый открытый экран с этими данными обновляется сам. Одно поле поиска находит заказы, товары, покупателей и КП и отвечает только тем, что человеку разрешено видеть. Каждое изменение есть в истории с автором, а целый импорт или массовую правку можно откатить.
Технологии
- Хаб: Laravel 13 + Inertia + React 19 + Ant Design
- Витрина: Laravel 13 + Inertia + React 19, серверный рендеринг
- Данные: MySQL 8.4, Redis 7
- Фоновые задачи: Laravel Horizon (очереди), Reverb (живые экраны админки)
- Интеграции: курсы Нацбанка Украины, Telegram-бот, S3-совместимое хранилище для копий
- Инфраструктура: Docker Compose, GitLab CI/CDРезультат
Цены, остатки, аксессуары и условия для компаний - это правила, которые владелец может прочитать и поменять без программиста, а любую цену на сайте можно объяснить по шагам. Необычные изменения останавливаются и ждут человека, а не уходят к покупателям. У компаний есть свои цены и нормальные коммерческие предложения, а команда узнаёт о проблемах из Telegram, а не от клиентов.



