Оповещения

Для использования функционала должен быть доступен функционал Ротация номеров.

Код 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 - попытка успешная и получение считается подтверждённым.