Почти любой современный бизнес, когда приходит время выстраивать отношения с клиентами, полагается на CRM-системы (Customer Relationship Management). И сталкивается с тем, что ожидания не совпадают с реальностью: эффективность не такая высокая, да и управление данными кажется слишком сложным. Один из способов решить эти проблемы — интегрировать сервис со своим веб-приложением.
Привет! Меня зовут Денис, я Python-разработчик в Kokoc Group. Уже около года занимаюсь интеграцией одной из наших платформ на Django с Zoho CRM. Мы соединяем пользователей с широким спектром услуг, требования к обработке заявок и управлению партнерскими и пользовательскими профилями высокие, поэтому Zoho CRM стала ключевым элементом.
В статье хочу показать, как провести ее и сделать процессы проще и эффективнее. Мы рассмотрим все этапы: от подготовки среды до настройки вебхуков и асинхронной обработки данных с помощью Celery. Советую почитать всем разработчикам и менеджерам, так или иначе связанным с работой в CRM-системах.
О чем поговорим:
-
Как подготовить CRM и Django-приложение к интеграции.
-
Как взаимодействовать с API Zoho CRM через Python.
-
Как настроить правила рабочего процесса в Zoho CRM для отправки данных в Django-приложение.
-
Как обработать данные, полученные от вебхука Zoho CRM, и обновить базу данных Django.
-
Как использовать Celery для асинхронной обработки данных из Zoho CRM.
Немного о Zoho CRM
Скрытый текст
Zoho CRM — это комплексная система управления отношениями с клиентами (CRM) от компании Zoho. В ней есть инструменты для управления лидами, контактной информацией, сделками, маркетинговыми кампаниями, обслуживанием клиентов и аналитикой — реализованные, как набор модулей:
-
Лиды (Leads) — модуль для сбора и управления информацией о потенциальных клиентах.
-
Контакты (Contacts) — модуль для хранения контактной информации о клиентах как физических лицах.
-
Аккаунты (Accounts) — модуль для хранения информации о компаниях, с которыми вы взаимодействуете.
-
Продукты (Products) — модуль для хранения информации о продуктах компании.
-
Сделки (Deals) — Модуль для отслеживания прогресса продаж и управления сделками.
Стандартные модули можно редактировать, как и добавлять новые под свои бизнес-процессы. Еще один плюс — интеграция с другими продуктами Zoho: Zoho Mail, Zoho Campaigns, Zoho Desk, Zoho Books — из которых можно собрать полноценную платформу для управления бизнесом.
Готовим CRM-систему
Первым делом нужно зарегистрироваться с в системе и создать песочницу (дальше работать будем уже в ней).
-
Заводим аккаунт и переходим в настройки:

-
Выбираем Sandbox:

-
Нажимаем Create New Sanbox, заполняем форму, нажимаем Create:

-
Нажимаем Go to sunbox и оказываемся внутри нашей песочницы (о чем говорит флаг на скриншоте):

Получаем ключи API
Для взаимодействия понадобятся ключи. Идем сюда: https://api-console.zoho.eu/:

-
Выбираем Self Client, нажимаем Create:

-
Записываем вот эти значения — они еще понадобятся:

Указываем Scope
В API Zoho, он определяет разрешения, которые приложение запрашивает для доступа к различным ресурсам (подробнее советую почитать тут: https://www.zoho.com/crm/developer/docs/api/v6/scopes.html).
Мы возьмем «ZohoCRM.modules.ALL», который дает доступ ко всем модулям в Zoho CRM. То есть приложение сможет выполнять операции (чтение, создание, обновление, удаление) с любыми модулями: контактами, сделками, компаниями и прочим.
-
Нажимаем Create и выбираем кабинет, для которого создается ключ:

-
Выбираем, для какой версии CRM создать токен: для производственной или песочницы. Фича удобная: достаточно взять однажды все токены и больше не возвращаться к этому вопросу.
Получаем токены
Отправляем POST-запрос на этот url со следующими параметрами. Пример:
Заменить токены на условные <token>
https://accounts.zoho.eu/oauth/v2/token?client_id=<client_id>&client_secredt=<client_secret>&code=<token>&grant_type=authorizationcode
В ответ нам придет access_token и refresh_token. Сохраняем и идем дальше.
Готовим Django-приложение
Первым делом устанавливаем пакеты, которые понадобятся для работы:
-
Django — основной фреймворк для разработки веб-приложений.
-
djangorestframework — пакет для создания API.
-
requests — библиотека для отправки HTTP-запросов.
-
Celery — система для создания и обработки асинхронных задач.
Далее прописываем модели, я для примера буду использовать эти:
-
Расширенная модель юзера:
class User(AbstractBaseUser): first_name = models.CharField(_('first name'), max_length=30, blank=True, null=True) last_name = models.CharField(_('last name'), max_length=30, blank=True, null=True) phone_number = models.CharField(_('phone number'), max_length=20, unique=True) email = models.EmailField(_('email address'), unique=True) USERNAME_FIELD = 'email' objects = UserManager() class Meta: verbose_name = _('User') verbose_name_plural = _('Users')
-
Модель продукта:
class Product(models.Model): name = models.CharField(verbose_name=_("Product name"), max_length=200) description = models.TextField(verbose_name=_("Product description"), blank=True, null=True) price = models.DecimalField(verbose_name=_("Price"), decimal_places=2, max_digits=10) zoho_product_id = models.CharField(verbose_name=_("Zoho product ID"), max_length=50, blank=True, null=True, unique=True) def __str__(self): return self.name
-
Модель ExternalResource. Она нужна для хранения данных, полученных при настройке Zoho CRM (Client ID, Client Secret, access_token, refresh_token):
class ExternalResource(models.Model): name = models.CharField(verbose_name=_("Name"), max_length=200, unique=True) client_id = models.CharField(verbose_name=_("Client ID"), max_length=200, null=True, blank=True) client_secret = models.CharField(verbose_name=_("Client Secret"), max_length=200, null=True, blank=True) token = models.CharField(verbose_name='Token', max_length=256, null=True, blank=True, default=None) refresh_token = models.CharField(verbose_name='Refresh token', max_length=256, null=True, blank=True, default=None) class Meta: verbose_name = _('Third-party service') verbose_name_plural = _('Third-party services') @classmethod def get_zoho(cls): return cls.objects.get(name='ZohoAPI')
Регистрируем ExternalResource в админке. И создаем объект модели с полученными данными:

Настраиваем взаимодействие с Zoho API. Понадобятся следующие классы:
-
ExternalResourceManager — базовый класс для работы с API внешних сервисов:
class ExternalResourceManager(ABC): """ Базовый класс для работы с API внешних сервисов, таких как ZohoCRM. """ @abstractmethod def db_object(self): """ Метод реализует получение объекта модели ExternalResource """ pass @abstractmethod def send_request(self, method, url, data, **kwargs): """ Метод реализует отправку запроса к внешнему ресурсу """ pass
-
ZohoBaseManager — класс для работы с ZohoCRM API, реализующий методы отправки данных в ZohoCRM и обновления токенов:
class ZohoBaseManager(ExternalResourceManager): @cached_property def db_object(self): return ExternalResource.get_zoho() def send_request(self, method, url, data=None, auth=False, **kwargs): """ Отправка запроса к ZohoCRM API. """ if auth: kwargs.update({"Authorization": f"Zoho-oauthtoken {self.db_object.token}"}) try: response = requests.request(method=method, url=url, data=data, headers=kwargs) except RequestException as e: pass # как то обрабатываем исключение... return response def handle_response(self, response): """ Обработка ответа от API. Проверяем на наличие ошибок и возвращаем необходимые данные. """ if response is None: raise ValueError("Ответ от API отсутствует") try: response_json = response.json() except ValueError: raise ValueError("Невозможно преобразовать ответ в JSON") if response.status_code != 200: error_message = response_json.get('error', 'Неизвестная ошибка') raise Exception(f"Ошибка API: {error_message} (код {response.status_code})") return response_json def update_token(self): """ Отправка запроса к Zoho API для обновления token """ url = 'https://accounts.zoho.eu/oauth/v2/token' data = { 'client_id': self.db_object.client_id, 'client_secret': self.db_object.client_secret, 'refresh_token': self.db_object.refresh_token, 'grant_type': 'refresh_token', } response = self.send_request( method='post', url=url, data=data ) try: response_json = self.handle_response(response) except Exception as e: # как то обрабатываем исключение... return new_token = response_json.get('access_token') self.db_object.token = new_token self.db_object.save()
-
RegistrationDataManager — класс для управления данными при регистрации пользователя.
class RegistrationDataManager(ZohoBaseManager): @staticmethod def get_registration_data(user): data = { "data": [ { 'First_Name': user.first_name, 'Last_Name': user.last_name, 'Email': user.email, 'Mobile': user.phone_number, } ] } return data def create_lead(self, user): """ Отправляет данные для создания лида в ZohoCRM. """ data = self.get_registration_data(user) json_data = json.dumps(data) url = "https://www.zohoapis.eu/crm/v2/Leads" method = 'post' response = self.send_request(method, url, json_data, auth=True) json_response = self.handle_response(response) # Обрабатываем ответ от ZohoCRM (проверяем статус, получаем ID лида и т.д.)
Обеспечиваем бесперебойный доступ к API Zoho CRM
Чтобы доступ оставался постоянным, необходимо обновлять токен. Напишем задачу, которая будет делать это за нас каждые 10 минут.
-
Создаем Celery-таск, и в нем — экземпляр ZohoBaseManager и вызываем метод update_access_token(), который отвечает за фактическое обновление токена.
@shared_task def refresh_zoho_token(): """Обновляет токен доступа для API Zoho CRM.""" manager = ZohoBaseManager() manager.update_token token()
-
Настраиваем расписание для выполнения задачи в файле settings.py (там будем определять, как часто вызывается задача). Создаем запись для задачи refresh_zoho_token в словаре CELERY_BEAT_SCHEDULE:
CELERY_BEAT_SCHEDULE = { 'refresh_zoho_token': { 'task': 'zoho_integration.tasks.refresh_zoho_token', 'schedule': crontab(minute='*/10'), 'args': (), 'kwargs': {}, 'options': { 'expires': 60.0, }, }, }
Что именно прописали
Скрытый текст
-
task — указывает путь к нашей задаче.
-
schedule — использует crontab(minute=’*/10′), то есть “выполнение задачи каждые 10 минут”.
-
args и kwargs — пустые, так как задача не требует дополнительных параметров.
-
options — гарантирует, что если задача не будет выполнена в течение минуты, то станет считаться устаревшей и отменится.
Создаем лида в ZohoCRM при регистрации пользователя
Здесь все просто:
-
Используем Django-сигналы, чтобы отслеживать создание пользователей:
@receiver(post_save, sender=User) def send_user_data(sender, instance, created, **kwargs): if created: create_zoho_lead.delay(instance.id)
-
Используем Celery-задачи для асинхронной отправки данных в Zoho CRM:
@shared_task def create_zoho_lead(user_id: int) -> None: try: user = User.objects.get(pk=user_id) except User.DoesNotExist: return manager = RegistrationDataManager() manager.create_lead(user)
Вот и все, теперь при каждой регистрации данные о пользователе будут отправляться в ZohoCRM.
Проводим интеграцию с помощью Workflow Rules
Представим, что каждый раз, когда в Zoho создается или обновляется продукт, нам нужно забирать его в свою базу данных. Реализовать это можно как правила рабочего процесса и функций в Zoho CRM.
Подробнее о правила рабочего процесса
Скрытый текст
В Zoho CRM, Workflow Rules —- это по сути триггеры, которые автоматизируют задачи. Правила могут срабатывать автоматически в конкретное время или запускаются, когда:
-
создается новая запись;
-
обновляется существующая запись;
-
удаляется запись;
-
создаются, изменяются, удаляются примечания к записи.
Создадим правило, которое при создании или обновлении продукта будет присылать нам данные по нему и обновлять значение в базе.
-
Переходим в настройки и нажимаем на вкладку Workflow Rules:

-
Create Rule и заполняем форму:

-
Нажимаем Next и попадаем на эту страницу:

-
В первом селекте выбираем Record Action. Во втором — Create or Edit и Repeat this workflow whenever a Product is edited. Эти настройки говорят о том, что правило будет срабатывать при каждом редактировании записи:

-
Нажимаем Next, выбираем All Products (так правило будет применяться ко всем записям):

-
Выбираем, какое именно действие будет происходить. В нашем случае — Function :

-
В появившемся окне выбираем Write your own:

-
Заполняем форму и нажимаем Create:

-
Попадаем на страницу создания функции:

Разберем типичную функцию в Zoho CRM
Что это вообще такое?
Скрытый текст
Это фрагменты кода, написанные на языке Deluge. Deluge разработан специально для Zoho CRM и позволяет выполнять операции более сложные, чем простое изменение полей или отправка писем. Вот пара примеров:
-
Обработка данных. Вы можете манипулировать данными из разных записей, использовать условные операторы и циклы для логического управления потоком выполнения.
-
Вызов API. Вы можете использовать функции для вызова внешних API, например, для получения данных из других сервисов или для отправки запросов в приложение.
В качестве примера возьмем функцию, которая будет отправлять данные о продукте из Zoho CRM в наше Django-приложение.
-
Указываем, что функция принимает ID записи, и нажимаем Edit Arguments:

-
В появившемся окне, в поле Argument Name задаем имя аргумента. В поле Argument Value вводим «#». Выбираем Product Id. Нажимаем Save:

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

Напишем view, которая будет принимать запрос
View
class ZohoProductView(APIView) serializer_class = ZohoProductSerializer permission_classes = (CheckZohoTokenPermission,) def post(self, request): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) sync_product.delay(data=serializer.validated_data) return Response(serializer.data, status=status.HTTP_202_ACCEPTED
Serializer
class ZohoProductSerializer(serializers.Serializer): zoho_product_id = serializers.CharField() name = serializers.CharField() description = serializers.CharField() price = serializers.DecimalField(max_digits=10, decimal_places=2)
Permission
class CheckZohoTokenPermission(BasePermission): def has_permission(self, request, view): if request.META.get("HTTP_ZOHO_REQUEST_AUTH_TOKEN") == settings.ZOHO_REQUEST_AUTH_TOKEN: return True
Celery Task
@shared_task def sync_product(data): zoho_product_id = data.get("zoho_product_id") product = Product.objects.filter(zoho_product_id=zoho_product_id) if product.exists(): product.update(**data) else: Product.objects.create(**data)
Теперь, когда в Zoho CRM, в модуле Products будет создаваться или редактироваться запись, сработает правило и система вызовет нужную функцию. Функция в свою очередь отправит данные на наш Django API-endpoint, который принимает данные о продукте и передает их на обработку в Celery-задачу sync_product. Задача проверит наличие продукта в базе данных по zoho_product_id.
Наконец, если продукт существует, данные обновятся. Если нет — появится новый объект Product с полученными данными.
Такой подход обеспечивает синхронность Zoho CRM и Django-приложением, то есть все изменения в данных продуктов будут отражены в обеих системах.
Заключение
Я постарался максимально полно показать, как интегрировать Zoho CRM с Django-приложением для автоматизации работы с данными о клиентах и продуктах. Но важно помнить, что эта статья — лишь начало, и интеграция с Zoho CRM — это гибкий и мощный инструмент, который можно настроить под любые потребности. Экспериментируйте, чтобы сделать сделать свой бизнес еще эффективнее.
И пара советов напоследок:
-
Добавьте логирование, чтобы отслеживать ошибки и успешную обработку данных.
-
Документируйте код. Это поможет и вам, и вашей команде лучше ориентироваться в структуре интеграции и легко вносить изменения в будущем.
-
Тестируйте. Это поможет убедиться, что интеграция работает корректно и изменения не нарушат ее работу.
-
Изучите документацию Zoho CRM и Django. В них вы найдете много полезной информации, которая поможет реализовать более сложные сценарии.
ссылка на оригинал статьи https://habr.com/ru/articles/861430/



Добавить комментарий