Использование IVR меню, в большинстве случаев, позволяет эффективно распределять входящие звонки и снижать нагрузку с секретаря. Клиент звонит, выбирает нужный отдел либо донабирает внутренний номер сотрудника и достигает цели. Но, как быть в ситуации, когда клиент не знает кому он звонит? Что если это наш менеджер не смог дозвонится клиенту, который перезвонил и попал на IVR? В данном случае будет полезным функционал "Липкости звонка". Мы уже рассматривали реализацию: Входящий звонок с маршрутизацией на ответственного в bpm'online. Сегодня мы рассмотрим пример маршрутизации в первую очередь на того, кто сегодня уже общался с данным номером либо звонил ему. Приступим!

Kibana нам в помощь

Для решения поставленной задачи нам понадобится приложение cdr, которое предназначено для поиска по журналу звонков в elasticsearch. В начале, нам нужно написать правильный запрос. Делаем тестовый звонок и открываем интерфейс Kibana, раздел Discover. Выбираем для отображения колонки extension (номер сотрудника), caller_id_number (номер абонента), destination (номер назначения).

Теперь сделаем запрос с фильтрацией по номеру абонента, он может быть либо в номере назначения (для исходящих) либо в номере абонента (для входящих):

destination_number:/0969716158/ OR caller_id_number:/0969716158/

Как результат, мы получаем номер сотрудника, extension, который общался либо звонил абоненту. И обязательно открываем Response (ответ со стороны elasticsearch), он нам пригодится ниже:

И так, как искать мы уже поняли, а теперь, добавим это все в маршрутизацию на стороне Webitel.

Запрос в CDR

Для работы с приложением cdr, нам нужно написать правильно запрос в elasticsearch

{
    "limit": 1,
    "sort": {
        "created_time": {
            "order": "desc",
            "unmapped_type": "boolean"
        }
    },
    "index": "cdr-a",
    "query": "*",
    "columns": [
        "extension"
    ],
    "filter": [
        {
            "bool": {
                "must": [
                    {
                        "range": {
                            "created_time": {
                                "gte": "now/d",
                                "lte": "now"
                            }
                        }
                    },
                    {
                        "query_string": {
                            "query": "destination_number:/.*${caller_id_number}/ OR caller_id_number:/.*${caller_id_number}/",
                            "analyze_wildcard": true,
                            "default_field": "*"
                        }
                    }
                ]
            }
        }
    ]
}

Разберем запрос:

ПараметрОписание
limit
Количество записей. 1 - так как нам нужно только последнего звонившего.
sort
Сортировку делаем от новых к старым, опять же - только последний.
index
В каком индексе осуществлять поиск: cdr-a
columns
Какие поля возвращать - нам нужен номер сотрудника: extension
query_string
Строка запроса в которой номер телефона заменен на канальную переменную caller_id_number
range
Временной интервал: начиная с 00:00 текущего дня до теперь.

А теперь посмотрим на ответ со стороны elasticsearh:

{
    "took": 4,
    "timed_out": false,
    "_shards": {
        "total": 10,
        "successful": 10,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 5,
        "max_score": null,
        "hits": [
            {
                "_index": "cdr-a-2019-.bpmonline.com",
                "_type": "cdr",
                "_id": "bb643481-310a-45cb-8c4e-95244c8e02b8",
                "_score": null,
                "fields": {
                    "extension": [
                        "115"
                    ]
                },
                "sort": [
                    1547032525216
                ]
            }
        ]
    }
}

Что бы добраться к нужному полю extension, мы должны пройти путь:  hits => hits => fields => extension

Теперь давайте обновим нашу маршрутизацию в Public

Маршрутизация входящего звонка

У нас уже есть готовое IVR меню, так что мы добавим вначале проверку, и если результат не пустой, попытаемся соединить с нужным сотрудников (а с помощью userData добавим еще условие, что бы он был в статусе onhook - Готов). Если сотрудник не ответит в течение 15 секунд, тогда уже продолжим выполнять нашу типовую IVR схему:

["начало схемы"],

    {
        "cdr": {
            "exportVar": {
                "last_cid": "hits.hits.0.fields.extension.0"
            },
            "elastic": {
                "limit": 1,
                "sort": {
                    "created_time": {
                        "order": "desc",
                        "unmapped_type": "boolean"
                    }
                },
                "index": "cdr-a",
                "query": "*",
                "columns": [
                    "extension"
                ],
                "filter": [
                    {
                        "bool": {
                            "must": [
                                {
                                    "range": {
                                        "created_time": {
                                            "gte": "now/d",
                                            "lte": "now"
                                        }
                                    }
                                },
                                {
                                    "query_string": {
                                        "query": "caller_id_number:/.*${caller_id_number}/ AND destination_number:${destination_number}",
                                        "analyze_wildcard": true,
                                        "default_field": "*"
                                    }
                                }
                            ]
                        }
                    }
                ]
            }
        }
    },
    {
        "if": {
            "expression": "${last_cid}",
            "then": [
                {
                    "userData": {
                        "name": "${last_cid}",
                        "var": "account_state",
                        "setVar": "acc_state"
                    }
                },
                {
                    "log": "CID: ${caller_id_number}, Ext: ${last_cid} (${acc_state})"
                },
                {
                    "if": {
                        "expression": "${last_cid} && ${acc_state} == 'onhook'",
                        "then": [
                            {
                               "bridge": {
                                   "endpoints": [
                                         {
                                           "name": "${last_cid}",
                                           "type": "user",
                                           "parameters": [
                                              "leg_timeout=15"
                                           ]
                                        }
                                     ]
                                 }
                            }
                        ]
                    }
                }
            ]
        }
    },

["продолжение схемы"]
  • No labels