Оповещения
Для использования функционала должен быть доступен функционал Ротация номеров.
Код API: api/domain/domain_warning_system.py.
Модели: models/domain_warning_system.py. Фронт: rt-v2/src/app/dws/.
Пример запроса
Список
Все методы модуля — это POST /api/ с JSON в теле:
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"action": "list",
"obj": "DWSLocation",
"action_id": "uuid-или-строка",
"params": { "domain_id": 34 },
"limit": 100,
"offset": 0,
"sort": { "id": "-" },
"filter": {
"type": 0,
"field_list": [
{ "field": "location_id", "condition_type": 0, "value": 12 }
]
}
}
В корне запроса:
obj — имя сущности;
action — метод;
action_id — идентификатор запроса, его же вернут в ответе;
params — поля самой сущности и domain_id;
limit, offset, sort и filter тоже в корне. Они нужны только для list и select.
Пользователю домена domain_id подставляется из сессии. Для роли провайдера его нужно передать явно в params. Для списков по умолчанию limit = 100, offset = 0. Сортировка выглядит как { «поле»: «+» } или { «поле»: «-» } (по возрастанию/по убыванию). Если sort не передать, сервер сортирует по name по убыванию.
Фильтры
filter.type: 0 — все условия через И, 1 — через ИЛИ.
Код |
Расшифровка |
|---|---|
0 |
Равно |
1 |
Начинается с |
2 |
Заканчивается на |
3 |
Содержит |
4 |
Больше |
5 |
Больше или равно |
6 |
Меньше |
7 |
Меньше или равно |
8 |
Не равно |
9 |
Входит в список |
10 |
Не входит в список |
11 |
Диапазон дат |
12 |
Не пусто |
Примечание
Диапазон дат (11) используется в журнале задач для поля dt.
Примеры ответов
Код |
Расшифровка |
|---|---|
200 |
Успех |
500 |
Ошибка разбора или бизнес-правила |
401/407 |
Сессия истекала |
403 |
Нет прав |
Права
Код |
Действие |
|---|---|
1 |
Создать |
2 |
Изменить |
3 |
Удалить |
4 |
Список |
5 |
Получить |
6 |
Выбрать |
Запуск шаблона (run) проверяет право изменить на DWSTask, а не на сам шаблон. Если у сущности нет такого метода в permissions, сервер отвечает RMObjectActionNotExists. У DWS нет методов дополнительных полей (get_additional_fields/set_additional_field), хотя базовый обработчик доменных сущностей их умеет.
Какие методы у каких сущностей
Сущность |
list |
get |
select |
append |
update |
delete |
Ещё |
|---|---|---|---|---|---|---|---|
DWSLocation |
да |
да |
да |
да |
да |
да |
|
DWSContactGroup |
да |
да |
да |
да |
да |
да |
вместе с группой удаляются контакты |
DWSContact |
да |
да |
да |
да |
да |
да |
bulk_delete |
DWSTemplate |
да |
да |
да |
да |
да |
да |
run |
DWSTask |
да |
да |
да |
нет |
нет |
нет |
stop |
DWSTaskContact |
да |
да |
да |
нет |
да |
нет |
интерфейс вызывает только list |
DWSTaskAttempt |
да |
да |
да |
нет |
да |
нет |
интерфейс вызывает только list |
Локации, группы, контакты и шаблоны лежат в основной базе, таблицы domain_ws_*.
Задачи, получатели задачи и попытки — в статистической базе. Таблицы именуются {id_домена}__dws_task, {id_домена}__dws_contact, {id_домена}__dws_attempt и создаются при первом запуске.
DWSLocation — локации
Таблица domain_ws_location. В одном домене имя локации уникально.
Локация — площадка, к которой привязывают группы и шаблоны. Удалить её нельзя, пока на неё ссылаются.
Поле |
Тип |
Комментарий |
|---|---|---|
id |
целое |
при создании не передавать |
domain_id |
целое |
домен |
name |
строка, 1 … 150 |
обязательно |
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"action": "append",
"obj": "DWSLocation",
"params": { "domain_id": 34, "name": "Офис Москва" }
}
Примечание
Интерфейс запрашивает список с limit: 500.
DWSContactGroup - группы контактов
Таблица domain_ws_contact_group. В одной локации имя группы уникально.
Права на группы проверяются как на DWSContact. Отдельного объекта прав DWSContactGroup нет.
Поле |
Тип |
Комментарий |
|---|---|---|
id |
целое |
|
domain_id |
целое |
|
name |
строка, 1…150 |
обязательно |
location_id |
целое |
локация, обязательно |
all_employees |
да/нет |
по умолчанию нет |
Если all_employees = true, при запуске в задачу попадут все активные сотрудники домена — плюс контакты, которые явно лежат в группе.
Удаление группы сначала удаляет все её контакты, потом саму группу.
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"action": "append",
"obj": "DWSContactGroup",
"params": {
"domain_id": 34,
"name": "Охрана",
"location_id": 12,
"all_employees": false
}
}
Примечание
Интерфейс запрашивает список с limit: 500. В журнале группы фильтруют по локации.
DWSContactGroup - контакты группы
Таблица domain_ws_contact. Оповестить одного человека отдельно нельзя: запуск всегда идёт на группу. Контакт получает сообщение только как член этой группы.
Поле |
Тип |
Комментарий |
|---|---|---|
id |
целое |
|
domain_id |
целое |
|
group_id |
целое |
группа, обязательно |
user_id |
целое или null |
сотрудник, если контакт привязан к пользователю |
name |
строка 1…150 или null |
|
phones |
массив строк или null |
каждая строка 2…150 символов |
emails |
массив адресов или null |
адрес не длиннее 100 символов |
priority |
целое ≥ 0 |
чем меньше, тем раньше обрабатывают; по умолчанию 0 |
Создание и правка
Логика своя, не общая для доменных сущностей (APIDWSContact._append_update):
После нормализации должен остаться хотя бы один канал: телефон или почта. Иначе RMODataError с текстом phones or emails are required.
Если передан user_id, такой пользователь должен существовать. Тогда сервер подставляет телефоны и почту из карточки пользователя (user.phone и user.email) — по одному значению или пустой список.
В одной группе нельзя два контакта с пересекающимися телефонами или адресами. Ответ — RMUniqueViolation.
Индекс unique_contact_1 запрещает двух сотрудников с одним user_id в одной группе. Несколько внешних контактов без user_id создавать можно: в PostgreSQL несколько NULL в уникальном индексе не конфликтуют.
Поля dt и create_dt из запроса выбрасываются. Поля update_dt в таблице контакта нет.
Обычный контакт:
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"action": "append",
"obj": "DWSContact",
"params": {
"domain_id": 34,
"group_id": 5,
"name": "Иванов",
"phones": ["79001234567"],
"emails": ["ivanov@example.com"],
"priority": 0
}
}
Контакт-сотрудник:
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"action": "append",
"obj": "DWSContact",
"params": {
"domain_id": 34,
"group_id": 5,
"user_id": 88,
"priority": 1
}
}
Импорт из файла в интерфейсе — это серия append. Отдельного метода импорта нет. В CSV ждут колонки имени, телефона, почты и приоритета (на фронте много синонимов заголовков).
Массовое удаление
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"action": "bulk_delete",
"obj": "DWSContact",
"params": { "domain_id": 34, "ids": [1, 2, 3] }
}
ids - непустой список целых чисел. Дубликаты схлопываются, порядок первых вхождений сохраняется.
За один запрос не больше 50 идентификаторов.
Все id должны существовать в текущем домене, иначе RMObjectNotExists со списком отсутствующих.
Если на контакт кто-то ссылается внешним ключом — RMDBReferencesError, ничего не удаляется.
При успехе в body приходит { «ids»: [ …удалённые… ] }.
Примечание
В форме группы страница контактов — от 10 до 50 строк. Полная выгрузка группы — limit: 1000.
DWSTemplate - шаблон сценария
Таблица domain_ws_template. В одной локации имя шаблона уникально.
Шаблон — это сценарий оповещения: последовательность шагов. Каждый шаг - звонок, пауза, SMS или письмо. Текст SMS и письма берётся из текстовых шаблонов TextTemplate.
Поле |
Тип |
Комментарий |
|---|---|---|
id |
целое |
|
domain_id |
целое |
|
name |
строка, 1…150 |
|
location_id |
целое |
локация |
icon |
строка, 1…150 |
в интерфейсе по умолчанию campaign |
color |
строка до 8 символов |
по умолчанию #a72117 |
body |
массив шагов |
хотя бы один шаг |
Примечание
Тип шага задаёт поле model_name.
Звонок - DWSActionCall
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"model_name": "DWSActionCall",
"outbound_dp_id": 15,
"confirm_action": -1,
"confirm_key": 0,
"min_duration": 5,
"audio": { "list": [ { "dpe_name": "DPEAudioDomain", "id": 123 } ] }
}
Поле |
Смысл |
|---|---|
outbound_dp_id |
исходящий маршрут, не меньше 0 |
confirm_action |
-1 — без подтверждения, -3 — DTMF. Перезвон (-2) в модели есть, но в допустимых значениях выключен |
confirm_key |
цифра DTMF, 0…99 |
min_duration |
минимальная длительность разговора в секундах, чтобы считать звонок подтверждённым при confirm_action = -1 |
audio |
что проигрывать: записи домена/системы, TTS и т.п. |
Примечание
Интерфейс при включённом DTMF шлёт confirm_action: -3 и min_duration: 0. Без DTMF - -1 и указанную длительность.
Пауза - DWSActionSleep
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{ "model_name": "DWSActionSleep", "seconds": 30 }
seconds не меньше 1. Пауза не создаёт отдельную попытку: после успешного шага следующая попытка откладывается на это время (delay_until). В интерфейсе по умолчанию 30 секунд.
SMS - DWSActionSMS
Текст сообщения — из текстового шаблона (TextTemplate), поле txt_id. В шаблоне можно использовать Jinja.
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"model_name": "DWSActionSMS",
"confirm_action": -1,
"txt_id": 10,
"domain_extension_id": 3
}
Поле |
Смысл |
|---|---|
txt_id |
текстовый шаблон тела SMS |
domain_extension_id |
SMS-интеграция домена |
confirm_action |
сервер принимает только -1. Интерфейс умеет слать -4 (подтверждение ссылкой), но при сохранении шаблона это не пройдёт проверку |
Письмо - DWSActionEMail
Тема, HTML и текстовая часть — три отдельных текстовых шаблона. Нужен настроенный SMTP.
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"model_name": "DWSActionEMail",
"confirm_action": -1,
"txt_id": 11,
"html_id": 12,
"subject_id": 13
}
Как у SMS, сервер принимает только confirm_action = -1.
Подтверждение получения (confirm_action)
Значение |
Смысл |
Где реально работает |
|---|---|---|
-1 |
подтверждение не нужно |
звонок, SMS, письмо |
-2 |
перезвон |
в перечислении есть, для звонка выключено |
-3 |
DTMF |
только звонок |
-4 |
ссылка |
в перечислении есть, для SMS и письма выключено |
Запуск - DWSTemplate.run
Нужно право изменить DWSTask.
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"action": "run",
"obj": "DWSTemplate",
"params": { "domain_id": 34, "template_id": 7, "group_id": 5 }
}
Идентификатор шаблона передаётся как template_id, не как id.
Что происходит:
Шаблон и группа должны быть в этом домене/
Если уже есть активная задача (status = 1) с той же парой шаблон + группа, повтор запрещён: RMObjectBusy. Сначала нужно остановить предыдущую.
В статистической базе создаётся задача: копируются имя, иконка, цвет и сценарий шаблона, плюс template_id, location_id, group_id, время старта и status = 1.
В таблицу получателей копируются люди:
обычный контакт — contact_id равен id из domain_ws_contact;
сотрудник (user_id или флаг «все сотрудники») — contact_id = -(id пользователя), телефоны = внутренние номера плюс user.phone, почта = user.email, приоритет = 1.
В очередь кладётся служебная задача Task с mname=»DWS» и action=»start».
При успехе в body приходит созданная задача. При ошибке — код 500, notifies, без body.
В журнале интерфейс для каждой выбранной группы вызывает отдельный run (массива групп нет). Перед запуском показывают диалог подтверждения на 60 секунд.
DWSTask - журнал задач
Таблица {id_домена}__dws_task в статистической базе. Создать, поправить или удалить задачу через API нельзя. Доступны list, get, select и stop.
Поле |
Тип |
Комментарий |
|---|---|---|
id |
целое |
в пределах таблицы домена |
name |
строка |
имя шаблона на момент запуска |
template_id |
целое |
какой шаблон запускали |
location_id |
целое |
|
group_id |
целое |
|
icon, color |
строка |
|
body |
массив шагов |
копия сценария |
dt |
дата со временем и зоной |
старт |
status |
1 или 0 |
1 — выполняется, 0 — остановлена |
Правка шаблона после запуска на уже созданную задачу не влияет.
Примечание
Интерфейс просит список с limit: 200, сортировка по id по убыванию. Фильтры: имя, статус, шаблон, группа, период по dt.
Остановка - stop
Нужно право изменить DWSTask.
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"action": "stop",
"obj": "DWSTask",
"params": { "domain_id": 34, "id": 42 }
}
Ищется задача с этим id и статусом «выполняется». Если её нет (уже остановили или не существовала) - RMObjectNotExists. Иначе статус становится 0, в очередь уходит Task с action=»stop». В body возвращается задача.
DWSTaskContact - получатели уже запущенной задачи
Таблица {id_домена}__dws_contact в статистической базе. Это не справочник DWSContact, а снимок людей в конкретной задаче.
Поле |
Тип |
Комментарий |
|---|---|---|
id |
целое |
строка в задаче |
task_id |
целое |
задача |
contact_id |
целое |
исходный контакт или минус id сотрудника |
name |
строка |
|
phones, emails |
массивы |
каналы на момент запуска |
status |
0 или 1 |
0 — ещё обрабатывается, 1 — закончили |
priority |
целое |
Список по задаче:
POST http://{{v2_host}}/api/
Content-Type: application/json
Authorization: Bearer {{auth_token}}
{
"action": "list",
"obj": "DWSTaskContact",
"params": { "domain_id": 34 },
"limit": 2000,
"sort": { "id": "-" },
"filter": {
"type": 0,
"field_list": [
{ "field": "task_id", "condition_type": 0, "value": 42 }
]
}
}
Создать или удалить получателя через API нельзя. Метод update на сервере есть, интерфейс его не вызывает. Статус меняет движок, когда человек подтвердил получение.
Примечание
Интерфейс запрашивает до 2000 строк.
DWSTaskAttempt - попытки по шагам
Таблица {id_домена}__dws_attempt в статистической базе.
Поле |
Тип |
Комментарий |
|---|---|---|
id |
целое |
|
task_id |
целое |
|
contact_id |
целое |
id получателя задачи, не контакта из справочника |
step |
целое |
номер шага в task.body |
idx |
целое ≥ 0 |
какой телефон или адрес из массива контакта |
init_dt |
дата |
начало попытки |
confirm_dt |
дата или null |
человек подтвердил получение |
finish_dt |
дата или null |
попытка завершена |
delay_until |
дата |
следующую попытку не начинать раньше |
call_uuid, session_uuid |
uuid или null |
|
status |
0/1/2 |
новая/успех/ошибка |
Список — тот же фильтр по task_id, на фронте до 2000 строк. update есть, интерфейс не использует.
Примечание
Пауза после шага сдвигает delay_until. Когда проставлено confirm_dt, получатель переходит в статус «закончен», и по нему больше не звонят и не пишут.
Статусы
Задача:
Код |
Действие |
|---|---|
0 |
Остановлена |
1 |
Выполняется |
Получатель задачи:
Код |
Действие |
|---|---|
0 |
Ещё обрабатывается |
1 |
Закончили |
Попытка:
Код |
Действие |
|---|---|
0 |
Новая |
1 |
Успех |
2 |
Ошибка |
Как движок идёт по сценарию
Для каждого получателя со статусом «ещё обрабатывается» берётся последняя попытка. Следующая цель - пара «шаг + индекс канала»:
звонок и SMS - следующий телефон phones[idx];
письмо - следующий адрес emails[idx];
каналы шага кончились - следующий шаг, индекс снова 0;
пауза в выбор цели не попадает, только откладывает следующую попытку.
За один цикл движок берёт не больше 200 контактов. В коде есть лимит звонков на домен: GLOBAL_CALL_LIMIT_PER_DOMAIN = 100.
По CDR: если звонок не ответили и не перевели - попытка с ошибкой. Если ответили, подтверждение DTMF не требовалось и длительность разговора больше min_duration - попытка успешная и получение считается подтверждённым.