Несмотря на эпоху интернета и всевозможных средств коммуникации, телефонная связь по прежнему остаётся одним из важнейших каналов взаимодействия компании со своими клиентами. И каким бы ни был корпоративный сайт, — лицо фирмы — отсутствие телефона или плохое качество связи может сильно подпортить впечатление клиентов и партнёров. Поэтому, мы когда-то всерьёз озаботились тем, чтобы интегрировать в «Битрикс24» полноценную систему телефонной связи, которую наши пользователи могут применять для поддержки и развития своего бизнеса. И на страницах этого поста мы хотим рассказать об архитектуре и принципах функционирования созданной системы.

Прорабатывая требования к телефонии, которую планировалось интегрировать в «1С-Битрикс», мы сразу же решили, что каждый телефонный аккаунт должен быть изолирован друг от друга. Чтобы ни один клиент не мог помешать или навредить другому. Нас не устраивала схема, когда на нашу компанию выделяется один телефонный аккаунт, клиенты переводят нам деньги, а мы как-то распределяем трафик. Нам требовалась полная изоляция, чтобы у каждого пользователя была своя статистика, свой баланс, раздельное предоставление прочих услуг. Для этого потребовалось, чтобы компания Voximplant, чей продукт мы выбрали для создания телефонии, доработала свою систему. В результате был внедрён так называемый мастер-аккаунт, под которым создаются все дочерние аккаунты наших пользователей, для каждого портала свой. Хотя, на самом деле, технически используется четыре мастер-аккаунта: для рублей, гривен, долларов и евро.

Это архитектурное решение позволило в будущем реализовать ряд услуг. Например, на каждом портале пользователи могут подключать собственную АТС. Обеспечить такой функционал на одном общем аккаунте было бы невероятно трудно, ведь пришлось бы создавать сложнейшую систему учета, обеспечивать безопасность каждого звонка. А изолированные пользовательские аккаунты позволили всего этого избежать, как и множества других проблем.

Контроллер телефонии


Однако это ещё не решало всех наших задач. Дело в том, что Voximplant представляет собой не просто некий сервис для организации телефонии. Это платформа для разработчиков. А это подразумевает, что все необходимые инструменты должны создавать сами разработчики, в зависимости от своих нужд, принятой бизнес-логики и имеющихся условий.

Поэтому, чтобы реализовать задуманное нами разделение пользовательских аккаунтов, нам пришлось написать на PHP и MySQL модуль для Битрикс24, называющийся контроллер телефонии. Он выступает своеобразным информационным посредником между пользовательским порталом и сервером Voximplant.



Когда пользователь впервые инициирует вызов, то модуль телефонии на его портале обращается к контроллеру телефонии и запрашивает учётные данные. Контроллер проверяет на сервере лицензий, что данный пользователь имеет право на использование этой услуги, а потом обращается за учётными данными на сервер Voximplant. Если учётной записи ещё нет, то она сразу создаётся. После этого контроллер возвращает порталу учётные данные для подключения по SIP, они записываются в БД на портале и используются при всех последующих вызовах. То есть в дальнейшем контроллер телефонии уже не задействуется.

По получении учётных данных пользователь напрямую обращается к Voximplant и весь голосовой трафик идет по WebRTC без каких-либо посредников. Для передачи все прочей информации используется подключение по протоколу WebSocket. Когда вызов завершается, Voximplant уведомляет контроллер, а тот фиксирует это в статистике пользователя. Всё общение с серверами Voximplant осуществляется по принципу REST.

То же самое происходит и в том случае, если пользователь хочет выполнить какие-то другие операции, например, узнать баланс, просмотреть статистику звонков или приобрести телефонный номер. Портал сначала обращается к контроллеру с соответствующим запросом, а тот запрашивает необходимые данные в соответствующем источнике и передает их пользователю.

Иными словами, сами пользовательские порталы ничего не знают про Voximplant, для них точкой входа всегда является контроллер телефонии. Получилась изолированная система, при которой сам пользователь совершенно не беспокоится о том, как совершаются звонки. Вся статистика и текущий баланс отображаются прямо на портале, оплата осуществляется там же, пользователю не нужно заходить куда-то ещё. Это позволяет максимально быстро начать пользоваться услугой телефонии: достаточно зайти на свой портал, выбрать номер, оплатить тут же деньги, и можно совершать звонки. Не нужно заводить какие-то дополнительные аккаунты, что-то настраивать.

В отличие от звонков через браузер, телефонные аппараты пользователей «Битрикс24» подключаются к серверу Voximplant напрямую, минуя контроллер телефонии. Для этого при первичном подключении в телефон заносятся логин и пароль, которые впоследствии используются при каждом звонке. Эти учётные данные пользователь получает во время настройки в разделе «Телефония», процедура такая же, как и при совершении первого звонка. И уже на основе этих регистрационных данных Voximplant отправляет статистику о совершенных звонках. А поскольку телефонные аппараты (в том числе приложения для VoIP-телефонии) могут менять хозяев, то у администратора есть возможность быстро сменить пароль или вообще отключить данный аккаунт.



Когда из внешней сети поступает входящий вызов на номер, арендованный пользователем «Битрикс24», то он попадает на сервер Voximplant. Тот обращается к контроллеру за информацией о том, кому нужно направить звонок. На портале соответствующего пользователя появляется оповещение о входящем вызове, и как только кто-то отвечает, сервер связывает обоих абонентов напрямую.

Безопасность


Несмотря на наличие информационного посредника в виде контроллера телефонии, безопасности это не вредит. Во-первых, все данные передаются по HTTPS, то есть шифруются протоколом SSL. Кроме того, при каждом обмене данными (любая команда по REST) между порталом и контроллером телефонии, на основе передаваемой информации и лицензионного ключа формирует уникальный ключ запроса (для каждого набора данных он будет разным). Такое же шифрование осуществляется при обмене данным между контроллером и голосовыми терминалами Voximplant. Обмен ключами осуществляется и при установлении прямой связи между пользовательским порталом и сервером Voximplant.

Регистрация аккаунтов


Когда новый пользователь заходит на портале «Битрикс24» в раздел телефонии, то контроллер телефонии автоматически создает для него учетную запись в Voximplant. При совершении первого звонка или подключении телефонного аппарата информация о телефонном номере добавляется в учетную запись. То есть все операции по регистрации выполняются последовательно, по мере осуществления пользователем тех или иных действий. Тем самым мы избегаем возникновения пиковой нагрузки на серверы в процессе регистрации.

Обновление аккаунтов


Одной из главных причин создания контроллера телефонии была необходимость контроля за аккаунтами с возможностью их легкого обновления. Внутри пользовательских аккаунтов на порталах хранятся настройки сценария звонка, правила маршрутизации и многое другое. А поскольку у нас уже сейчас созданы десятки тысяч аккаунтов, то суммарный объём данных получается очень большим. И в случае, если мы находим какую-то ошибку в сценарии или хотим добавить новый функционал, нужно зайти в каждый аккаунт и что-то поменять.

Но это даже при ста клиентах очень сложно и долго. Поэтому мы сделали систему обновления. Работает она так: мы создаем новый сценарий, нумеруем его, отправляем на контроллер телефонии, а тот начинает постепенно обновлять все телефонные аккаунты.



Так как у нас много пользователей, которые когда-то попробовали нашу телефонную связь, но не стали ею дальше пользоваться, то мы решили обновлять только те аккаунты, которые будут использовать телефонную связь после выхода обновления. То есть процедура будет запущена только в том случае, если будет инициирован вызов или проверка баланса. Это позволяет планомерно проводить обновление, по мере обращения, не устраивая каждый раз аврал и не загружая систему обновлением многих тысяч аккаунтов.

Сценарии звонков


Voximplant позволяет создать абсолютно любой сценарий звонка. Ниже представлен пример упрощенной схемы входящего вызова.



Давайте разберемся в этой схеме. Итак, у нас есть входящий звонок. Поскольку Voximplant является для «Битрикс24» внешней системой, сначала ему нужно получить у контроллера настройки для вызываемого абонента (в формате JSON), на основании которых сценарий выполняет действия, предусмотренные для входящих или исходящих вызовов. После первого вызова настройки JSON кэшируются, и впоследствии нам не нужно каждый раз обращаться за ними на пользовательский портал. Сам же сценарий представляет собой программный модуль, написанный на JavaScript и содержащий около 3000 строк кода.

После получения настроек начинается обработка сценария, то есть выполнение алгоритма многочисленных проверок. Входит ли вызывающего номера в чёрный список, выходной сегодня день или рабочий, надо ли проигрывать приветствие и проверять добавочные коды, и многое другое.

Мы обрабатываем все типовые сценарии, которые могут быть востребованы нашими пользователями. Например, если входящий звонок совершается ночью, то нужно сообщить о том, что на месте пока никого нет, перезвоните позже или оставьте сообщение. Или сценарии обработки CRM: нужно ли это делать, если да, то перевести вызов на ответственного человека и сразу сообщить ему, от кого именно поступил звонок. Чтобы звонящему сразу ответили: «Здравствуйте, Иван Иванович. Что вы хотите?»

Схема сценария выполняется последовательно: сразу после запуска приветствия запрашиваются необходимые данные, если абонент не ответил на вызов, то выполняется соответствующий этап сценария, и т.д. То есть схема хоть и выглядит очень внушительно, но обрабатывается поэтапно, а не единовременно, так что абоненту не приходится ждать.

Дополнительные возможности


С помощью контроллера телефонии мы можем предупреждать пользователей о том, что их баланс достиг определенного лимита. Это особенно важно для компаний, в которых активно используется телефонная связь, а раннее уведомление позволяет заранее внести средства на счет, не оставшись внезапно без связи на какое-то время.

Также контроллера позволяет нам переносить все настройки пользователя при его переходе с облачной версии «Битрикс24» на коробочную. Поскольку телефонный аккаунт не привязан жёстко к порталу, то достаточно просто переназначаем его на другую версию продукта. Поэтому клиенту ничего не нужно перенастраивать, сразу после миграции он может продолжить пользоваться телефонной связью.

Помимо прочего, посредством контроллера телефонии наша техническая поддержка может оказывать помощь пользователям. Когда кто-то обращается с некой проблемой, специалист техподдержки запрашивает у пользователя данные для авторизации. А затем по утверждённому регламенту спрашивает у него разрешение на просмотр статистики. После того, как разрешение получено, через контроллер телефонии мы получаем данные телефонного аккаунта, логи звонков и прочую информацию, позволяющую решить проблему, с которой обратился пользователь. Зачастую, для полной диагностики проблемы достаточно проанализировать лог вызова, поэтому доступ непосредственно к аккаунту телефонии наши специалисты запрашивают крайне редко. Вот как выглядит лог в оригинале:

Лог
2015-07-24 08:50:08 Loading scenario bitrix24
2015-07-24 08:50:08 Sent event to JS onPhoneEvent with params [{accessURL = ;  accountId = XXXXX ;  applicationId = XXXXX ;  logURL = ;  name = Application.Started ;  sessionId = 48475497 ;  userId = 1 ;  } ;  ]
2015-07-24 08:50:08 Sent event to JS onPhoneEvent with params [{callerid = test ;  destination = 74012XXXXXX ;  displayName = 79112233444 ;  fromURI = sip:test@ip.accountName.voximplant.com ;  headers = {VI-Client-Device = SIP ;  VI-Client-IP = 69.167.178.6 ;  VI-Client-Type = user ;  } ;  id = 16214d90008034a8.1437727808.225341 ;  name = Application.CallAlerting ;  toURI = sip:74012XXXXXX@ip.accountName.voximplant.com ;  } ;  ]
2015-07-24 08:50:08 Executing JS command: SetCustomData with params [{data = 16214d90008034a8.1437727808.225341 ;  } ;  ]
2015-07-24 08:50:08 Executing JS command: StartAudio with params [{headers = NULL ;  id = 16214d90008034a8.1437727808.225341 ;  } ;  ]
2015-07-24 08:50:08 Executing JS command: PlayToneScript with params [{id = 16214d90008034a8.1437727808.225341 ;  loop = true ;  script = 440@-19,480@-19;*(2/4/1+2) ;  } ;  ]
2015-07-24 08:50:08
2015-07-24 08:50:08 ------------------------------------------------------------------------------------------
2015-07-24 08:50:08 Start INCOMING scenario (version: 9)
2015-07-24 08:50:08 ------------------------------------------------------------------------------------------
2015-07-24 08:50:08
2015-07-24 08:50:08
2015-07-24 08:50:08 ------------------------------------------------------------------------------------------
2015-07-24 08:50:08 Pure variables
2015-07-24 08:50:08 Call scenario user: 1
2015-07-24 08:50:08 Call callerId: test
2015-07-24 08:50:08 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = 16214d90008034a8.1437727808.225341 ;  name = Call.AudioStarted ;  } ;  ]
2015-07-24 08:50:08 Call destination: 74012XXXXXX
2015-07-24 08:50:08 Call displayName: 79112233444
2015-07-24 08:50:08 Call number/destination: 74012XXXXXX
2015-07-24 08:50:08 ------------------------------------------------------------------------------------------
2015-07-24 08:50:08
2015-07-24 08:50:09
2015-07-24 08:50:09 ------------------------------------------------------------------------------------------
2015-07-24 08:50:09 Get B24 config:
2015-07-24 08:50:09 ID: 23   /   PORTAL_MODE: RENT   /   SEARCH_ID: test   /   PHONE_NAME: 88002501860   /   CRM: Y   /   CRM_RULE: queue   /   CRM_CREATE: lead   /   CRM_FORWARD: Y   /   QUEUE_TIME: 3   /   QUEUE_TYPE: evenly   /   DIRECT_CODE: Y   /   DIRECT_CODE_RULE: voicemail   /   RECORDING: Y   /   RECORDING_TIME: 0   /   NO_ANSWER_RULE: voicemail   /   FORWARD_NUMBER:    /   FORWARD_LINE: default   /   TIMEMAN: N   /   VOICEMAIL: Y   /   MELODY_LANG: RU   /   MELODY_WELCOME: http://dl.bitrix24.com/vi/RU01.mp3   /   MELODY_WELCOME_ENABLE: Y   /   MELODY_WAIT: http://dl.bitrix24.com/vi/MELODY.mp3   /   MELODY_HOLD: http://dl.bitrix24.com/vi/MELODY.mp3   /   DATE_DELETE: null   /   TO_DELETE: N   /   MELODY_VOICEMAIL: http://dl.bitrix24.com/vi/RU03.mp3   /   PHONE_TITLE: 88002501860   /   PORTAL_URL: https://phone.bitrix24.ru/
2015-07-24 08:50:09 PORTAL_SIGN: -hidden-
2015-07-24 08:50:09 ------------------------------------------------------------------------------------------
2015-07-24 08:50:09
2015-07-24 08:50:09
2015-07-24 08:50:09 ------------------------------------------------------------------------------------------
2015-07-24 08:50:09 Call type is: TEST CALL
2015-07-24 08:50:09 Phone number: 74012XXXXXX
2015-07-24 08:50:09 Call to: 79112233444
2015-07-24 08:50:09 ------------------------------------------------------------------------------------------
2015-07-24 08:50:09
2015-07-24 08:50:09 Call in correct worktime
2015-07-24 08:50:09 ------------------------------------------------------------------------------------------
2015-07-24 08:50:09
2015-07-24 08:50:09 Executing JS command: AcceptCall with params [{headers = NULL ;  id = 16214d90008034a8.1437727808.225341 ;  } ;  ]
2015-07-24 08:50:09 Executing JS command: Play with params [{id = 16214d90008034a8.1437727808.225341 ;  loop = false ;  url = http://dl.bitrix24.com/vi/RU01.mp3 ;  } ;  ]
2015-07-24 08:50:09 Executing JS command: HandleTones with params [{handle = true ;  id = 16214d90008034a8.1437727808.225341 ;  } ;  ]
2015-07-24 08:50:10 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = 16214d90008034a8.1437727808.225341 ;  name = Call.Connected ;  } ;  ]
2015-07-24 08:50:17 Sent event to JS onPhoneEvent with params [{id = 16214d90008034a8.1437727808.225341 ;  name = Call.PlaybackFinished ;  } ;  ]
2015-07-24 08:50:17 Executing JS command: Stop with params [{id = 16214d90008034a8.1437727808.225341 ;  } ;  ]
2015-07-24 08:50:19 Executing JS command: HandleTones with params [{handle = false ;  id = 16214d90008034a8.1437727808.225341 ;  } ;  ]
2015-07-24 08:50:19
2015-07-24 08:50:19 ------------------------------------------------------------------------------------------
2015-07-24 08:50:19 Direct code is: none
2015-07-24 08:50:19 ------------------------------------------------------------------------------------------
2015-07-24 08:50:19
2015-07-24 08:50:19 Executing JS command: Play with params [{id = 16214d90008034a8.1437727808.225341 ;  loop = true ;  url = http://dl.bitrix24.com/vi/MELODY.mp3 ;  } ;  ]
2015-07-24 08:50:20
2015-07-24 08:50:20 ------------------------------------------------------------------------------------------
2015-07-24 08:50:20 Get B24 invite answer: {"COMMAND":"wait","TYPE_CONNECT":"crm","USER_ID":"67","USER_HAVE_PHONE":"Y"}
2015-07-24 08:50:20 ------------------------------------------------------------------------------------------
2015-07-24 08:50:20
2015-07-24 08:50:20
2015-07-24 08:50:20 ------------------------------------------------------------------------------------------
2015-07-24 08:50:20 Action: Send invite to phone67
2015-07-24 08:50:20 from number: 74012XXXXXX
2015-07-24 08:50:20 ------------------------------------------------------------------------------------------
2015-07-24 08:50:20
2015-07-24 08:50:20 Executing JS command: CallUser with params [{id = viXMtbt2TrSdBzRsqoyzSUQTaqDxKESGr_bNdm7UuBI ;  } ;  {callerid = 79112233444 ;  displayName = NULL ;  headers = NULL ;  username = phone67 ;  video = NULL ;  } ;  ]
2015-07-24 08:50:21 Sent event to JS onPhoneEvent with params [{content = {"COMMAND":"wait","OPERATOR_ID":"67"} ;  method = POST ;  name = Application.HttpRequest ;  path = /request/28ccd1538fd88709.1437727808.225342_38.88.16.65/e2a2f42cebd2f7a2 ;  } ;  ]
2015-07-24 08:50:21
2015-07-24 08:50:21 ------------------------------------------------------------------------------------------
2015-07-24 08:50:21 Get command from B24 portal: {"COMMAND":"wait","OPERATOR_ID":"67"}
2015-07-24 08:50:21 ------------------------------------------------------------------------------------------
2015-07-24 08:50:21
2015-07-24 08:50:22 Sent event to JS onPhoneEvent with params [{content = {"COMMAND":"wait","OPERATOR_ID":"67"} ;  method = POST ;  name = Application.HttpRequest ;  path = /request/28ccd1538fd88709.1437727808.225342_38.88.16.65/e2a2f42cebd2f7a2 ;  } ;  ]
2015-07-24 08:50:22
2015-07-24 08:50:22 ------------------------------------------------------------------------------------------
2015-07-24 08:50:22 Get command from B24 portal: {"COMMAND":"wait","OPERATOR_ID":"67"}
2015-07-24 08:50:22 ------------------------------------------------------------------------------------------
2015-07-24 08:50:22
2015-07-24 08:50:25 Sent event to JS onPhoneEvent with params [{content = {"COMMAND":"user","OPERATOR_ID":"67","USER_ID":67} ;  method = POST ;  name = Application.HttpRequest ;  path = /request/28ccd1538fd88709.1437727808.225342_38.88.16.65/e2a2f42cebd2f7a2 ;  } ;  ]
2015-07-24 08:50:25
2015-07-24 08:50:25 ------------------------------------------------------------------------------------------
2015-07-24 08:50:25 Get command from B24 portal: {"COMMAND":"user","OPERATOR_ID":"67","USER_ID":67}
2015-07-24 08:50:25 ------------------------------------------------------------------------------------------
2015-07-24 08:50:25
2015-07-24 08:50:25
2015-07-24 08:50:25 ------------------------------------------------------------------------------------------
2015-07-24 08:50:25 Action: Connect to user67
2015-07-24 08:50:25 from number: 74012XXXXXX
2015-07-24 08:50:25 ------------------------------------------------------------------------------------------
2015-07-24 08:50:25
2015-07-24 08:50:25 Executing JS command: CallUser with params [{id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  } ;  {callerid = 79112233444 ;  displayName = NULL ;  headers = NULL ;  username = user67 ;  video = NULL ;  } ;  ]
2015-07-24 08:50:26 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  name = Call.Ringing ;  } ;  ]
2015-07-24 08:50:26 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  name = Call.Ringing ;  } ;  ]
2015-07-24 08:50:26 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  name = Call.AudioStarted ;  } ;  ]
2015-07-24 08:50:26 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  name = Call.Connected ;  } ;  ]
2015-07-24 08:50:26 Executing JS command: HangupCall with params [{code =  3.0200E+02 ;  headers = NULL ;  id = viXMtbt2TrSdBzRsqoyzSUQTaqDxKESGr_bNdm7UuBI ;  } ;  ]
2015-07-24 08:50:26 Executing JS command: SendMediaBetween with params [{id1 = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  id2 = 16214d90008034a8.1437727808.225341 ;  } ;  ]
2015-07-24 08:50:26 Executing JS command: Record with params [{id = 16214d90008034a8.1437727808.225341 ;  stereo = false ;  } ;  ]
2015-07-24 08:50:26 Sent event to JS onPhoneEvent with params [{id = 16214d90008034a8.1437727808.225341 ;  name = Call.RecordStarted ;  url = http://recordUrl.com/record.mp3 ;  } ;  ]
2015-07-24 08:50:26
2015-07-24 08:50:26 ------------------------------------------------------------------------------------------
2015-07-24 08:50:26 Send CallStart: COMMAND=StartCall&CALL_ID=16214d90008034a8.1437727808.225341&CALL_DEVICE=WEBRTC&EXTERNAL=N&USER_ID=67
2015-07-24 08:50:26 ------------------------------------------------------------------------------------------
2015-07-24 08:50:26
2015-07-24 08:50:26
2015-07-24 08:50:26 ------------------------------------------------------------------------------------------
2015-07-24 08:50:26 Start recording call: http://recordUrl.com/record.mp3
2015-07-24 08:50:26 ------------------------------------------------------------------------------------------
2015-07-24 08:50:26
2015-07-24 08:50:31 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  name = Call.MessageReceived ;  text = {"COMMAND":"hold"} ;  } ;  ]
2015-07-24 08:50:31
2015-07-24 08:50:31 ------------------------------------------------------------------------------------------
2015-07-24 08:50:31 Get command from B24 user: {"COMMAND":"hold"}
2015-07-24 08:50:31 ------------------------------------------------------------------------------------------
2015-07-24 08:50:31
2015-07-24 08:50:31 Executing JS command: StopMediaBetween with params [{id1 = 16214d90008034a8.1437727808.225341 ;  id2 = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  } ;  ]
2015-07-24 08:50:31 Executing JS command: Stop with params [{id = 16214d90008034a8.1437727808.225341 ;  } ;  ]
2015-07-24 08:50:31 Executing JS command: Play with params [{id = 16214d90008034a8.1437727808.225341 ;  loop = true ;  url = http://dl.bitrix24.com/vi/MELODY.mp3 ;  } ;  ]
2015-07-24 08:50:31 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  name = Call.MessageReceived ;  text = {"COMMAND":"meter","PERCENT":100,"GRADE":5} ;  } ;  ]
2015-07-24 08:50:31
2015-07-24 08:50:31 ------------------------------------------------------------------------------------------
2015-07-24 08:50:31 Get command from B24 user: {"COMMAND":"meter","PERCENT":100,"GRADE":5}
2015-07-24 08:50:31 ------------------------------------------------------------------------------------------
2015-07-24 08:50:31
2015-07-24 08:50:36 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  name = Call.MessageReceived ;  text = {"COMMAND":"meter","PERCENT":100,"GRADE":5} ;  } ;  ]
2015-07-24 08:50:36
2015-07-24 08:50:36 ------------------------------------------------------------------------------------------
2015-07-24 08:50:36 Get command from B24 user: {"COMMAND":"meter","PERCENT":100,"GRADE":5}
2015-07-24 08:50:36 ------------------------------------------------------------------------------------------
2015-07-24 08:50:36
2015-07-24 08:50:36 Sent event to JS onPhoneEvent with params [{code = 487 ;  headers = {} ;  id = viXMtbt2TrSdBzRsqoyzSUQTaqDxKESGr_bNdm7UuBI ;  name = Call.Failed ;  reason = Request Terminated ;  } ;  ]
2015-07-24 08:50:39 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  name = Call.MessageReceived ;  text = {"COMMAND":"unhold"} ;  } ;  ]
2015-07-24 08:50:39
2015-07-24 08:50:39 ------------------------------------------------------------------------------------------
2015-07-24 08:50:39 Get command from B24 user: {"COMMAND":"unhold"}
2015-07-24 08:50:39 ------------------------------------------------------------------------------------------
2015-07-24 08:50:39
2015-07-24 08:50:39 Executing JS command: Stop with params [{id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  } ;  ]
2015-07-24 08:50:39 Executing JS command: Stop with params [{id = 16214d90008034a8.1437727808.225341 ;  } ;  ]
2015-07-24 08:50:39 Executing JS command: SendMediaBetween with params [{id1 = 16214d90008034a8.1437727808.225341 ;  id2 = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  } ;  ]
2015-07-24 08:50:41 Sent event to JS onPhoneEvent with params [{headers = {} ;  id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  name = Call.MessageReceived ;  text = {"COMMAND":"meter","PERCENT":100,"GRADE":5} ;  } ;  ]
2015-07-24 08:50:41
2015-07-24 08:50:41 ------------------------------------------------------------------------------------------
2015-07-24 08:50:41 Get command from B24 user: {"COMMAND":"meter","PERCENT":100,"GRADE":5}
2015-07-24 08:50:41 ------------------------------------------------------------------------------------------
2015-07-24 08:50:41
2015-07-24 08:50:44 Sent event to JS onPhoneEvent with params [{cost =  0.0000E+00 ;  direction = any outgoing voip ;  duration = 18 ;  headers = {} ;  id = aI2BuvHLRLmeITs0LNDdq1O4AmrcWkZUmtayuwx7k_o ;  name = Call.Disconnected ;  } ;  ]
2015-07-24 08:50:44 Executing JS command: HangupCall with params [{code =  6.0300E+02 ;  headers = NULL ;  id = 16214d90008034a8.1437727808.225341 ;  } ;  ]
2015-07-24 08:50:44 Sent event to JS onPhoneEvent with params [{content = {"COMMAND":"queue","OPERATOR_ID":"67"} ;  method = POST ;  name = Application.HttpRequest ;  path = /request/28ccd1538fd88709.1437727808.225342_38.88.16.65/e2a2f42cebd2f7a2 ;  } ;  ]
2015-07-24 08:50:44
2015-07-24 08:50:44 ------------------------------------------------------------------------------------------
2015-07-24 08:50:44 Get command from B24 portal: {"COMMAND":"queue","OPERATOR_ID":"67"}
2015-07-24 08:50:44 ------------------------------------------------------------------------------------------
2015-07-24 08:50:44
2015-07-24 08:50:44 Sent event to JS onPhoneEvent with params [{cost =  0.0000E+00 ;  direction = any Incoming VoIP ;  duration = 34 ;  headers = {} ;  id = 16214d90008034a8.1437727808.225341 ;  name = Call.Disconnected ;  } ;  ]
2015-07-24 08:50:44
2015-07-24 08:50:44 ------------------------------------------------------------------------------------------
2015-07-24 08:50:44 Send HangupCall: COMMAND=HangupCall&PHONE_NUMBER=74012XXXXXX&ACCOUNT_SEARCH_ID=test&CALL_ID=16214d90008034a8.1437727808.225341&USER_ID=67
2015-07-24 08:50:44 ------------------------------------------------------------------------------------------
2015-07-24 08:50:44
2015-07-24 08:50:44
2015-07-24 08:50:44 ------------------------------------------------------------------------------------------
2015-07-24 08:50:44 Send call history
2015-07-24 08:50:44 Call code: 200
2015-07-24 08:50:44 Call reason: Success call
2015-07-24 08:50:44 Call direction: any%20Incoming%20VoIP
2015-07-24 08:50:44 Call params: COMMAND=AddCallHistory&ACCOUNT_ID=XXXXX&PORTAL_USER_ID=67&APPLICATION_ID=XXXXX&PORTAL_TYPE=RENT&PORTAL_NUMBER=74012XXXXXX&PORTAL_CALL=N&ACCOUNT_SEARCH_ID=test&PHONE_NUMBER=79112233444&URL=http://recordUrl.com/record.mp3&INCOMING=2&CALL_ID=16214d90008034a8.1437727808.225341&CALL_LOG=http://callLog/call.log&CALL_DURATION=34&CALL_START_DATE=1437727826308&CALL_STATUS=true&CALL_QUALITY=100&CALL_DEVICE=WEBRTC&CALL_VOTE=0&COST=0
2015-07-24 08:50:44 ------------------------------------------------------------------------------------------
2015-07-24 08:50:44
2015-07-24 08:50:45 Sent event to JS onPhoneEvent with params [{cost = 0 ;  duration = 18 ;  id = 16214d90008034a8.1437727808.225341 ;  name = Call.RecordStopped ;  reason = Stopped by user ;  url = http://recordUrl.com/record.mp3 ;  } ;  ]
2015-07-24 08:50:45 Executing JS command: close with params [void ;  ]
2015-07-24 08:50:45 Session terminated



Все вызываемые JavaScript-методы прописаны в API Voximplant.
Чтобы специалистам было проще читать логи, мы сделали небольшой плагин для Chrome, который немного меняет форматирование:



Так как услуга телефонии предоставляется в рамках сервиса «Битрикс24», то к ней мы применяем такие же политики безопасности, как и к самому сервису. Мы гарантируем пользователям, что без их ведома не заходим к ним на порталы, не прослушиваем записи разговоров и так далее. У нас хранятся только статистические данные по количеству и продолжительности звонков. А сами записи разговоров хранятся только у оператора в закрытом разделе и на портале у клиента. Кроме того, круг специалистов, которые могут с разрешения пользователей получать доступ к записям, строго ограничен.

Трудности внедрения


В целом мы не сталкивались с какими-то сложностями при внедрении системы телефонной связи в «Битрикс24». Можно отметить разве что один момент, да и тот вообще не связан с платформой Voximplant.

Проблема была связана с реализацией «SIP-коннектора». Это услуга, позволяющая пользователю подключить свою АТС (облачную или офисную), чтобы совершать звонки через неё, а не через интерфейс браузера. Оказалось, что разные поставщики услуг и операторы облачных АТС (не говоря уже про офисные АТС) по-разному работают с форматами номеров. Кто-то прекрасно понимает, что такое 7495; кому-то нужно указывать ведущий +; для некоторых не нужно указывать код страны. Для казахских операторов нужно вместо 7495 указывать 8495, иначе не дозвонишься. Также абонентам казахских операторов для международных вызовов (на все номера, кроме казахских и российских) нужно перед кодом страны указывать 810.

Вообще проблема нумерации существует даже в головах пользователей: кто-то набирает перед номером префикс +7, кто-то 8; кто-то набирает 007495, а кто-то 0117495. Многие пользователи любят указывать номера в таком виде: 8 (495) 445-11-20, и нам приходится приводить их к международному формату (без знака +) 74954451120.

Не так давно Voximplant реализовали у себя логику, с помощью которой система распознаёт, откуда звонит пользователь. И для РФ, например, префикс 8 заменяет на 7. Мы пока не готовы к этому переходу, нам кажется, что тут нужно ориентироваться не на страну регистрации номера, а на предпочтения пользователя и сложившиеся традиции; всё-таки русскому человеку, находящемуся в командировке, куда привычнее набирать 8, чем какие-то непонятные 00.

Планы на будущее


Возможности платформы Voximplant весьма обширны, и на сегодняшний день мы используем лишь порядка 30% её функционала. Например, мы планируем внедрить у себя систему многоуровневого IVR. Также собираемся дополнить функцию предупреждения о малом остатке средств на счёте неким адаптивным алгоритмом. По умолчанию в Voximplant уведомления рассылаются по достижении некой границы, общей для всех пользователей. Но в каждой компании свой уровень использования телефонной связи, и если для одной 300 рублей на счёте вполне позволят спокойно работать пару дней, пока не будет пополнен баланс, то для другой даже 2000 рублей не хватит на рабочий день. Так что мы хотим дополнить контроллер телефонии модулем, который будет анализировать расходы компании на телефонную связь в течение недели, и исходя из полученных данных будет устанавливать индивидуальный порог остатка на счёте, по достижении которого будет отправляться уведомление.

Кроме того, в ближайшее время мы внедрим возможность совершения звонков на внутренние номера, трансфер звонков между телефонными аппаратами, конференц-связь и фиксацию источника вызова в CRM. Весь этот функционал уже находится на стадии тестирования, и ближе к середине августа станет доступен нашим пользователям.

Иными словами, телефония для «Битрикс24» активно развивается, мы внимательно отслеживаем все пожелания наших пользователей и стараемся максимально быстро внедрять необходимые новинки.

Комментарии (15)


  1. kaichou
    31.07.2015 13:43
    -1

    Битрикс и телефония в одном предложении?
    Боже, убей идиотов.


    1. burjui
      31.07.2015 13:56
      +5

      Вы как там, ещё живы? Интересно, что вас смущает в таком сочетании.


      1. WhiteD
        31.07.2015 14:46
        -1

        Наверное то, что битрикс — неподдерживаемая свалка кода с тормозами и багами. И добавить туда еще и телефонию — ад и Израиль.


        1. berezuev
          31.07.2015 16:27
          +3

          а ничего, что Битрикс и Битрикс24 — это разные вещи?
          Первое — CMS (система управления контентом), второе — что-то вроде социальной сети для сотрудников.

          Другое дело, что 90% функций в большинстве случаев не нужны, и только лишь отвлекают (привет тем начальникам, которые для имитации бурной деятельности постоянно заваливают тебя всякими уведомлениями через битрикс24). Трелло — наше все.


          1. eyeofhell
            31.07.2015 16:35
            +1

            Трелло неплох, сам пользуюсь. Битрикс24 хорош тем, что есть CRM (client relations management, карточки клиентов) и интеграция с телефонией. Используется в бизнесе для работы с клиентами, заказами итд. Интернет магазин, например. На трелло такое тяжеловато будет сделать.


          1. WhiteD
            31.07.2015 17:19
            -2

            А я про него и говорю. Он чуть менее, но все равно ужасен, чем битрикс CMS.
            Минусящие адепты культа не устали минусить?


    1. eyeofhell
      31.07.2015 16:00
      +1

      Битрикс разный бывает :). Bitrix24 — это немного другая история. Неплохая, надо сказать :)


  1. Alukar
    31.07.2015 19:03
    +1

    Это всё круто, но а как насчёт работы с Asterisk Без всяких сторонних компаний?


    1. ihazz
      01.08.2015 11:32
      +1

      Это не рентабельно, очень сложная будет интеграция и последующее сопровождение.
      Asterisk это ведь не «поставил из коробки и заработало» — у каждой компании свои настройки, свои бизнес-процессы.
      Возможно в будущем, мы вернёмся к этому вопросу, но пока нас устраивает партнёрство с VoxImplant и судя по ежедневным отчетам по телефонии не только нас :)


      1. dslimp
        01.08.2015 19:31
        +1

        Смущает, что сигнальный SIP трафик — идет с IP адреса США.
        А медиа трафик — откуда то с России.
        Столкнулись с этим с точки зрения оператора связи =)


        1. eyeofhell
          02.08.2015 11:40

          А что тут странного? Серверов много, часть отвечает за сигналинг, часть — за передачу голосового трафика. Много разных серверов в разных датацентрах.


  1. RinatUsmanov
    02.08.2015 09:29
    +2

    Классно. Наконец то из Битрикса 24 хоть кто то но отреагирует. А то на все попытки поднять вопросы по телефонии у Ваших хелп десков привычка отписываться ссылками. Какое то у Вас несерьезное отношение к тех поддержке клиентов в этом направлении.

    У компании где я работаю(интегратор одно из направлений телефония), несколько клиентов которые по сути дела отказались от Битрикса24 только по той причине что там не предусмотрена интеграция по открытым стандартам с телефонией. Причем это энтерпрайз клиенты. Каждый из которых имеет штат от 150 офисных сотрудников. Многие из них ушли к «западным» конкурентам. И это за последние полгода. Единственная проблема по которой многие отказываются от Ваших продуктов это полное с Вашей стороны ПРЕНЕБРЕЖЕНИЕ к существующей инфраструктуре компаний. Так же имеется факт что аренда телефонии происходит каким то загадочным и не прозрачным(вполне возможно незаконным) способом отталкивает крупных клиентов от Вашей телефонии. Многие клиенты не хотят да и не будут менять маркетинговую политику связаную с привлечением клиентов только ради интеграции Ваших решений.

    Далее по астериску. Многие компании работают на Астере, плюс имеется тенденция которая ведет к тому что при коммутировании офисов шлюзом становится астериск который можно легко перенастроить в случае если в офисах различное не совместимое оборудование.

    В связи с Выше сказанным у меня имеется вопрос:
    Когда Ваша компания услышит своих клиентов и перестанет предлагать единственную возможность интеграции с телефонией через свои карманные компании или партнеров тарифы которых завышены в среднем в 2-10 раз чем по рынку?

    (по поводу незаконного способа предоставления городских телефонных номеров возможно я не прав, но в РФ и Казахстане, для получения городского номера обязательно должны предоставляться документы удостоверяющие личность физ лица или уставные документы компании, это связано с телефонными правонарушениями и уголовной ответственностью владельца телефонного номера. Возможно я здесь не прав, но имея 15 летний стаж по интеграции телефонии, по моему мнению это актуальная информация)


    1. RinatUsmanov
      02.08.2015 09:38

      По поводу завышенных тарифов.
      Многие ИП имеют возможность звонить внутри РК на все стационарные телефоны абсолютно бесплатно. Многие операторы предлагают тарифы при предоплате допустим в 400 долларов, звонить внутри РК по нулевой ставке уже крупным компаниям.
      Допустим направление Казахстан Китай, Казахстан Российская Федерация, операторы дают по цене 0,01 доллара. А это основные торговые партнеры РК(95% торгового оборота).


    1. RinatUsmanov
      02.08.2015 09:49

      По поводу интеграции с Астериском или текущей телефонией она имеется только на словах и не имеет тех поддержки.


  1. student_ivan
    02.08.2015 18:31
    +2

    Впервые открыл для себя такую вещь как звонки с браузера на мобильные номера и был приятно удивлен невысокими ценами, и качеством звонка. Самим битриксом24 пользоваться пробовали, но к сожалению так и не срослось (слишком перегруженный и местами долгий функционал), однако звонки там работают на ура — весьма доволен. А еще классно сделана воронка продаж, лишнее конечно что надо все сделки грузить «оплатами» — у меня это и эльба прекрасно делает, нафига мне еще куда-то что-то заносить? =)
    В целом классный продукт — чувствуется широкий бюджет.