Своя CRM для инженерной компании: как мы вдвое сократили цикл сделки

—

от автора

Мы продаём инженерные узлы для отопления и водоснабжения многоэтажек. Каждая сделка — расчёт под конкретный дом, коммерческое предложение, договор, закуп, сборка и отгрузки партиями по графику стройки. Ещё недавно эта цепочка жила в Битрикс24, отдельном калькуляторе, 1С и рабочих чатах.

Мы написали свою CRM. Раньше от заявки до подписанного договора проходило около двух месяцев, теперь — около месяца: сделки закрываются примерно вдвое быстрее. Сильнее всего сократился первый отрезок: раньше КП уходило заказчику через 3–4 дня после заявки, теперь — на следующий день. Ниже — где на самом деле терялось время, что мы для этого сделали и на какие грабли наступили.

Кто мы и что продаём

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

Узел собирается под этаж: число квартир задаёт число выходов, дальше следуют диаметры, балансировка, бренд арматуры. Один дом — это десятки узлов и тысячи фитингов: в одном реальном КП было 84 узла, в другом — 4 078 ниппелей. Заказчик видит в КП готовый узел с шифром, а снабжению и складу нужна каждая деталь внутри.

Ещё три обстоятельства, без которых дальше не понять:

  • Три юрлица. Два ТОО продают, третье ведёт монтаж. Учёт — в 1С.

  • Поставка партиями. Договор живёт месяцами: график отгрузок идёт за стройкой и меняется вместе с ней.

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

Где терялось время

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

До своей CRM сделка жила в четырёх местах:

  • Битрикс24 — сделки и контакты. У инженеров, снабжения и склада там своего места не было.

  • Калькулятор инженеров — отдельное браузерное приложение. Состав и сумма из него переезжали в сделку и в КП.

  • 1С — счета, реализации, поступления. Данные сделки вносили туда ещё раз.

  • Чаты — всё остальное: «посчитай», «согласуй», «что с договором?», «когда отгрузка?».

Отсюда три вида потерь.

Ожидание на передаче. Менеджер ждёт расчёт, а инженер не знает, что его ждут. КП готово, но коммерческий директор увидит его, когда долистает чат. Каждая передача — это ожидание, а передач до первой отгрузки семь.

Восемь шагов и семь передач. До CRM ни одна передача не сигналила сама: следующий узнавал о своём ходе из чата или звонка.

Перенос руками. Калькулятор → сделка → КП → 1С. Каждый перенос — время и шанс ошибиться. В одном КП из старого калькулятора 12 узлов ушли по 194 ₸ вместо 262 763 ₸ за штуку. Недобор — 3,15 млн ₸, около 15% суммы, а в строке «ИТОГО» стояло 68 узлов вместо 84. Причина нашлась позже: калькулятор молча ставил 0 ₸ детали без привязки к каталогу.

Никто не знает, у кого сделка. Чтобы ответить на «на чём застряли?», руководитель обзванивал людей. Стадия в Битриксе показывала, где сделка была вчера, а не чей сейчас ход.

Почему своё, а не коробка

Коробочная CRM знает сделку и товар, но не знает узел. А у нас всё держится на узле: заказчик покупает его целиком, снабжение закупает по деталям, склад собирает и отгружает партиями по графику стройки. Состав коллекторного узла выводится из параметров этажа по девятнадцати связанным правилам. Допиливать это в Битрикс роботами и смарт‑процессами значило бы держать бизнес‑логику в чужой системе и потом переносить её дважды.

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

Из Битрикса уходим поэтапно: сначала зеркалим его сделки, потом синхронизируем в обе стороны, потом сами становимся мастером. Критерий перехода между этапами — не технический: месяц без жалоб «а в Битриксе было удобнее». Резкий переезд убил бы продажи: менеджеры там живут.

Стек скучный, и это специально:

Слой

Чем сделан

Бэкенд

PHP 8.3, Laravel 13, модули по предметным областям (CRM, продажи, калькулятор, закуп, склад, исполнение, интеграции и др.)

База

PostgreSQL, около 116 таблиц

Фронтенд

Vue 3, PrimeVue 4, Vite

Телефон

PWA с Web Push — без отдельного мобильного приложения

Интеграции

1С по OData, Битрикс24 по REST и вебхукам

Тесты

около 1 600 автотестов + сквозной прогон по ролям в браузере

Что сделали

Мы били по передачам. Цель — чтобы человек узнавал, что ход за ним, в ту же минуту и попадал на экран, где нужная кнопка уже под рукой.

1. «Мой день» вместо чатов

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

Карточка ведёт не в сделку вообще, а на вкладку с нужной кнопкой. Это проверяет робот в браузере: до правки сразу на нужную кнопку вели 3 карточки из 8, после — 7 из 8.

2. Пуш на каждое новое дело

CRM ставится на телефон как PWA, отдельного приложения нет. Раз в минуту сервер собирает «Мой день» каждого сотрудника и сравнивает со снимком. Появилось новое дело — уходит Web Push на iPhone или Android.

Две детали, без которых это не работает:

  • Каждая строка карточки отдаёт стабильный id: сущность плюс номер, а для события — ещё и состояние. Иначе сравнение снимков либо молчит, либо спамит.

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

3. «Что дальше» в шапке сделки и договора

Под шапкой сделки одна строка в одном из трёх состояний: «сделайте вот это», «ждём такого‑то» или «готово». На вопрос «у кого сделка» теперь отвечает экран, а не телефон. Правило интерфейса: подпись кнопки в этой строке слово в слово совпадает с подписью на вкладке, потому что человек ищет глазами ту же надпись.

4. Расчёт → спецификация → КП без перепечатки

Калькулятор теперь внутри CRM. Менеджер запрашивает расчёт прямо из сделки: раздел, срок «нужен к», пояснение. Инженер получает карточку и пуш. Готовый расчёт он замораживает версией, и дальше всё читает этот снимок: спецификация, КП в PDF, потом закуп и сборка.

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

5. Три способа получить работу — намеренно

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

Кто

Как получает работу

Почему так

Менеджер

закреплён за сделкой, передаёт главный менеджер

сделка длинная, у заказчика один собеседник

Инженер

расчёт назначает главный инженер

загрузку знает только он; сам инженер выберет проект по вкусу

Снабжение, склад

берут сами кнопкой «Беру»

раздавать заявки по одной некому, а справится любой

6. Решения в одном месте

Согласование КП и договора — одна карточка «Ждут вашего решения» и две кнопки на всех экранах: «Согласовать» и «Вернуть». Вернуть можно только с причиной — иначе автор идёт в чат спрашивать «а что не так?», и передача снова висит.

7. Заявка по ссылке

Первую передачу мы отдали заказчику. Менеджер отправляет ссылку, заказчик сам заполняет объект и контакты, и сделка появляется в CRM уже с данными — без переписывания из письма.

Откуда «вдвое»

Отрезок

Было

Стало

От заявки до КП у заказчика

3–4 дня

около 1 дня

От заявки до подписанного договора

около 2 месяцев

около 1 месяца

Это оценка команды по сделкам, а не строгий замер. И оговорка: «на 50% меньше времени» — это и есть «в два раза быстрее». А «на 50% быстрее» значило бы в полтора раза.

КП ускорилось в 3–4 раза, а весь цикл — в два. Разница понятна: дальше по цепочке много времени уходит на сторону заказчика — переговоры, его юристов, его бюджет. На это CRM почти не влияет.

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

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

Грабли

«Готово» в дорожной карте — не значит «работает»

На аудите выяснилось, что сделка ни разу не прошла цепочку целиком. Все пункты дорожной карты стояли с галочками, тесты были зелёными. Но тесты звали сервер с параметрами, которых интерфейс не шлёт, и тупики прошли мимо CI. Из интерфейса сделка доходила до КП, а после договора в базе не было ни одной записи.

Помогли две вещи. HTTP‑тесты пишем «как шлёт интерфейс», а не «как удобно тесту». И регулярно гоняем сквозной прогон по ролям в браузере, с подменной 1С. Первый такой прогон дал 15 находок. В боевой базе есть галочка «Прогон»: такая сделка живёт на отдельном складе и в 1С ничего не отправляет.

1С по OData врёт с кодом 200

Все пять ловушек мы нашли на живой базе, а не в документации:

  • Страницы без $orderby приходят в произвольном порядке. Из 4 550 позиций справочника дошло 1 177 уникальных. При этом строк было ровно 4 550, и с $count всё сходилось. Сверяйте число уникальных ключей, а не строк.

  • If-Match игнорируется. PATCH с чужой версией отвечает 200 и пишет. Версию сверяем сами чтением в том же сеансе.

  • Длины режутся молча. Номер документа — 11 знаков, и «ОТ-2026-1000» станет «ОТ-2026-100», обновив чужой документ. В $metadata длин нет, мы добыли их опытом.

  • Сумма документа не пишется. PATCH отвечает 200, значение остаётся нулём.

  • Даты уходят без зоны. Платформа читает присланное смещение как своё.

Поэтому правила обмена жёсткие. Метода DELETE в клиенте нет физически. Документы создаём только непроведёнными — проводит бухгалтер. Перед любой правкой спрашиваем, не проведён ли документ. Оплаты только читаем, регистры не трогаем. Запись в боевую 1С пока выключена.

Артикул — не ключ

Номенклатуру из 1С мы сначала сопоставляли по артикулу. Оказалось, что один артикул стоит у 52 разных позиций: тройники, гильзы, угольники. При первом приёме 197 карточек свернулись в 115 наших позиций. Ошибки в коде не было — негодной оказалась сама предпосылка. Теперь артикул — подсказка для человека, а не тождество. Проверка в одну строку: число непустых артикулов против числа различных.

Гонка на остатках

Склад списывал остаток по схеме «прочитал — проверил — записал» без блокировки. Две одновременные выдачи одной позиции обе проходили проверку и затирали друг друга. Транзакция не спасает: уровень READ COMMITTED в PostgreSQL от такой потери не защищает. Такое расхождение всплывает только на инвентаризации. Закрыли SELECT … FOR UPDATE на строке остатка.

Два калькулятора не сверить чтением кода

Новый калькулятор должен был считать как старый, только без его ошибок. Два дня мы сверяли исходники построчно и пропустили 9 расхождений: значения по умолчанию, умножение количеств, связи между полями. Сработало другое: гонять оба движка на одних данных и сравнивать результат. Эталоном стало реальное КП: 23 шифра узлов с ценами, новый движок восстанавливает все 23. Именно так и нашлись те самые узлы по 194 ₸.

Итоги

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

Если вы думаете о своей CRM для сложного товара, вот что мы бы сделали с самого начала:

  1. Нарисуйте передачи, а не стадии. Стадия говорит, где сделка. Передача говорит, кто её сейчас держит. Время теряется на втором.

  2. Начинайте с экрана «что мне сегодня делать», а не со списка сделок. Список сделок нужен руководителю. Исполнителю нужен список дел.

  3. Один источник данных от расчёта до отгрузки. Замороженная версия расчёта кормит и КП, и закуп, и сборку. Любой ручной перенос рано или поздно даст свои 194 ₸.

  4. Тестируйте сделку целиком, глазами каждой роли. Зелёный CI и галочки в дорожной карте ничего не говорят о том, дойдёт ли сделка до отгрузки.

  5. В 1С пишите непроведённым и не верьте коду 200. Проверяйте записанное обратным чтением.

Дальше в планах: счета поставщиков и согласование оплат в закупе, лиды из WhatsApp и полный уход из Битрикса. Через квартал вернёмся с точным замером. Вопросы про архитектуру, 1С и калькулятор — в комментарии.

ссылка на оригинал статьи https://habr.com/ru/articles/1095456/