====== Незаморочений кол-центр ====== В середньостатистичного ISP, функціонування колцентру/техпідтримки зводиться до двох простих речей: * Провайдеру телефонують абоненти, котрі від нього щось хочуть. * Працівники кол-центру підіймають трубку та розмовляють з ними ротом, намагаючись вирішити їхні проблеми. Усе. Нічого більше глобально не відбувається. Все інше це вторинні штуки і розширення, призначені суто для підвищення зручності, отримання статистики, контролю якості та розуміння того, що відбувається у вищеописаних двох пунктах. За звичай, в інтернетах ще прийнято ілюструвати це все якимись такими добрими картинками, на кшталт таких: {{:tipacallcenter.jpg?direct&600|}} чи такими {{:tipacallcenter2.jpg?direct&600|}} або навіть такими, ну щоб "взагалі на серйозних щах" {{:tipacallcenter3.jpg?direct&600|}} //Так-так, більше усміхнених і щасливих людей! Так! Ще більше! Йоу! Щасливий персонал, котрий контактує з клієнтами! Це ж так реалістично... ага..// **Ну, ви ж розумієте, куди ви потрапили, де ви це читаєте і що далі подібної херні не буде? Так?** ====== Що потрібно? ====== Для реалізації основного функціоналу колцентру вам знадобляться: - Бажання. - Люди, які здатні розмовляти на потрібні вам теми по телефону - Якась PBX, щоб комутувати ці всі розмови Тут усе зрозуміло. Для цього взагалі можна нічого особливо не робити. Воно "якось робиться" і "якось працює". Фактично саме по-собі. Але можливо вам захочеться наступних речей: * Хоч якось внятно керувати тим, як, кому і куди додзвонюватимуться ваші абоненти * Хоч якось нотифікувати їх що "чекайте-чекайте, ми ось зараз як трубку піднімемо!" * Хоч якось сповіщати їх про те, що "вибачте дорогенькі, о четвертій годині ранку ми спимо". * Щоб, ваш персонал, дізнавався про те, хто йому телефонує ще до підняття трубки * Мати можливість запису/прослуховування всіх розмов * Мати можливість дізнатися коли дзвонив користувач, а також можливість швидко прослухати всі попередні розмови з ним * Мати загальну статистику за дзвінками, що відбулися, порахувати кількість відповідей/невідповідей * Мати можливість передзвонити на пропущені дзвінки абонентів, та контролювати наскільки добре це відбувається * Мати можливість оцінити ККД вашого кол-центру загалом * Мати можливість швидко дізнатися про дзвінки у неробочий час та якось їх обробити. Власне всі вищевикладені речі, в тому чи іншому вигляді, цілком можна реалізувати за допомогою інтеграції вашої PBX з Ubilling. ====== А як? ====== Власне типовий і рандомно-масштабований кейс типового кол центру виглядає якось так: {{:telepony0.png?direct&800|}} (саппортів намальовано три штуки, щоб вони могли по черзі обійматися і плакати) PBX ми будемо використовувати On-Premise Asterisk, оскільки боротись з тарганами в голові нікому невідомих SaaS ми не хочемо і в принципі не маємо здоров'я розбиратись з цим за вас. Також поряд там намальовано GSM-to-SIP gateway, в який можна натицяти SIM-карток та приймати виклики ними. Якщо вам дуже хочеться аби ми "порадили якийсь нормальний", то нехай це буде, щось типу Yeastar TGХХХ. Якщо вам дуже цікаво знати, як це все налаштовується та інтегрується з Asterisk - дайте нам знати, скажімо отут [[https://t.me/ubilling|@Ubilling]]. В подальшому будуть використовуватись наступні дані, для прикладу: ^ Дані з прикладу ^ Що це? ^ | 192.168.0.162/24 | IP адреса нашого серверу з Asterisk | | em1 | Інтерфейс, через котрий ми будемо спілкуватись з PBX | | 192.168.0.161/24 | IP адреса нашого біллінгового серверу з Ubilling | | 172.16.42.0/24 та 192.168.0.0/24 | умовно "безпечні мережі" де знаходяться наше обладнання, телефони, працівники, тощо | | 185.45.152.0/22 та 195.5.0.54/32 | Мережі та адреси ззовні нашої мережі, де знаходяться наші SIP-провайдери | | 444444 | Номер отриманий від сервісу Zadarma. Він же логін. | | 0800123456 | Вхідний багатоканальний 0800 номер від Укртелекому, насправді 0800 працюють як "аліаси" і дзвінки з них надходять на "справжній номер" | | 0333333333 | Наш справжній номер Укртелекому, на який прилітатиме усе, що дзвонить на 0800123456 а також кудою ми будемо здійснювати вихидні дзвінки за замовчуванням. Він же логін. | | 195.5.0.54 | IP адреса SIP транку Укртелекому | | sip.zadarma.com | Хост SIP транку сервісу Zadarma | | zadarmasecretpassword | Пароль сервісу Zadarma | | verysecretmysqlrootpassword | root-пароль на MySQL серверу телефонії | | asteriskmysqlpassword | пароль MySQL користувача asterisk - використовувається для з'єднання з БД як самим Aterisk для запису CDR, так і біллінгом для читання CDR | | UBxxxxxxxxxxxxxxxxxxxxx | Серійний номер вашого працюючого Ubilling | | http://192.168.0.161/billing/ | Повний URL веб інтерфейсу вашого Ubilling | | sharedsippassword | Загальний пароль наших SIP телефонів, це має сенс якщо всі їх налаштовує ваш адміністратор та стоять вони у вас десь в офісі | | bosspassword | Пароль на конкретний SIP телефон, який демонструє своїм виглядом, як використовувати конкретний пароль не наслідуючи "загальний" для якогось конкретного пристрою | | 08:00-20:00 | Робочий час роботи техпідтримки | | 20:00-08:00 | Час "нічного режиму" | | maryana,mariya,markiyan | Логіни та відповідно імена працівників служби техпідтримки, котрі приймають дзвінки | | 121,122,123 | SIP номери працівників техпідтримки, котрі приймають дзвінки в рамках черги | | 120 | SIP номер, котрий може телефонувати куди йому заманеться, але дзвінки від клієнтів не будуть до нього потрапляти | ====== Налаштовуємо Asterisk з нуля ====== У праву руку беремо чисту FreeBSD 13.2 та ставимо все необхідне нам ПЗ. # pkg install -y asterisk18 # pkg install -y mysql80-server # pkg install -y lame # pkg install -y sox Редагуємо наш **/etc/rc.conf** якось так hostname="sip" ifconfig_em1="inet 192.168.0.162/24" defaultrouter="192.168.0.1" sshd_enable="YES" dumpdev="AUTO" #firewall firewall_enable="YES" firewall_nat_enable="YES" dummynet_enable="YES" firewall_script="/etc/firewall.conf" #fsck no bg fsck_y_enable="YES" background_fsck="NO" #asterisk and mysql mysql_enable="YES" asterisk_enable="YES" #nfs for calls archive export rpcbind_enable="YES" nfs_server_enable="YES" nfs_server_flags="-u -t -n 4" mountd_enable="YES" mountd_flags="-r" Запихаємо все потрібне до **/boot/loader.conf** kern.hz="1000" ipfw_load="YES" net.inet.ip.fw.default_to_accept="1" libalias_load="YES" ipfw_nat_load="YES" dummynet_load="YES" І хоч якось намагаємося подбати про свою безпеку використовуючи якийсь такий **/etc/firewall.conf** # touch /etc/firewall.conf # chmod a+x /etc/firewall.conf #!/bin/sh # firewall command FwCMD="/sbin/ipfw -q" ${FwCMD} -f flush #safe networks define ${FwCMD} table 22 add 127.0.0.1 ${FwCMD} table 22 add 192.168.0.0/24 ${FwCMD} table 22 add 172.16.42.0/24 #peers ${FwCMD} table 22 add 185.45.152.0/22 ${FwCMD} table 22 add 195.5.0.54 #safe zones ${FwCMD} add 45 allow ip from table\(22\) to me ${FwCMD} add 45 allow ip from me to table\(22\) #ssh access ${FwCMD} add 46 deny ip from any to me dst-port 22 ${FwCMD} add 46 deny ip from me to any src-port 22 #snmp access ${FwCMD} add 47 deny ip from any to me dst-port 161 ${FwCMD} add 47 deny ip from me to any src-port 161 #SIP access ${FwCMD} add 48 deny ip from any to me dst-port 5060 ${FwCMD} add 48 deny ip from me to any src-port 5060 #mysql access ${FwCMD} add 49 deny ip from any to me dst-port 3306 ${FwCMD} add 49 deny ip from me to any src-port 3306 #Asterisk misc ${FwCMD} add 50 deny ip from any to me dst-port 28533 ${FwCMD} add 50 deny ip from me to any src-port 28533 ${FwCMD} add 50 deny ip from any to me dst-port 2727 ${FwCMD} add 50 deny ip from me to any src-port 2727 ${FwCMD} add 50 deny ip from any to me dst-port 4569 ${FwCMD} add 50 deny ip from me to any src-port 4569 ${FwCMD} add 50 deny ip from any to me dst-port 4520 ${FwCMD} add 50 deny ip from me to any src-port 4520 #NFS ${FwCMD} add 51 deny ip from any to me dst-port 111 ${FwCMD} add 51 deny ip from me to any src-port 111 ${FwCMD} add 51 deny ip from any to me dst-port 601 ${FwCMD} add 51 deny ip from me to any src-port 601 ${FwCMD} add 51 deny ip from any to me dst-port 602 ${FwCMD} add 51 deny ip from me to any src-port 602 ${FwCMD} add 51 deny ip from any to me dst-port 2049 ${FwCMD} add 51 deny ip from me to any src-port 2049 ${FwCMD} add 65535 allow all from any to any Встановлюємо рутовий пароль на MySQL у випадку, якщо було згенеровано тимчасовий: # service mysql-server start # cat /root/.mysql_secret # set OMP=`cat /root/.mysql_secret | tail -n 1` && mysqladmin -u root -p"${OMP}" password verysecretmysqlrootpassword або ж просто змінуємо пароль на необхідний, якщо **/root/.mysql_secret** не існує: # cat /root/.mysql_secret cat: /root/.mysql_secret: No such file or directory # mysqladmin -u root password verysecretmysqlrootpassword Попередньо готуємо базу даних для зберігання наших CDR # mysql -u root -pverysecretmysqlrootpassword CREATE DATABASE asterisk; CREATE USER 'asterisk'@'%' IDENTIFIED BY 'asteriskmysqlpassword'; GRANT ALL PRIVILEGES ON *.* TO 'asterisk'@'%' WITH GRANT OPTION; USE asterisk; CREATE TABLE `cdr` ( `calldate` datetime NOT NULL DEFAULT '1970-01-01 00:00:01', `clid` varchar(80) NOT NULL DEFAULT '', `src` varchar(80) NOT NULL DEFAULT '', `dst` varchar(80) NOT NULL DEFAULT '', `dcontext` varchar(80) NOT NULL DEFAULT '', `channel` varchar(80) NOT NULL DEFAULT '', `dstchannel` varchar(80) NOT NULL DEFAULT '', `lastapp` varchar(80) NOT NULL DEFAULT '', `lastdata` varchar(80) NOT NULL DEFAULT '', `duration` int(11) NOT NULL DEFAULT '0', `billsec` int(11) NOT NULL DEFAULT '0', `disposition` varchar(45) NOT NULL DEFAULT '', `amaflags` int(11) NOT NULL DEFAULT '0', `accountcode` varchar(20) NOT NULL DEFAULT '', `userfield` varchar(255) NOT NULL DEFAULT '', `uniqueid` varchar(32) NOT NULL DEFAULT '' ) ENGINE=InnoDB DEFAULT CHARSET=latin1; ALTER TABLE `cdr` ADD KEY `calldate` (`calldate`), ADD KEY `dst` (`dst`), ADD KEY `uniqueid` (`uniqueid`); COMMIT; exit а також готуємо місце для експорту записів дзвінків в NFS: # mkdir /mnt/calls # chmod 777 /mnt/calls # echo "/mnt/calls -alldirs -maproot=root 192.168.0.161" > /etc/exports а також місце, де ми зберігатимемо всю нашу кастомну озвучку # mkdir /usr/local/etc/asterisk/ivr_media/ # mkdir /usr/local/etc/asterisk/ivr_media/dasmusic # chmod -R 777 /usr/local/etc/asterisk/ivr_media і превентивно створюємо скрипт, який буде нотифікувати наш біллінг про вхідні дзвінки, що надходять **/usr/local/etc/asterisk/notifybilling** # touch /usr/local/etc/asterisk/notifybilling # chmod a+x /usr/local/etc/asterisk/notifybilling #!/bin/sh NUMBER=$* BILLING_SERIAL="UBxxxxxxxxxxxxxxxxxxxxx" BILLING_URL="http://192.168.0.161/billing/" NOTIFY_URL="${BILLING_URL}?module=remoteapi&key=${BILLING_SERIAL}&action=telepony&number=${NUMBER}" echo `date` ${NUMBER} >> /var/log/asterisk/income_calls.log /usr/bin/fetch -o /dev/null ${NOTIFY_URL} Далі переходимо до власне конфігурації нашої(го?) PBX. Усі необхідні далі нам файли конфігурації лежать у **/usr/local/etc/asterisk**. Для початку, згадуємо, що ми ліниві та тупі, тому ми будемо використовувати старий і нікому не потрібний chan_sip замість нового та красивого PJSIP. Для цього потрібно закоментувати рядок "noload = chan_sip.so" в **modules.conf**, приблизно якось так: ;noload = chan_sip.so а також там же, ми можемо вимкнути деякі модулі які нам скоріш за все не знадобляться noload = res_hep.so noload = res_hep_pjsip.so noload = res_hep_rtcp.so noload = res_config_pgsql.so noload = cel_sqlite3_custom.so noload = cel_radius.so noload = cdr_pgsql.so noload = cdr_radius.so noload = chan_skinny.so noload = res_ari.so noload = res_phoneprov.so noload = cel_custom.so noload = res_pjsip_phoneprov_provider.so noload = res_ari_asterisk.so noload = res_ari_channels.so noload = res_ari_applications.so noload = res_ari_device_states.so noload = res_ari_recordings.so noload = res_ari_sounds.so noload = res_ari_playbacks.so noload = res_ari_bridges.so noload = res_ari_events.so noload = res_ari_endpoints.so noload = res_timing_dahdi.so noload = res_pjsip_transport_websocket.so noload = cel_tds.so noload = cdr_tds.so noload = cdr_sqlite3_custom.so noload = chan_unistim.so Далі редагуємо **sip.conf** приводячи його до наступного вигляду, і залишаючи в ньому лише якісь такі, базові штуки: [general] context=default allowoverlap=no bindport=5060 bindaddr=0.0.0.0 srvlookup=yes relaxdtmf=yes alwaysauthreject=yes videosupport=no notifybusy=yes counteronpeer=yes notifyhold=yes notifycid=ignore-context notifyringing=yes pedantic=yes callcounter=yes register_retry_403=yes [authentication] [phones](!) type=friend context=call-out secret=sharedsippassword host=dynamic nat=force_rport,comedia qualify=yes dtmfmode=auto qualifyfreq=60 qualify=2000 disallow=all allow=alaw allow=ulaw allow=gsm allow=g726 allow=g729 allow=g723 allow=g722 phone-mac-type=none call-limit=1 callgroup=1 pickupgroup=1 canreinvite=no ;================================== ; Here is some awesome phones! ;================================== #include phones.conf ;================================== ; Providers configuration below ;================================== #include providers.conf Виходячи з цього, досить очевидно що для наших пірів, тобто SIP-телефонів з групи [phones], ми резервуємо окремий конфіг phones.conf і будемо використовувати загальний пароль sharedsippassword, який при бажанні можна перепризначити опцією secret конкретного клієнту. Але ж ми пам'ятаємо, що ми ліниві? Так? Власне наших SIP транків, через які надходять та виходять дзвінки, ми будемо описувати в providers.conf. На майбутнє вважатимемо їх нашими "SIP-провайдерами". В принципі можна все це намалювати прямо в sip.conf і не використовуючи групи, як і роблять у більшості мануалів, але повірте - коли у вас буде кілька десятків телефонів і десяток транків - підтримка цього перетворитися на пекельне пекло. Воно вам треба? Далі просто заповнюємо наші телефони у **phones.conf** [120](phones) callerid=Boss <120> secret=bosspassword [121](phones) callerid=Maryana <121> [122](phones) callerid=Mariya <122> [123](phones) callerid= Markiyan <123> Та наших SIP-провайдерів відповідно в **providers.conf** ; Ukrtelecom 0800 [0333333333] type=peer defaultuser=0333333333 secret= fromuser=0333333333 host=195.5.0.54 port=5060 context=call-in fromdomain=195.5.0.54 language=ru-ru nat=never qualifyfreq=60 qualify=2000 directmedia=no insecure=port,invite dtmfmode=rfc2833 disallow=all allow=alaw ;Zadarma trunk [444444] host=sip.zadarma.com insecure=invite,port type=peer fromdomain=sip.zadarma.com disallow=all allow=alaw dtmfmode=auto secret=zadarmasecretpassword defaultuser=444444 trunkname=444444 fromuser=444444 callbackextension=444444 context=call-in qualify=400 directmedia=no nat=force_rport,comedia Додаємо телефони нашої техпідтримки в чергу для обдзвонювання, приводячи **queues.conf** до наступного виду: ;Primary tech support queue [techsupport] music = dasmusic timeout=7 wrapuptime=5 ringinuse=yes autofill=yes periodic-announce = /usr/local/etc/asterisk/ivr_media/wait periodic-announce-frequency = 15 ;possible strats: ringall, leastrecent, fewestcalls, random, rrmemory, linear, wrandom strategy = rrmemory ;Queue members here member => SIP/121 member => SIP/122 member => SIP/123 та додаємо відповідний клас музики додаючи у **musiconhold.conf** наступне: [dasmusic] mode=quietmp3 directory=/usr/local/etc/asterisk/ivr_media/dasmusic Все досить очевидно, так? А тепер намагаємось зосередитись. Зараз почнеться трохи складніше.\\ Описуємо поведінку всієї нашої телефонії у вигляді діалплану, приводячи **extensions.conf** до наступного вигляду [general] static=yes writeprotect=no [globals] DIR_RECORDS=/mnt/calls/ [default] [recording-in] exten => s,1,Set(fname=in_${ARG1}_${STRFTIME(${EPOCH},,%Y-%m-%d-%H-%M-%S)}) exten => s,n,Set(CDR(filename)=${fname}.gsm) exten => s,n,Set(CDR(userfield)=in) exten => s,n,MixMonitor(${DIR_RECORDS}${fname}.gsm,b) exten => s,n(no),Verbose(Exit record) exten => s,n,Return() [recording-out] exten => s,1,Set(fname=out_${ARG2}_${STRFTIME(${EPOCH},,%Y-%m-%d-%H-%M-%S)}) exten => s,n,Set(CDR(filename)=${fname}.gsm) exten => s,n,Set(CDR(userfield)=out) exten => s,n,MixMonitor(${DIR_RECORDS}${fname}.gsm,b) exten => s,n(no),Verbose(Exit record) exten => s,n,Return() [handup-sip] exten => _X!,1,HangUp() ; Outcoming calls [call-out] ;Debug and testing extensions exten => 334,1,Goto(ivr-main,s,1) exten => 333,1,Queue(techsupport,t) ; internal num call exten => _XXX,1,Dial(SIP/${EXTEN}) ; external number call via 0800 exten => _XXX.,1,Set(VOLUME(RX)=8) exten => _XXX.,2,Set(VOLUME(RX)=8) exten => _XXX.,3,GoSub(recording-out,s,1,(${CALLERID(num)},${EXTEN})) exten => _XXX.,4,Dial(SIP/${EXTEN}@0333333333) ;zadarma test exten => 1111,1,Dial(SIP/${EXTEN}@444444) include => handup-sip ;Incoming calls [call-in] exten => 0333333333,1,Goto(ivr-main,s,1) exten => 444444,1,Goto(ivr-main,s,1) [ivr-main] exten => s,1,Answer() exten => s,n,Set(VOLUME(TX)=8) exten => s,n,Set(VOLUME(RX)=8) ;comment following line to disable nightmode exten => s,n,GotoIfTime(20:00-08:00,*,*,*?nightmode,s,1) exten => s,n,GoSub(notifybilling,s,1,(${CALLERID(num)})) exten => s,n,Wait(3) exten => s,n,Background(/usr/local/etc/asterisk/ivr_media/greeting) exten => s,n,GoSub(recording-in,s,1,(${CALLERID(num)},${EXTEN})) exten => s,n,Queue(techsupport,t) [nightmode] exten => s,1,Wait(2) exten => s,2,Playback(/usr/local/etc/asterisk/ivr_media/nighttime) exten => s,3,Wait(3) exten => s,4,Hangup() [notifybilling] exten => s,1,system(/usr/local/etc/asterisk/notifybilling ${ARG1}) exten => s,n,Return() Детальніше про діалплани та те як вони працюють, ви можете дізнатись, почитавши [[https://wiki.asterisk.org/wiki/display/AST/Dialplan|ось цю документацію]] чи подивившись ось ці, [[https://www.youtube.com/c/asteriskvideos/search?query=dialplan|дуже цікаві та пізнавальні відео на YouTube]]. Стало страшно? Ну якщо так - можете помолитись і продовжувати читати далі {{wolfprey.webm?640|Будь хоробрим як вовк!}} У випадку, якщо вам надто складно, то все що вам потрібно знати, це те що вхідні дзвінки маршрутизуються в контексті (так, це оті штуки в квадратних дужечках) call-in та передають дзвінок в контекст ivr-main якоюсь отакою конструкцією [call-in] exten => номер_на_котрий_прилетів_дзвінок,1,Goto(ivr-main,s,1) а те, куди буде змаршрутизовано вихідні дзвінки з ваших телефонів керується в контексті call-out. Власне за напрямок за замовчуванням, кудою будуть улітати всі наші вихідні звінки на номери довжиною більше трьох цифр відповідає оця конструкція: [call-out] ..... exten => _XXX.,4,Dial(SIP/${EXTEN}@0333333333) Окей, страшне закінчилось. Продовжуємо далі. Вмикаємо запис CDR в нашу MySQL базу, додавши в конфіг **cdr_mysql.conf** секцію [global] наступного вигляду [global] hostname=localhost dbname=asterisk table=cdr user=asterisk password=asteriskmysqlpassword Також не забуваємо переконатися, що MySQL буде слухати всі потрібні нам інтерфейси, виправивши опцію bind-address у секції [mysqld] конфігу **/usr/local/etc/mysql/my.cnf** якось так bind-address = 0.0.0.0 з подальшим перезапуском MySQL # service mysql-server restart Тепер можемо перевірити, як це все стартує запустивши Asterisk # service asterisk start і залогінившись у його консоль # asterisk -r далі ми можемо виконати, наприклад, команду sip show peers і дізнатися як виглядають наші піри sip*CLI> sip show peers Name/username Host Dyn Forcerport Comedia ACL Port Status Description 0333333333/0333333333 195.5.0.54 No No 5060 OK (14 ms) 120 (Unspecified) D Yes Yes 0 UNKNOWN 121 (Unspecified) D Yes Yes 0 UNKNOWN 122 (Unspecified) D Yes Yes 0 UNKNOWN 123 (Unspecified) D Yes Yes 0 UNKNOWN 444444/444444 185.45.152.161 Yes Yes 5060 OK (29 ms) Наразі, ми можемо взяти будь-який підручний SIP-клієнт чи телефон, та швиденько його налаштувати {{:linphone_test.png?direct|}} і переконатися, що він успішно логіниться. sip*CLI> sip show peers Name/username Host Dyn Forcerport Comedia ACL Port Status Description 0333333333/0333333333 195.5.0.54 No No 5060 OK (14 ms) 120 (Unspecified) D Yes Yes 0 UNKNOWN 121 (Unspecified) D Yes Yes 0 UNKNOWN 122/122 172.16.42.8 D Yes Yes 5060 OK (5 ms) 123 (Unspecified) D Yes Yes 0 UNKNOWN 444444/444444 185.45.152.161 Yes Yes 5060 OK (29 ms) Також можна подивитися на стан нашої черги за допомогою команди queue show sip*CLI> queue show techsupport has 0 calls (max unlimited) in 'rrmemory' strategy (0s holdtime, 0s talktime), W:0, C:0, A:0, SL:0.0%, SL2:0.0% within 0s Members: SIP/121 (ringinuse enabled) (Not in use) has taken no calls yet (login was 6 secs ago) SIP/123 (ringinuse enabled) (Unavailable) has taken no calls yet (login was 6 secs ago) SIP/122 (ringinuse enabled) (Not in use) has taken no calls yet (login was 6 secs ago) No Callers Тепер можна перезавантажити сервер, щоб переконатися, що все стартує саме і нормально працює після його завантаження # reboot ====== Тестуємо ====== Наразі, ми можемо спробувати зателефонувати на номер 1111 через Zadarma, щоб дізнатися про стан нашого рахунку і просто послухати як воно звучить. А також спробувати зателефонувати до черги самому, скориставшись тестовим номером 334 аби послухати як це все звучатиме для користувачів при вхідному дзвінку. {{siptesting.webm?662|Тестування SIP}} ====== Коротко про озвучку та формати ====== Ми ж хочемо, щоб усе гарно розмовляло, вітало та повідомляло? Для початку слід запам'ятати, що всі файли з нашим озвученням ми будемо класти в **/usr/local/etc/asterisk/ivr_media/** у прийнятному для Asterisk форматі. Конвертувати MP3 в нього, можна якось так: $ lame --decode filename.mp3 tmp.wav $ sox -v 0.5 tmp.wav -t wav -b 16 -r 8000 -c 1 filename.wav $ rm tmp.wav Виходячи з вищеописаного прикладу конфігурації ми припускаємо, що такі файли містять відповідну озвучку: * greeting.wav - початкове вітання типу "Вас вітає провайдер ХХХ, з метою забезпечення якості обслуговування всі дзвінки записуються, очікуйте з'єднання з оператором" * nighttime.wav - озвучка нічного режиму, типу "Вибачте, ви зателефонували в неробочий час, але ми обов'язково вам перетелефонуємо" * wait.wav - періодичне оповіщення під час очікування в черзі, щось типу "очікуйте з'єднання з оператором" * ivr_media/dasmusic/*.mp3 - якась музика очікування, яка може бути в mp3. Якщо ви з якоїсь причини, не здатні за досить мало грошей домовитися з професійним диктором, який надиктує потрібні вам звукові файли з нормальною артикуляцією та поставленим голосом, можете спробувати використати щось[[https://ubilling.net.ua/presets/ivr_media.tar.gz|із цих файлів]], за авторством [[https://github.com/vikdon/|VikDon]] чисто для тестування. Записи дзвінків, зберігаємо в .gsm, оскільки місце в вас не безлімітне, а Ubilling вміє сам нормально прослуховувати та конвертувати при збереженні їх в mp3 чи ogg. ====== Трохи про стратегії обдзвону ====== Те, в якій черговості будуть дзвонити телефони вашої техпідтримки регулюється опцією strategy черги в конфігу **queues.conf**. Вони можуть бути якимись такими: * linear - телефони дзвонять в порядку своєї наявності в черзі "зверху вниз". * ringall - одночасно дзвонять всі телефони, всі бігають і панікують. * leastrecent - виклики надходять спочатку на ті номери, котрі найдовше не приймали викликів. * fewestcalls - виклик надходить на номери, котрі прийняли менше всього викликів. * random - дзвінки надходять на випадкові номери. * rrmemory - телефони дзвонять циклічно, по колу, починаючи з наступного телефону після того, хто останнім відповідав на виклик. * wrandom - звонить випадковий телефон, але використовується штраф цього номеру в якості ваги для розрахунку метрики. ====== Переходимо до налаштувань Ubilling ====== Монтуємо записи дзвінків на локальну файлову систему: # mkdir /mnt/calls_records # mkdir /mnt/calls_archive # chmod -R 777 /mnt/calls_* # mount 192.168.0.162:/mnt/calls /mnt/calls_records Додаємо автоматичне монтування цієї директорії при завантаженні в /etc/fstab 192.168.0.162:/mnt/calls /mnt/calls_records nfs rw 0 0 Далі в [[alteriniconf|alter.ini]] вмикаємо власне телефонію а також заповнюємо доступ до БД з CDR: TELEPONY_ENABLED=1 TELEPONY_CDR="192.168.0.162|asterisk|asteriskmysqlpassword|asterisk|cdr" {{::telepony_icon.png?direct|}} Вмикаємо модуль "Записи телефонних розмов" PBXMON_ENABLED=1 {{::pbxmonitor_icon.png?direct|}} Модуль "Навіщо телефонуєш?" WDYC_ENABLED=1 та додаємо потрібні для його роботи виклики в crontab */1 * * * * /bin/ubapi "whydoyoucall" 5 20 * * * /bin/ubapi "whydoyoucallstats" {{::wdyc_icon.png?direct|}} Він нам потрібен для відслідковування "пропущених дзвінків", ну тобто "абонент зателефонував, повисів на лінії, йому стало сумно, він поклав слухавку". В самому по собі "пропущенному дзвінку" немає нічого страшного. Набагато гірше, коли він в кінці робочого дня стає "дзвінком без реакції" бо абоненту ніхто не перетелефонував і не дізнався, що він хотів. Власне для забезпечення цієї самої реакції нам і потрібен модуль "Навіщо телефонуєш?". {{:wdycok0.png?direct|}} Та вмикаємо модуль "Історія дзвінків" CALLSHIST_ENABLED=1 {{::callshist_icon.png?direct|}} Швиденько також налаштовуємо модуль [[fwtbt|По кому подзвін?]] FWTBT_ENABLED=1 FWTBT_ANYWHERE=1 FWTBT_ADMINS="maryana,mariya,markiyan" FWTBT_INTERVAL=7 FWTBT_TIMER=10 FWTBT_DESKTOP=1 Також може знадобитись "Телефонний довідник" PHONEBOOK_ENABLED=1 {{::phonebook_icon.png?direct|}} де ми, щонайменше зможемо заповнити внутрішні номери наших працівників {{:phonebooksipcontacts.png?direct|}} Також непоганим кейсом, задля того аби зробити ваш сервіс ще кращим, може буде налаштувати модуль та оточення для обробки [[callmeback|запитів зворотніх дзвінків]]: CALLMEBACK_ENABLED=1 {{::callmeback_icon.png?direct|}} Також чисто заради естетичного задоволення, можемо додати маунтпоінт записів дзвінків до опції SYSLOAD_DISKS SYSLOAD_DISKS="/,/mnt/calls_records/" задля того, щоб візуально контролювати заповненість {{:sysloadfreespacecalls.png?direct|}} Ось власне і все. ====== Що працює після цього всього? ====== Тепер, при надходженні вхідного дзвінка, ваша техпідтримка зможе: * Побачити що їм телефонують за допомогою модулю [[fwtbt|По кому подзвін?]] та швиденько перейти до профілю абонента прямо з сповіщення. * Опрацювати (вочевидь перетелефонувавши їм) пропущені дзвінки абонентів, за допомогою модулю "Навіщо телефонуєш"? * Опрацювати запити на зворотній дзвінок, отримані скажімо з вашого сайтку за допомогою модулю "Перетелефонуйте мені будь ласка". * Дізнатись хто намагався зателефонувати в неробочий час та взнати "якого біса ти хотів?" за допомогою тих же модулів "ТелеПоні" чи "Навіщо телефонуєш"? * Прямо з профілю абонента, дізнатись коли та скільки він телефонував, та прослухати записи попередніх розмов з ним скориставшись [[https://piclod.com/i/1659181679/bmsipicons.png|Чорною магією]]. Менеджмент, в свою чергу також може контролювати, базові KPI опрацювання телефонних дзвінків техпідтримкою, за допомогою модулю "Екзистенційний кінць" куди вже автоматично складаються дані по наступних показниках: * Кількість вхідних дзвінків * Кількість вхідних дзвінків з відповіддю * Кількість вхідних дзвінків на які не відповіли "одразу". * Загальна тривалість розмов * Середня тривалість розмови * Відсоток вхідних дзвінків, на котрі відповіли "одразу". * Відсоток дзвінків без реакції. Тобто відсоток "повністю пропущених" дзвінків куди не передзвонили. * Час реакції на пропущені дзвінки. Власне інтервал часу між "абонент позвонив, не дочекався, поклав слухавку" і "ми його набрали". Ну а також вибірково прослуховувати/завантажувати записи телефонних розмов у різних форматах, для розбору польотів. ====== Телепатична реакція на стан абонента ====== Вам також, може захотітись автоматично реагувати на стан ваших абонентів, у випадку якщо вам телефонує ваш абонент з відомим вам номером у якого на рахунку заборгованість "одразу після привітання кажемо йому "шановний абонент у вас на рахунку заборгованість", або його рахунок заморожено, про що ми також хочемо його повідомити. Ну або ще щось на кшталт того. Тут на допомогу нам прийде механіка AGI скриптів, котру ми можемо викликати з нашого контексту ivr-main. Взагалі, якщо ви розумієте, що ви робите, насправді, все лімітовано тільки вашою фантазією та скіллом. Для початку встановлюємо PHP, на якому ми і будемо писати AGI скрипти, котрі лежатимуть у нас за шляхом /usr/local/share/asterisk/agi-bin/ # pkg install -y php82 Після чого, створюємо наступний файл скрипта **/usr/local/share/asterisk/agi-bin/telepathy.php** який власне і отримуватиме стан вгаданого за номером абонента, паралельно нотифікуючи біллінг про вхідний дзвінок. #!/usr/local/bin/php -q 'nomoney', '3' => 'frozen' ); /** * End of config section */ $stdin = fopen('php://stdin', 'r'); $stdout = fopen('php://stdout', 'w'); $number=$argv[1]; $url = $ubillingApiUrl . '?module=remoteapi&key=' . $ubillingSerial . '&action=telepony&number=' . $number; $user = file_get_contents($url); $user = trim($user); if (isset($userStates[$user])) { //uncomment following line to debug detected caller id user state //fputs($stdout,'SAY ALPHA "'.$userStates[$user].'" ""'.PHP_EOL); fputs($stdout,'EXEC PLAYBACK "/usr/local/etc/asterisk/ivr_media/'.$userStates[$user].'" ""'.PHP_EOL); fflush($stdout); } fclose ($stdin); fclose ($stdout); exit(0); додаємо контекст telepathy котрий власне і буде викликати наш AGI скрипт з параметром у вигляді CALLERID(num) [telepathy] exten => s,1,AGI(telepathy.php,${ARG1}) exten => s,n,Return() ну і власне, наш контекст ivr main в діалплані, тепер може виглядати наступним чином: [ivr-main] exten => s,1,Answer() exten => s,n,Set(VOLUME(TX)=8) exten => s,n,Set(VOLUME(RX)=8) ;comment following line to disable nightmode exten => s,n,GotoIfTime(20:00-08:00,*,*,*?nightmode,s,1) exten => s,n,Wait(3) exten => s,n,Background(/usr/local/etc/asterisk/ivr_media/greeting) exten => s,n,GoSub(telepathy,s,1,(${CALLERID(num)})) exten => s,n,GoSub(recording-in,s,1,(${CALLERID(num)},${EXTEN})) exten => s,n,Queue(techsupport,t) власне очевидно, що ми заміняємо контекст notifybilling на telepathy для того, щоб здійснювати нотифікацію біллінгу про вхідний дзвінок а також озвучувати абоненту якийсь файл, з /usr/local/etc/asterisk/ivr_media/ відносно його статусу, перед передачею дзвінка до черги. Коротко про статуси абонентів, що повертаються в AGI скрипт: * 0 - невідомий нам номер (абонента не знайдено) * 1 - абонента знайдено, з рахунком якого все добре * 2 - абонента знайдено, на його рахунку, існує заборгованість * 3 - абонента знайдено, його рахунок заморожено Отож, виходячи з цього, наступним массивом AGI скрипта телепатії, регулюється який конкретний файл з теки, буде програно абоненту одразу після привітання: $userStates = array( '0' => 'nouser', '1' => 'allok', '2' => 'nomoney', '3' => 'frozen' ); очевидно, що на відповідні статуси буде програно файли з іменами nouser.wav, allok.wav, nomoney.wav та frozen.wav які ми покладемо у /usr/local/etc/asterisk/ivr_media/? Також ми можемо зручно віддебажити виконання нашого контексту та AGI скрипта за допомогою команди agi set debug on в консолі Asterisk: # asterisk -r *CLI> agi set debug on AGI Debugging Enabled Та зателефонувавши за тестовим номером 334, нашого контексту ivr-main. Якось так: {{teleponytelepathy.webm?662|Тестування телепатії}} AGI Tx >> agi_request: telepathy.php AGI Tx >> agi_channel: SIP/122-00000007 AGI Tx >> agi_language: en AGI Tx >> agi_type: SIP AGI Tx >> agi_uniqueid: 1677860146.8 AGI Tx >> agi_version: 18.15.1 AGI Tx >> agi_callerid: 122 AGI Tx >> agi_calleridname: Mariya AGI Tx >> agi_callingpres: 0 AGI Tx >> agi_callingani2: 0 AGI Tx >> agi_callington: 0 AGI Tx >> agi_callingtns: 0 AGI Tx >> agi_dnid: 334 AGI Tx >> agi_rdnis: unknown AGI Tx >> agi_context: telepathy AGI Tx >> agi_extension: s AGI Tx >> agi_priority: 1 AGI Tx >> agi_enhanced: 0.0 AGI Tx >> agi_accountcode: AGI Tx >> agi_threadid: 34418519040 AGI Tx >> agi_arg_1: 122 AGI Tx >> AGI Rx << EXEC PLAYBACK "/usr/local/etc/asterisk/ivr_media/frozen" "" AGI Tx >> 200 result=0 ====== Чорний список ====== Дуже-дуже чорний. Початок нашого контексту ivr-main повинен виглядати наступним чином: [ivr-main] exten => s,1,Answer() exten => s,2,GotoIf($[${BLACKLIST()}=1]?blacklist) exten => s,3,GoTo(ivr-main,s,5) exten => s,4(blacklist),Hangup() Додавання номера в чорний список відбувається так: asterisk -rx 'database put blacklist 0931234567 1' asterisk -rx 'database del blacklist 0931234567' Перегляд чорного-чорного списку номерів: asterisk -rx 'database show blacklist' ====== Конференції ====== Налаштування конференцій, теж дуже просте та зрозуміле. Для початку в діалплан, в контекст **call-out** необхідно додати відповідні записи, якось так: ; Outcoming calls [call-out] ; conference exten => 777,1,Answer() exten => 777,n,ConfBridge(1,confer) .... та у конфіг **/usr/local/etc/asterisk/confbridge.conf**, в самому його кінці, необхідно додати якусь таку секцію налаштувань нашої конференції: [confer] type=bridge max_members=20 mixing_interval=10 internal_sample_rate=auto record_conference=yes Очевидно, що наші телефони, одночасно всі, зможуть між собою поспілкуватись, зідзвонившись за номером 777.