Files
BitrixDealsBot/docs/adr/006-guarded-deal-mutations.md
T

4.3 KiB
Raw Blame History

ADR-006: изменение сделки с проверкой актуального состояния

Статус: Принято
Дата: 2026-07-23

Контекст

Состояние сделки может измениться в Битрикс24 после формирования карточки в Telegram, но до нажатия callback-кнопки. Используемый метод crm.deal.update не предоставляет условный UPDATE, поэтому перед изменением требуется проверить, что показанное пользователю состояние остаётся актуальным.

Решение

Назначение ответственного и изменение стадии

Callback-кнопка назначения содержит не только id сделки, но и ASSIGNED_BY_ID, который был показан пользователю: deal:assign:<deal_id>:<expected_responsible_id>. Перед изменением сервис повторно загружает сделку и сравнивает фактического ответственного с ожидаемым. Если карточка устарела, REST-обновление не выполняется.

Внутри одного процесса операции по паре (member_id, deal_id) последовательно выполняются под asyncio.Lock. После crm.deal.update сервис повторно читает сделку и убеждается, что ответственным стал bitrix_user_id привязанного пользователя.

Диаграмма последовательности взятия сделки в работу

Рисунок ADR-006/1. Диаграмма последовательности взятия сделки в работу

При обновлении одновременно передаются ASSIGNED_BY_ID связанного пользователя, рабочая STAGE_ID и параметр REGISTER_HISTORY_EVENT=Y. После REST-запроса выполняется контрольное чтение сделки.

Планирование звонка и просмотр истории

Действие «Позвонить позже» создаёт в Битрикс24 дело типа todo с крайним сроком через один час. Владельцем является сделка (ownerTypeId=2), а ответственным — связанный пользователь Битрикс24. Массив pingOffsets=[0] включает напоминание в момент наступления срока.

История загружается методом crm.stagehistory.list с фильтром OWNER_ID и сортировкой по убыванию идентификатора. В интерфейс выводятся первые пять событий. Для каждого события идентификатор стадии преобразуется в название с учётом CATEGORY_ID, после чего DealFormatter формирует защищённый HTML-текст и клавиатуру возврата к карточке или списку.

Диаграмма последовательности планирования звонка и просмотра истории

Рисунок ADR-006/2. Диаграмма последовательности планирования звонка и просмотра истории

Последствия

Локальный asyncio.Lock защищает только один процесс bot. При горизонтальном масштабировании на несколько контейнеров потребуется распределённая блокировка либо серверная условная операция. Повторная проверка REST-результата сохраняет защиту от внешних изменений, но не делает два удалённых вызова одной транзакцией Битрикс24.