Сервисы вокруг amoCRM

Дедупликация сделок: anti_double_deals

Для разработчиков. Состояние на 24.09.2026. Подробности, переменные и выкатка — README Buharestskie/anti_double_deals.

Коротко

anti_double_deals не даёт заводить в amoCRM (donula.amocrm.ru) повторные сделки на одного клиента и раскладывает новые заявки по этапам. На каждую новую сделку он сливает контакты с тем же телефоном, решает, какая сделка лишняя, убирает её в этап для дублей и переносит оставшуюся в рабочий этап. Всё, что сделал, пишет в журнал.

Как обрабатывается сделка

  1. Вебхук о новой сделке (штатный amoCRM или Sensei) → api ставит задачу в Celery на каждую сделку. worker берёт блокировку сделки в Redis.
  2. Все телефоны иностранные (казахстанские +7 7xx тоже) → этап для дублей, тег «Иностранный номер». Конец.
  3. Слияние контактов. Ищутся контакты с теми же последними 10 цифрами телефона. Выживает самый старый, остальные сливаются в него. В публичном API слияния нет — используется внутренний /ajax amoCRM, для которого worker входит в веб-интерфейс браузером Playwright под служебным пользователем; сессия хранится в Redis. После слияния все сделки группы заново привязываются к выжившему контакту.
  4. Кто дубль. Если у контакта есть более старая активная сделка в одной из 11 «рабочих» воронок (не в статусе 143) — дублем считается новая: этап для дублей, тег «Дубль новая». Иначе в этап для дублей уходят старые неактивные сделки с тегом «Дубль старая», а новая остаётся.
  5. Маршрутизация. Оставшаяся сделка переносится в этап группы A или B по полю-списку 664291 (пять значений — группа A, остальное и пустое — B).
  6. Журнал. Исход пишется в lead_routing_log, одна строка на сделку: «Маршрутизация», «Дубль новая», «Иностранный номер», «В обработке». Страница «Журнал сделок» показывает последние 100 записей со ссылками на сделки.

Страховка: beat раз в 30 минут прогоняет сделки старше 5 минут, застрявшие на входном этапе, и раз в 5 минут лечит сделки, больше 10 минут висящие «В обработке».

Откуда данные: историю (кто ещё с этим телефоном, сделки контакта, справочники) сервис читает из реплики amo_db, с откатом на API при ошибке. Всё, от чего зависит решение, и всё, что читается сразу после записи, — из amoCRM напрямую: реплика отстаёт на секунды, в худшем случае на минуты.

Где живёт

Сервер global, compose из шести контейнеров: api, worker, beat, frontend, postgres, redis. Наружу — через шлюз donula26.ru. Каталог на сервере без git: выкатка копированием, порядок — в README. GitHub Actions deploy.yml проду не соответствует — коммиты в main пока только с [skip ci]. База бэкапится ежедневно, хранение 14 дней. В учёте обращений сервис называется «Журнал маршрутизации лидов».

На что наступают