Repository navigation
CRM
⭐ КП прямо из мессенджера. Во вкладках CRM «КП» и «Подтверждение» — коммерческие предложения, которые ассистент собирает из переписки сам; утвердить их можно и отсюда, и кнопкой в Telegram / командой в WhatsApp. Подробно: KP.
Интеграция с amoCRM v4 API: OAuth2 аутентификация, синхронизация контактов, лидов и задач, автоматическое создание сделок.

Интеграция с amoCRM v4 API через OAuth2 с автоматическим обновлением токенов. Система позволяет:
- Двусторонняя синхронизация: импорт контактов и лидов из amoCRM → экспорт данных из бота в CRM
- Автоматическое создание сделок: при обращении в Telegram бот или виджет
- Webhook-интеграция: получение событий от amoCRM (обновление контактов, сделок, задач)
- Управление воронками: выбор pipeline и статуса для новых лидов
- Docker/VPN proxy: поддержка прокси для работы из контейнера
Управление интеграцией через CrmView.vue с 8 вкладками: Подтверждение (очередь ответов ассистента, открывается первой), КП (коммерческие предложения в PIM), Клиенты (что ассистент помнит о клиентах), Мониторинг (здоровье каналов), Settings (настройки), Kanban (доска сделок), Deals (таблица сделок), Inbox (сообщения). «Подтверждение», «КП», «Клиенты» и «Мониторинг» доступны и без подключённого amoCRM.
Ассистент не отвечает клиенту сам, пока ответ не одобрит человек.
Режим по каналам. Для каждого WhatsApp-номера выбирается режим:
-
Сразу клиенту (
auto, по умолчанию) — как раньше, ответ уходит немедленно. -
Подтверждение (
approval) — ответ ассистента ложится в очередь, а клиент сразу получает только автоответ о приёме («Здравствуйте! Ваше сообщение получено, менеджер ответит вам в ближайшее время.»). Текст автоответа можно задать свой — без цен, товаров, сроков и обещаний. Он уходит один раз на серию сообщений (не чаще раза в 30 минут на номер).
Режим переключается сразу, без перезапуска бота.
Очередь. Карточка показывает, что написал клиент, и ответ ассистента. Действия:
- Отправить — ответ уходит клиенту в WhatsApp.
- Изменить → Отправить с правкой — уходит исправленный текст; исходный черновик остаётся виден под спойлером.
- Отклонить — клиент ничего не получит.
-
Удалить — убрать запись из очереди (только
sales:manage).
Фильтры: ждут / ошибки / отправлены / отклонены / все.
Особенности:
- После правки или отклонения история диалога переписывается под то, что клиент реально получил — ассистент не «помнит» черновик, которого клиент не видел.
- Заметка в сделку amoCRM пишется с отправленным текстом, а не с черновиком.
- Если доставка не удалась (телефон отключён), запись уходит в «Ошибки» с причиной, её можно отправить ещё раз. Двойное нажатие не отправит ответ дважды.
- Если бот не смог связаться с оркестратором, он ведёт себя по последнему известному режиму: в режиме подтверждения ничего не отправляет.
Пока через очередь идёт только WhatsApp; Telegram и виджет — только мониторинг.
Сами КП живут в PIM клиента (ar-gs.ru): там номер, PDF и ссылка для клиента. Секретарь отвечает за то, чего PIM не делает: кто подтвердил КП, как оно дошло до клиента и что делать, пока клиент молчит или срок истекает. Подключение задаётся ключом ARGS_PIM_API_KEY в .env (ключ выпускают в PIM: Настройки → API).
Черновик. Когда клиент в WhatsApp просит КП («пришлите КП», «выставьте счёт»), ассистент читает переписку, находит позиции в каталоге с ценами и создаёт в PIM черновик. Позиции без точного совпадения или без цены в КП не попадают: менеджер видит их отдельным списком «Не вошло в КП». КП можно создать и вручную: кнопка Новое КП, позиции вводятся руками или собираются из диалога по ID сессии.
Подтверждение. Клиенту ничего не уходит без человека. WhatsApp-КП появляется и здесь, и во вкладке «Подтверждение» с пометкой «КП-00XX». Подтверждение в любом из двух мест — одно и то же действие. Ссылка из PIM подставляется в момент отправки, а просроченное КП отправить нельзя. Способы отправки: WhatsApp (через очередь), письмом из PIM (PDF во вложении) или ссылкой, которую менеджер отправит сам.
Действия: изменить текст и способ отправки, сменить срок действия, отклонить, отметить «принято клиентом» или «проиграно», перевыпустить с новым сроком и пересчётом цен по каталогу, открыть PDF или КП в PIM, посмотреть историю. Фильтры: на подтверждении / у клиента / истекли / ошибки / приняты / закрыты.
Срок действия. Варианты 1, 2 и 3 дня, по умолчанию 3 (меняется в настройках вкладки). «N дней» значит: до сегодняшней даты + N включительно, по времени Казахстана. Истёкшее КП не продлевается молча: его нужно перевыпустить, потому что цены и наличие могли измениться.
Таймеры (проверка раз в 10 минут, правила можно добавлять, менять и выключать):
| Таймер по умолчанию | Когда | Что делает |
|---|---|---|
| Черновик ждёт подтверждения | 2 ч после создания | уведомляет менеджера |
| Клиент не открыл КП | 12 ч после отправки | уведомляет менеджера |
| Открыл, но не ответил | 12 ч после просмотра | готовит сообщение клиенту |
| Срок заканчивается | за 6 ч до конца срока | готовит напоминание клиенту |
| КП истекло | сразу после срока | «пересчитать и перевыпустить» |
| Закрыть как проигранное | 72 ч после срока | ставит статус «проиграно» |
Сообщения клиенту от таймеров тоже ждут подтверждения в очереди. Уведомления менеджеру собираются в блоке «Требуют внимания» и дублируются в Telegram.
Синхронизация с PIM. Статусы «отправлено / просмотрено / принято» подтягиваются из PIM. КП, созданные вручную прямо в PIM, тоже попадают во вкладку (за последние 30 дней), и таймеры следят за ними. Если менеджер отправил КП из PIM сам, копия в очереди снимается: дважды КП не уйдёт.
КП в мессенджере. Уведомление о новом черновике приходит в Telegram и на служебные WhatsApp-номера (настройки вкладки: «WhatsApp-номера для уведомлений» и номер-отправитель) и содержит сам КП: что просит клиент, что подобрал ассистент (с тем, как клиент назвал каждую позицию), что не вошло в КП и текст, который уйдёт клиенту. Действовать можно прямо оттуда:
- Telegram — кнопки «✅ Отправить», «✏️ Изменить текст», «❌ Отменить». Для правки бот просит ответить на его сообщение новым текстом и присылает обновлённую карточку.
- WhatsApp — ответом: «ок 18» (отправить), «текст 18: …» (заменить текст, не отправляя), «отмена 18», «кп» (что ждёт подтверждения). «18» — номер КП без нулей; если черновик один, номер можно не писать.
Это те же действия, что на вкладке, и отправку клиенту по-прежнему подтверждает человек. Сообщения со служебных номеров ассистенту не передаются — директор не получит консультацию как клиент.
Каких методов не хватает в API PIM (продление без смены номера, статус «проиграно», удаление черновика, уведомления), описано для разработчика PIM в docs/pim-api-for-kp.md. Секретарь начнёт пользоваться этими методами сам, как только они появятся.
Ассистент в WhatsApp больше не начинает каждый разговор с нуля. Когда диалог затихает (по умолчанию на 30 минут), он дописывает в карточку клиента то новое, что узнал: кто это, компания и город, что спрашивал, что ему предлагали, о чём договорились и что осталось открытым. В следующем разговоре карточка идёт ассистенту в контекст вместе с заметками менеджера и актуальным списком КП этого клиента (номер, статус, срок действия). Карточка привязана к номеру клиента, а не к конкретному диалогу, поэтому переживает и перезапуск бота.
Цены и наличие в карточку не попадают никогда — строки с суммами и «в наличии» удаляются автоматически, даже если их вписать руками. Цены ассистент берёт только из свежего поиска по каталогу.
Включение. Отдельно для каждого WhatsApp-канала — галочкой в верхнем блоке вкладки; там же время паузы, после которой диалог считается законченным. По умолчанию выключено. Перезапуск бота не нужен.
Действия с карточкой: изменить имя, текст карточки и заметки менеджера (заметки ассистент видит, но никогда не переписывает), Обновить по диалогу — дописать новые сообщения сразу, не дожидаясь паузы, и удалить — ассистент забудет клиента полностью, сами диалоги останутся. Поиск — по имени, номеру и тексту карточки.
Сводка здоровья каналов, обновляется каждые 30 секунд:
- Общий статус и список проблем (бот не запущен, телефон не на связи, диалоги без ответа, просроченная очередь, недоставленные ответы, amoCRM не подключён).
- Очередь: сколько ждёт подтверждения, возраст самого старого, сколько не доставлено и отправлено сегодня.
- По каждому WhatsApp-номеру: работает ли бот, связь телефона (QR-мост), последнее входящее и последний ответ, число диалогов за 72 часа и диалоги без ответа — клиент написал, а ответа нет дольше порога. Это ловит ситуацию, когда телефон «на связи», а бот молчит.
- Telegram и виджет: последнее входящее/ответ, диалоги без ответа.
- amoCRM: подключён ли, создаются ли лиды автоматически.
- Пороги тревоги: через сколько минут диалог без ответа считается проблемой (по умолчанию 10) и ответ в очереди — просроченным (30).
API: GET /admin/outbound/monitor, GET /admin/outbound/messages?status=, PUT /admin/outbound/messages/{id}, POST /admin/outbound/messages/{id}/approve ({"text": "..."} — необязательная правка), POST /admin/outbound/messages/{id}/reject, DELETE /admin/outbound/messages/{id}, GET/PUT /admin/outbound/settings. Права: просмотр — sales:view, действия — sales:edit, настройки и удаление — sales:manage.
Визуальная доска сделок в стиле Trello/Kanban (CrmKanban.vue):
| Функция | Описание |
|---|---|
| Выбор воронки | Выпадающий список всех pipelines из amoCRM |
| Колонки по статусам | Горизонтальные колонки — каждая соответствует статусу воронки |
| Drag & Drop | Перетаскивание сделок между статусами через vuedraggable@next (SortableJS) |
| Изменяемая ширина колонок | Перетаскивание разделителя между колонками, ширина сохраняется в localStorage |
| Сворачивание колонок | Кнопка ChevronLeft в заголовке сворачивает колонку в узкую вертикальную полоску (48px) с цветной точкой, счётчиком и вертикальным названием. Клик по свёрнутой полоске раскрывает обратно. Состояние сохраняется в localStorage (crm-kanban-collapsed). Разделители ресайза скрываются между свёрнутыми колонками |
| Сброс ширины | Кнопка ↺ сбрасывает все колонки до ширины по умолчанию (288px) |
| Горизонтальная прокрутка | Drag-to-scroll по горизонтали |
| Ленивая загрузка | Карточки подгружаются порциями по 30 шт., IntersectionObserver автоматически загружает ещё при прокрутке |
| Неразобранные сделки | Автоматически подгружаются в первую колонку воронки (статус «Неразобранное») |
| Авто-обновление | Каждые 30 секунд |
| Карточка сделки | Название, сумма, ответственный, контакт |
Табличный вид всех сделок (CrmDeals.vue):
| Функция | Описание |
|---|---|
| Поиск | Фильтрация сделок по названию |
| Пагинация | Кнопки «назад/вперёд» в тулбаре (между поиском и кнопкой «Создать») |
| Детали сделки | Модальное окно: контакты, примечания, теги |
| Создание сделки | Диалог с полями: название, сумма, воронка, статус, контакт |
Unified inbox с двумя подвкладками (CrmInbox.vue):
Все клиентские диалоги с ИИ-ботами, сгруппированные по источнику:
| Функция | Описание |
|---|---|
| Группировка по источнику | Сессии разделены на сворачиваемые группы: Telegram, WhatsApp, Widget |
| Сворачиваемые группы | Chevron-toggle (▶/▼) на заголовке группы, со счётчиком сессий |
| Поиск | Фильтрация сессий по названию и тексту последнего сообщения (по всем группам) |
| Иконки источника | Каждый источник отображается своей иконкой: Send (Telegram), MessageCircle (WhatsApp), Globe (Widget) |
| Просмотр переписки | Выбор сессии → сообщения с markdown-рендерингом (marked + DOMPurify) |
| Ответ через стриминг | Ввод текста → chatApi.streamMessage() → streaming AI reply |
| Авто-обновление | Каждые 15 сек — список сессий, каждые 10 сек — сообщения |
Данные: используется
GET /admin/chat/sessions?group_by=source(группы: telegram, whatsapp, widget; admin-чаты исключены).
Мессенджер-интерфейс для переписки с контактами через Amojo API (CrmInboxAmoCRM.vue). Видна только если настроены Amojo credentials.
| Функция | Описание |
|---|---|
| Список контактов | Поиск контактов из amoCRM |
| Разрешение чата | Выбор контакта → автоматический запрос getContactChats() → получение UUID чата |
| История сообщений | Загрузка переписки из Amojo API |
| Отправка сообщений | Ввод текста → POST /admin/crm/chats/{chat_id}/messages
|
| Авто-обновление | Каждые 10 секунд |
Требования: для amoCRM Inbox необходимо настроить Amojo credentials (Amojo Scope ID, Channel Secret) во вкладке Settings.
| Индикатор | Описание |
|---|---|
| 🟢 Подключено | OAuth2 токены активны, аккаунт доступен |
| 🔴 Не подключено | Нет токенов или истекли |
| 🟡 Ошибка | Ошибка при последнем запросе |
| Поле | Описание |
|---|---|
| Subdomain | Поддомен amoCRM (например, mycompany для mycompany.amocrm.ru) |
| Client ID | OAuth2 Client ID из настроек интеграции |
| Client Secret | OAuth2 Client Secret |
| Redirect URI | URI для OAuth callback (автозаполняется: https://yourdomain.com/admin/crm/callback) |
| Sync Contacts | Включить синхронизацию контактов |
| Sync Leads | Включить синхронизацию лидов |
| Sync Tasks | Включить синхронизацию задач |
| Auto Create Lead | Автоматически создавать лид при первом обращении |
| Lead Pipeline ID | ID воронки для новых лидов |
| Lead Status ID | ID статуса для новых лидов |
- Зайдите в Настройки → Интеграции → Создать интеграцию
- Выберите тип Private app (для приватного доступа) или OAuth2 (для публичной интеграции)
- Скопируйте Client ID и Client Secret
- Укажите Redirect URI:
https://yourdomain.com/admin/crm/callback - Выберите права доступа (scope):
crm(контакты, сделки, задачи)
- Вставьте Subdomain, Client ID и Client Secret в форму
- Нажмите "Получить URL авторизации" → появится кнопка "Подключить amoCRM"
- Кликните на кнопку → откроется popup с OAuth-страницей amoCRM
- Подтвердите доступ в amoCRM
- После редиректа система получит токены и отобразит статус "Подключено"
Для приватных интеграций amoCRM код авторизации (authorization_code) получается из настроек интеграции:
- Создайте приватную интеграцию в amoCRM
- Скопируйте код авторизации из раздела "Получить код"
- Используйте этот код вместо OAuth2 flow
- Система автоматически обменяет код на токены
После подключения отображается:
| Поле | Описание |
|---|---|
| Account Name | Название аккаунта |
| Subdomain | Поддомен |
| User Name | Имя пользователя |
| User Email | Email пользователя |
| Кнопка | Действие |
|---|---|
| Синхронизировать | Запустить синхронизацию контактов/лидов |
| Отключить | Отозвать токены OAuth2 |
История операций синхронизации:
| Поле | Описание |
|---|---|
| Timestamp | Дата и время |
| Operation | Тип операции (sync_contacts, sync_leads, create_lead) |
| Status | Статус (success, error) |
| Details | Детали (количество синхронизированных записей, ошибки) |
| Метрика | Описание |
|---|---|
| Contacts Count | Количество контактов в amoCRM |
| Leads Count | Количество сделок |
| Last Sync Time | Время последней успешной синхронизации |
Синхронизация данных amoCRM в RAG-коллекцию для поиска по сделкам через LLM. Позволяет ИИ-секретарю отвечать на вопросы про конкретные сделки, клиентов, суммы и менеджеров.
-
Сбор данных —
POST /admin/crm/dataset-syncзагружает все воронки, сделки, контакты и пользователей из amoCRM -
Обогащение — контакты дополняются телефонами/email (
get_contacts_by_ids()), ответственные менеджеры резолвятся в имена (get_users()) -
Генерация markdown — по каждой воронке создаётся
crm-pipeline-{id}.md+ общая сводкаcrm-summary.md -
Индексация — файлы пишутся в
data/crm-dataset/, создаётся коллекция "amoCRM", BM25/embedding индекс обновляется
Каждая сделка записывается как секция с полными данными для поиска:
## Сделка #8847291: Разработка сайта — Переговоры (100 000 ₽)
- **ID сделки**: 8847291
- **Сумма**: 100 000 ₽ (100000)
- **Контакт**: Иванов Пётр | тел: +7 (999) 123-45-67 (79991234567) | email: ivanov@mail.ru
- **Тип продукта**: Корпоративный сайт
- **Источник**: Яндекс Директ
- **Теги**: VIP, срочно
- **Создана**: 15.01.2026
- **Обновлена**: 18.02.2026
- **Ответственный**: Алексей Сидоров| Проблема | Решение |
|---|---|
Форматированная цена 100 000 не матчит запрос 100000
|
Цена дублируется: 100 000 ₽ (100000)
|
Телефон +7 (999) 123-45-67 фрагментируется токенизатором |
Digits-only дубль: (79991234567)
|
responsible_user_id — числовой ID |
Резолвится в имя менеджера через get_users()
|
| Кастомные поля (товар, источник) игнорировались |
custom_fields_values извлекаются в markdown |
| ID сделки не записывался | Заголовок ## Сделка #8847291: + строка **ID сделки**
|
| Метод | Endpoint | Описание |
|---|---|---|
| POST | /admin/crm/dataset-sync |
Полная синхронизация: воронки + сделки + контакты + пользователи → markdown → RAG |
| GET | /admin/crm/dataset-status |
Статус: количество документов, секций, дата последней синхронизации |
| DELETE | /admin/crm/dataset |
Очистить датасет (только admin) |
{
"status": "ok",
"pipelines": 3,
"leads_total": 150,
"contacts_enriched": 89,
"users_resolved": 5,
"files_written": 4,
"files_removed": 4,
"collection_id": 2,
"synced_at": "19.02.2026 14:30"
}app/routers/amocrm.py (crm_dataset_sync)
├── get_pipelines() → воронки + статусы
├── get_all_leads_paginated() → все сделки (250/стр)
├── get_contacts_by_ids() → контакты с телефонами/email (50/батч)
├── get_users() → пользователи → {id: имя}
└── app/services/crm_dataset_service.py
├── build_pipeline_document() → markdown по воронке
└── build_summary_document() → сводка + статистика
Файлы:
data/crm-dataset/crm-pipeline-*.md,data/crm-dataset/crm-summary.mdКоллекция: slugamocrm,base_dir="data/crm-dataset"
Если Docker-контейнер не может напрямую достучаться до amoCRM (например, VPN настроен на хосте), используйте прокси:
python scripts/amocrm_proxy.pyПрокси запустится на порту 8888 и пробросит запросы к amoCRM.
Добавьте в .env:
AMOCRM_PROXY=http://172.17.0.1:8888Где 172.17.0.1 — IP хост-машины из Docker-сети.
Endpoint для получения событий от amoCRM: POST /webhooks/amocrm
- Перейдите в Настройки → Интеграции → Вебхуки
- Укажите URL:
https://yourdomain.com/webhooks/amocrm - Выберите события:
add,update,deleteдля контактов, сделок, задач - Сохраните
| Событие | Описание |
|---|---|
contacts:add |
Создан контакт |
contacts:update |
Обновлён контакт |
leads:add |
Создана сделка |
leads:update |
Обновлена сделка |
leads:status |
Изменён статус сделки |
tasks:add |
Создана задача |
tasks:update |
Обновлена задача |
Если включено Auto Create Lead, при первом обращении пользователя из Telegram бота или виджета:
- Система проверяет, существует ли контакт с этим Telegram User ID
- Если нет — создаёт контакт
- Создаёт сделку (лид) в указанной воронке (
Lead Pipeline ID) и статусе (Lead Status ID) - Связывает сделку с контактом
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/crm/config |
Получить конфигурацию CRM |
| PUT | /admin/crm/config |
Обновить конфигурацию |
| GET | /admin/crm/auth-url |
Получить URL для OAuth2 авторизации |
| GET | /admin/crm/callback |
OAuth2 callback (обмен кода на токены) |
| GET | /admin/crm/status |
Статус подключения (токены активны?) |
| POST | /admin/crm/disconnect |
Отключить amoCRM (отозвать токены) |
| GET | /admin/crm/contacts |
Список контактов из amoCRM |
| GET | /admin/crm/leads |
Список сделок из amoCRM |
| GET | /admin/crm/pipelines |
Список воронок и статусов |
| POST | /admin/crm/sync |
Запустить синхронизацию |
| GET | /admin/crm/sync/log |
Получить лог синхронизации |
| GET | /admin/crm/account |
Информация об аккаунте |
| GET | /admin/crm/leads/{id} |
Детали сделки |
| PATCH | /admin/crm/leads/{id} |
Обновить сделку (статус, pipeline) |
| GET | /admin/crm/leads/by-pipeline/{pipeline_id} |
Сделки по воронке (для Kanban) |
| GET | /admin/crm/events |
Лента событий |
| GET | /admin/crm/contacts/{id}/chats |
Чаты контакта (Amojo) |
| GET | /admin/crm/chats/{chat_id}/history |
История сообщений чата (Amojo) |
| POST | /admin/crm/chats/{chat_id}/messages |
Отправить сообщение в чат (Amojo) |
| POST | /admin/crm/dataset-sync |
Синхронизация данных в RAG-коллекцию |
| GET | /admin/crm/dataset-status |
Статус CRM-датасета |
| DELETE | /admin/crm/dataset |
Очистить CRM-датасет (admin only) |
GET /admin/crm/contacts?limit=50&offset=0
Authorization: Bearer <jwt_token>{
"_embedded": {
"contacts": [
{
"id": 12345,
"name": "Иван Иванов",
"custom_fields_values": [
{
"field_code": "PHONE",
"values": [{"value": "+79001234567"}]
},
{
"field_code": "EMAIL",
"values": [{"value": "ivan@example.com"}]
}
]
}
]
}
}Общая ошибка API amoCRM:
raise AmoCRMAPIError(f"API error: {response.status_code}")Истёк токен доступа (401):
raise AmoCRMTokenExpired("Access token expired")Система автоматически обновляет токен при получении 401 и повторяет запрос.
При превышении лимита запросов (429 Too Many Requests):
- Максимум повторов: 3 (
MAX_429_RETRIES) - Задержка между повторами: 1.5 секунды (
RETRY_DELAY_SECONDS) - Система использует экспоненциальный backoff
if response.status_code == 429 and retry_count < MAX_429_RETRIES:
await asyncio.sleep(RETRY_DELAY_SECONDS * (retry_count + 1))
return await self._request(...)Для снижения нагрузки на amoCRM API (лимит ~7 req/s) используется Redis-кэширование ответов. Kanban-доска обновляется каждые 30 секунд, при этом каждый рефреш вызывает GET /leads/by-pipeline/{id}, который пагинирует все сделки (250/стр). Без кэша это создаёт большое количество запросов к amoCRM.
| Эндпоинт | TTL | Ключ кэша |
|---|---|---|
GET /pipelines |
300с (5 мин) | amocrm:pipelines:{subdomain} |
GET /leads/by-pipeline/{id} |
60с (1 мин) | amocrm:pipeline_leads:{subdomain}:{pipeline_id} |
GET /leads/unsorted |
30с | amocrm:unsorted:{subdomain}:{page}:{limit} |
GET /leads/{id} |
120с (2 мин) | amocrm:lead:{subdomain}:{lead_id} |
GET /leads(поиск с query) не кэшируется — динамические запросы, низкая частота.
Кэш автоматически сбрасывается при мутациях:
| Мутация | Что инвалидируется |
|---|---|
PATCH /leads/{id} |
amocrm:lead:*:{lead_id} + amocrm:pipeline_leads:* + amocrm:unsorted:*
|
POST /leads |
amocrm:pipeline_leads:* + amocrm:unsorted:*
|
POST /webhooks/amocrm (events: leads[*]) |
amocrm:pipeline_leads:* + amocrm:unsorted:* + amocrm:lead:*
|
POST /disconnect |
amocrm:* (все ключи) |
Redis опционален. Если Redis недоступен — все эндпоинты работают напрямую с amoCRM API, как и до внедрения кэша. При восстановлении Redis кэширование возобновляется автоматически.
# Посмотреть ключи кэша
redis-cli keys "amocrm:*"
# Очистить весь CRM-кэш
redis-cli keys "amocrm:*" | xargs redis-cli delapp/routers/amocrm.py
→ app/services/amocrm_service.py (AmoCRMService)
→ AmoCRMService (modules/crm/service.py)
→ AmoCRMRepository (db/repositories/amocrm.py)
→ AmoCRMConfig, AmoCRMToken (modules/crm/models.py)
Чистый async HTTP-клиент без прямого DB-доступа. Методы:
-
get_contacts(limit, offset)— список контактов -
get_contacts_by_ids(contact_ids, batch_size=50)— батч-запрос контактов по ID с телефонами/email -
get_leads(limit, offset)— список сделок -
get_all_leads_paginated()— все сделки (250/стр, пагинация до конца) -
get_users()— все пользователи аккаунта →{id: имя} -
create_lead(name, price, pipeline_id, status_id, contact_id)— создать сделку -
get_pipelines()— список воронок и статусов -
refresh_tokens()— обновить токены при 401 -
exchange_code(code)— обменauthorization_codeна токены
Доменный сервис в modules/crm/service.py (ранее AsyncAmoCRMManager в db/integration.py) для работы с конфигурацией и токенами в БД:
-
get_config()— получить конфигурацию -
save_config(config)— сохранить конфигурацию -
get_tokens()— получить токены -
save_tokens(tokens)— сохранить токены -
delete_tokens()— удалить токены (отключение)
Если установлена переменная окружения AMOCRM_PROXY, все запросы проксируются:
proxies = {"http://": os.getenv("AMOCRM_PROXY"), "https://": os.getenv("AMOCRM_PROXY")}
async with httpx.AsyncClient(proxies=proxies) as client:
response = await client.get(url)- Admin — полный доступ к CRM-интеграции
-
User — только своя конфигурация (по
owner_id) - Guest — только чтение