Привет! Меня зовут Данила Соловьёв, я руковожу направлением PHP — самым крупным подразделением в отделе разработки AGIMA. Поделюсь историей о том, как мы встроили новую CRM-систему в два абсолютно незнакомых нам IT-ландшафта и тем самым спасли сейлзов двух крупных интернет-магазинов от бесконечных табличек в почте. Подробно опишу, какие данные мы выгружали, как их дедуплицировали и какие сервисы использовали для их валидации. Поехали!

Предпосылки. Как появилась задача?

Два федеральных интернет-магазина, для удобства назовем их А и Б. В каждом независимо друг от друга велась клиентская база юридических лиц с накопленными данными за весь период работы.

Работа с B2B-клиентами происходила по принципу «всё в почте». Менеджеры по продажам пересылают кучу неактуальных эксель-таблиц. К таким процессам были готовы не все, и менеджеры часто увольнялись в первые рабочие дни.

Бизнес был настроен изменить данный процесс, автоматизировать все возможные процессы, таким образом активно развивать B2B-направление и инвестировать в него.

Ограничения

Основными ограничения стали: 

  • Срок MVP — полгода (с июня-июля до нового года). Заказчик пришел летом. Релиз-фриз перед новым годом.

  • Бюджет. Лепить огромного, отказоустойчивого и, как следствие, дорогого мастодонта нет возможности. Бизнес хочет тестировать гипотезы, чем быстрее, тем лучше.

Также были сопутствующие ограничения:

  • Сервис одного окна. У менеджеров по продажам должен быть единый инструмент для ведения клиентов. Отправка почты, IP-телефония, формирование отчетов, просмотр всех клиентов и их заказов.

  • Низкий порог входа для менеджеров. Интерфейс системы должен быть прост и интуитивно понятен.

Ключевая задача

Создать единую клиентскую базу юридических лиц и обогатить ее данными из двух существующих баз данных (БД) интернет-магазинов для последующих продаж.

Для этого нужно:

  • Получить необходимый набор данных и сложить в нашу новую систему, чтобы менеджеры могли заходить и работать с ними.

  • Превратить их в сущности CRM. В качестве CRM выбрали решение от Bitrix24.

Выбор Bitrix24 обусловлен ограничениями, которые описаны выше + коробка предлагает достаточно широкий функционал:

  • интеграция с AD/LDAP, которая нам и требовалась в качестве SSO;

  • интеграции с IP-телефониями;

  • интеграция с почтой;

  • понятный и анимированный интерфейс.

Данные. Что выгружаем?

Приступаем к сбору информации о том, что мы хотим видеть в нашей CRM-системе. Определяем основные сущности и их свойства, требуемые для заполнения, а также устанавливаем критерии проверки данных. Таким образом, мы формируем желаемый итог нашей работы.

В рамках Bitrix24 нам предстоит взаимодействовать с двумя основными сущностями:

Компания — информация о юридическом лице, включая организационно-правовую форму, а также банковские реквизиты.

Контакт — карточка с данными о конкретном контактном лице, например менеджере по закупкам. Этот контакт привязан к конкретной компании.

Затем определяем бизнес-требования к Bitrix24:

  • Выгружаются только активные компании.

  • Исключаются дубликаты контактов и компаний.

Этап технического ППО. Работаем в чужой инфраструктуре

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

  • Кто может помочь со стороны интернет-магазинов интегрироваться (конкретные команды и люди)? К кому идти? Кто может рассказать про сетевую связность, про продукты и системы, которые есть внутри каждого из магазинов?

  • Как будет происходить обмен данными? Realtime? Огромные файлы выгрузки? Брокеры сообщений? REST?

  • Потребуются ли доработки со стороны интернет-магазинов?

  • Какой стек технологий потребуется (помимо Bitrix24, PHP и MySQL)?

  • Как оперативно мы должны и можем получать данные (технические возможности)? Важно! Мы не должны нашими обменами положить ни интернет-магазины, ни себя :)

Чтобы разобраться в инфраструктуре, мы встретились с представителями интернет-магазинов и обсудили важные детали:

  • Как забирать данные для каждой сущности (REST, брокеры, файлы и т.д.)? 

  • В каком формате (json, xml, csv и т.д.)?

  • Как оперативно? С какой периодичностью возможен обмен?

Проектирование. Выбор реализации. Архитектура

На этапе ППО мы определили:

  • Способы интеграции.

  • Режимы работы выгрузки. Спойлер: их два (полный и дельта).

  • Способы валидации компаний, чтобы не тащить «мусор» и дубли в новую систему.

  • Как «сырые» данные преобразовывать в сущности CRM.

Механизм: Извлечение. Преобразование. Загрузка

В этом блоке расскажу о том, как мы выгружали данные, и опишу технические моменты.

Для решения задачи было необходимо реализовать два режима выгрузки данных:

  1. Полная выгрузка — все данные за текущий и предыдущие годы.

  2. Выгрузка обновлений — периодически мы должны получать данные о новых компаниях из интернет-магазинов.

Объем данных получился таким:

  • В интернет-магазине А — 75 000 контактов, 53 000 компаний.

  • В интернет-магазине Б — 600 000 контактов, 125 000 компаний.

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

За основу реализации взяли процесс ETL. Аббревиатура ETL (Extract. Transform. Load) означает «Извлечение, Преобразование, Загрузка». Остановимся подробнее на каждом из этапов.

Extract — Извлечение

Это, наверное, самый сложный этап из всех трех, которые нас ждали. 

На данном шаге мы должны реализовать интеграцию с интернет-магазинами для получение «сырых» данных. Важно понимать, что «сырые» они только для новой CRM, в то время как для интернет-магазина это полноценный объем данных в его базе.

Полная выгрузка:

Также мы прикрутили к нашему проекту компонент Symfony Console, чтобы с помощью него запускать полную выгрузку из MySQL и другие фоновые задачи. 

Дельта выгрузка:

  • ИМ А — slave реплика MySQL (cronjob + symfony console command)

  • ИМ Б — kafka (php extension RdKafka + supervisor + symfony console command)

Отдельно остановлюсь на интернет-магазине Б — у них был SAP CRM, где они хранили всех клиентов. У SAP CRM был веб-сервис, который умел продюсировать свои изменения в Kafka. Нам предоставили отдельный топик. Мы на своей стороне реализовали консюмер, для этого нам пришлось установить PHP-расширение RdKafka. Консюмер представлял собой бесконечный цикл, поэтому сверху мы накрыли его еще Supervisor’ом, чтобы он за ним следил, и если падает — переподнимал его. А в сам Supervisor передали команду через Symfony Console.

Transform — Преобразование

Теперь важно реализовать очистку и преобразование данных для будущих сущностей, чтобы они соответствовали потребностям бизнес-модели. Для этого мы:

  • удаляли компании, которые приходили без ИНН;

  • преобразовали кодировку Windows-1251 в UTF-8;

  • преобразовали номера телефонов в общий формат данных;

  • удаляли лишние пробелы из текстовых полей; 

  • контакты и компании укладывали в DTO.

Load — Загрузка

Теперь мы получили очищенные данные и готовы сохранять их в БД как сущности CRM (компании и контакты).

Этот шаг был одинаковым для всех трех источников (БД, Kafka, файлы). Так как мы всё грузим в одно хранилище, организовать надо единообразно. 

Одновременно с этим происходила валидация компаний, т. к. нужны только действующие. Для реализации этого требования мы воспользовались сервисом ЕГРЮЛ, где присутствуют необходимые данные о компаниях. Отмечу, что у Bitrix24 есть готовый модуль «из коробки» для получения сведений из ЕГРЮЛ по ИНН.

Но данные приходили «сырые». Перед тем как сделать запрос в ЕГРЮЛ, мы должны были убедиться, что ИНН валидный. Такой запрос стоил времени, на него уходило 0,4 секунды, что уменьшало скорость обработки выгрузки. Поэтому для ИНН реализовали стандартную проверку на длину и символы: ИНН должен состоять из 10 или 12 цифр. Также реализовали проверку контрольных чисел, она определяет корректность номера ИНН с помощью математической формулы. Данная формула — унифицированная для всех ИНН. 

По итогам проверки в ЕГРЮЛ отправляются запросы только с валидным ИНН, что сократило этап загрузки на 30–40%. Невалидные компании в процессе загрузки складывали в отдельную табличку.

Релизы

Первым релизом мы выпустили выгрузку из интернет-магазина А с общим загрузчиком. 

Вторым релизом вышла дельта из интернет-магазина Б. 

Третьим — полная выгрузка исторических данных из интернет-магазина Б. 

Таким образом, даже на этапе разработки мы непрерывно снабжали новыми данными менеджеров по продажам.

Итоговый стек и архитектура

В ходе проекта нами использовался следующий стек:

  • B2B CRM — Bitrix 24.

  • База данных — MySQL.

  • Брокер сообщений — Kafka.

  • ETL — PHP-пакет flow-php/etl.

  • Большие json — PHP-пакет halaxa/json-machine.

  • Чтение из Slave-реплики — symfony/console + сron.

  • Консюмеры Kafka — symfony/console + supervisor.

Как видим, у нас было три экстрактора: общий для магазина А и два отдельных для магазина Б (один для Kafka, другой для Json). Два трансформера — для каждого магазина свой, они выдавали одинаковые DTO и передавали их в лоадер. Дальше лоадер закидывал всё в B2B CRM.

Заключение

Bitrix24 был успешно доработан. Нам удалось выгрузить свыше 170 000 активных компаний и более 264 000 контактов из обоих интернет-магазинов.

Менеджерам по продажам была предоставлена обширная клиентская база двух интернет-магазинов. Это позволяет эффективно работать со старыми клиентами и добиваться повторных продаж, используя функционал CRM Bitrix24. Все отчеты и аналитические данные стали доступны в один клик. И больше никаких табличек в почте. Ура!

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

Больше о разработке мы рассказываем в нашем телеграм-канале «Заметки тимлида». Приходите обсудить статью. А еще мы раз в месяц проводим закрытые встречи для еком-директоров разных компаний — обсуждаем там насущные проблемы, слушаем доклады и просто знакомимся. Будем рады новым участникам!


Что еще почитать

Комментарии (0)