Случается, что звонок с офисной АТС приходит на мобильный. И пропускается и на нём тоже.
Причины для этого у каждого свои, но последствия одни и те же — ты смотришь на городской номер офиса и думаешь, а кто же это звонил?



На Хабре уже не раз обсуждалась эта тема. Уведомления отправляли и на почту, и с помощью СМС, в последнее время модно делать это телеграм-ботами, однако я буду использовать Битрикс24.

Почему именно его? Добро пожаловать под кат!

Собственно, всё довольно просто — push-уведомления на телефонах подкупающе удобны и хочется использовать что-то, что доставит минимум хлопот при постоянном использовании.

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

Почему не СМС? Оставив за скобками вопрос небесплатности, скажу о том, что не хочется плодить точки обслуживания при приёме или увольнении сотрудника. Хочется, чтобы отключил его в AD и всё, нет у него больше корпоративных сервисов.

Почему не почта (уж она-то по предыдущему пункту вполне годится)? Потому что сотрудники внезапно не используют её на телефонах (ну, у нас и массово во всяком случае).

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

В общем, к делу!
Предупреждение: код ниже может нанести вам моральные травмы. Сразу соглашаюсь с тем, что он ужасен, всё-таки я не кодер.

Для начала соорудим приёмник со стороны портала, на который будут приходить уведомления и который будет слать их в IM:

send_from_pbx.php
<?
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");

if (!(count($_POST) == 2) || !CModule::IncludeModule('iblock') || !CModule::IncludeModule('im')) {
    die('error');
}

$dbr = CUser::GetList(($by="ID"), ($order="ACS"), ["UF_PHONE_INNER" => intval($_POST["number"])]);

while ($user = $dbr->Fetch()) {
    CIMMessenger::Add(array(
        "MESSAGE_TYPE" => "P", # P - private chat, G - group chat, S - notification
        "TO_USER_ID" => $user["ID"],
        "FROM_USER_ID" => 111,
        "MESSAGE" => substr(strip_tags($_POST[message]) ,0, 100),
        "AUTHOR_ID" => 111,
        "EMAIL_TEMPLATE" => "some",
        "NOTIFY_TYPE" => 2,
        "NOTIFY_MODULE" => "main",
        "NOTIFY_EVENT" => "IM_GROUP_INVITE",
        "NOTIFY_TITLE" => "Пропущенный звонок",
    ));
}
?>

примечание: здесь всё довольно просто. Сначала дёргаем БД, получая соответствие «внутренний номер — ID пользователя в битриксе», затем отправляем сообщение от учётной записи, специально заведённой для Астериска. В принципе, можно отправлять и от имени системы, дело вкуса.

Теперь, на сервере Астериска выложим небольшой скрипт:

send.sh
#! /bin/bash

date=`date +%H:%M`

curl --cookie-jar cookies.txt 'https://portal.domain.ru/?login=yes' -H 'Host: portal.domain.ru'         --data 'AUTH_FORM=Y&TYPE=AUTH&backurl=%2F&USER_LOGIN=asterisk&USER_PASSWORD=perasperaadastra&USER_REMEMBER=Y' > /dev/null 2>&1

curl --cookie cookies.txt --data "message=Вам не смогли дозвониться. Абонент $1 звонил вам в $date&number=$2"         https://portal.domain.ru/send_from_pbx.php > /dev/null 2>&1


Здесь всё ещё проще. Авторизуемся с помощью curl, а затем им же шлём POST-ом сообщение и номер телефона.

Ну и наконец правим extensions.conf в Астериске. В макрос, который переводит звонки на мобильный в случае недоступности основного телефона дописываем ровно одну строку, вызывающую скрипт, который мы только что написали (на всякий случай приведу здесь весь макрос):

[macro-mobile]
exten => s,1,Set(CDR(userfield)=LOCAL)
exten => s,n,ExecIf($[${LEN(${CALLERID(num)})}=3]?Set(name=${SHELL( mysql asterisk -uasterisk -pperasperaadastra -sse 'SELECT callerid FROM peers WHERE defaultuser=${CALLERID(num)}' )$
exten => s,n,Macro(record,local)
exten => s,n,Dial(SIP/${MACRO_EXTEN},20)
exten => s,n,Dial(SIP/tel_out/${ARG1})
exten => s,n,System(/srv/asterisk/send2bitrix/send.sh "${name} (номер ${CALLERID(num)})" ${EXTEN})

в плане набора этот макрос используется следующим образом:

exten => 100,1,Macro(mobile,79251122333)

Здесь всё так же довольно очевидно. Макрос принудительно выставляет CallerID из БД, включает запись разговоров, пытается дозвониться на основной телефон, затем на мобильный и, потерпев фиаско, вызывает наш скрипт, уведомляющий пользователя о том, кто и во сколько ему звонил.

Вот и всё. Спасибо за внимание!

Если у вы хотите что-то уточнить, высказаться, и уж тем более дать добрый совет — пишите.
Поделиться с друзьями
-->

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


  1. vanxant
    13.07.2017 11:13
    +2

    1. Отключите это немедленно! У вас же классическая SQL инъекция через POST.
    2. Я много повидал говнокода вокруг битрикса, но чтобы дергали мускул через shell_exec это на черный пояс тянет. Покурите http://dev.1c-bitrix.ru/api_help/main/reference/cuser/getlist.php например.
    3. Зачем вы два раза подключаете модуль im?


    1. StraNNicK
      13.07.2017 11:19

      Затем что я админ и не знаю php. Совсем не знаю. Правда.
      Поэтому я его слепил из того, что было и send_from_pbx.php закрыл nginx-ом для всех, кроме IP астериска.


      1. vanxant
        13.07.2017 12:07
        +1

        Что закрыли хорошо, но не спасет, если пропущен звонок по сип транку (в него могут напихать что угодно в поле «звонящий», в том числе '; drop table users


      1. vanxant
        13.07.2017 12:24
        +1

        В-общем, надо

        как-то так
        $dbr = CUser::GetList(($by="id"), "asc",["UF_PHONE_INNER" => $_POST["number"]);
        while($user = $dbr->Fetch() {
         $to_user_id = $user["ID"];
        // дальше как у вас
        }
        


        1. StraNNicK
          13.07.2017 12:53

          Ооо, спасибо! Сейчас опробую и, если у меня всё получится, поправлю статью.


        1. alexey-m-ukolov
          13.07.2017 13:46

          2. Найдет и оповестит всех юзеров с данным номером (если например телефон общий на кабинет, а не на сотрудника)
          3. На одного сотрудника можно будет повесить несколько номеров (личный плюс общий, или личный плюс телефон коллеги, пока тот в отпуске)

          Битрикс так не умеет — нельзя несколько внутренних указать и нельзя один внутренний раздать нескольким сотрудникам.


          1. vanxant
            13.07.2017 15:14

            Видимо, ограничения дефолтной установки битрикс 24 (сейчас под рукой нет посмотреть). Ну в общем ещё поле прикрутить не проблема (или заюзать тот же ADMIN_NOTES)


        1. StraNNicK
          13.07.2017 14:01

          поправил. Так лучше?


          1. alexey-m-ukolov
            13.07.2017 14:37
            +2

            <?php
            require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
            
            if (!(count($_POST) == 2) || !CModule::IncludeModule('iblock') || !CModule::IncludeModule('im')) {
                die('error');
            }
            
            $dbr = CUser::GetList(($by = "ID"), ($order = "ACS"), ["ACTIVE" => "Y", "UF_PHONE_INNER" => intval($_POST["number"])]);
            
            while ($user = $dbr->Fetch()) {
                CIMMessenger::Add(array(
                    "MESSAGE_TYPE" => "P", # P - private chat, G - group chat, S - notification
                    "TO_USER_ID" => $user["ID"],
                    "FROM_USER_ID" => 111,
                    "MESSAGE" => $_POST['message'],
                    "AUTHOR_ID" => 111,
                    "EMAIL_TEMPLATE" => "some",
                    "NOTIFY_TYPE" => 2,
                    "NOTIFY_MODULE" => "main",
                    "NOTIFY_EVENT" => "IM_GROUP_INVITE",
                    "NOTIFY_TITLE" => "Пропущенный звонок",
                ));
            }
            


            1. vanxant
              13.07.2017 15:19

              Тут ещё выводится success / error по итогам. Тогда надо

              <?php
              require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
              
              if (!(count($_POST) == 2) || !CModule::IncludeModule('iblock') || !CModule::IncludeModule('im')) {
                  die('error');
              }
              
              $dbr = CUser::GetList(($by = "ID"), ($order = "ASC"), ["ACTIVE" => "Y", "UF_PHONE_INNER" => intval($_POST["number"])]);
              $count = 0; //счётчик отправленных сообщений
              while ($user = $dbr->Fetch()) {
                 if (CIMMessenger::Add(array(
                      "MESSAGE_TYPE" => "P", # P - private chat, G - group chat, S - notification
                      "TO_USER_ID" => $user["ID"],
                      "FROM_USER_ID" => 111,
                      "MESSAGE" => $_POST['message'],
                      "AUTHOR_ID" => 111,
                      "EMAIL_TEMPLATE" => "some",
                      "NOTIFY_TYPE" => 2,
                      "NOTIFY_MODULE" => "main",
                      "NOTIFY_EVENT" => "IM_GROUP_INVITE",
                      "NOTIFY_TITLE" => "Пропущенный звонок",
                  ))) $count++;
              }
               if(count)
                  echo "success";
              else
                  echo "error";
              
              


              1. StraNNicK
                13.07.2017 15:23

                да, но после отладки этим выводом можно пренебречь.
                Но всё равно — отличные комментарии, спасибо ещё раз.


            1. StraNNicK
              13.07.2017 15:22

              Спасибо, так гораздо лучше.