Интеграция с АТС Aterisk (пример реализации)

Интеграция заключается во внесении изменений в текущий диалплан, таким образом чтобы во время его выполнения отправлялись http-запросы к MacroCRM

URL для отправки запросов можно посмотреть в настройках (Компания - Телефония)

Ожидаемые параметры:

cmd ['event', 'contact']

event - событие (действие по умолчанию если cmd не указано)

contact - определение номера ответственного менеджера

type ['OUTGOING', 'INCOMING', 'COMPLETED', 'CANCELLED']

OUTGOING - Исходящий отвеченный вызов

INCOMING - Входящий отвеченный вызов

COMPLETED - Завершенный вызов

CANCELLED - Пропущенный вызов (значение по умолчанию если type не указан)

direction ['in', 'out'] - явное указание направления вызова (необязательный параметр)

callid - уникальный идентификатор звонка

phone - номер телефона звонящего

diversion - номер на который был звонок

user - id пользователя для сопоставления в crm, рекомендуется использовать внутренний номер (extension)

сопоставление пользователей указывается в настройках (Компания - Интеграции - Asterisk - Сопоставление менеджеров)

recording_id - полный путь к файлу записи звонка

Пример настройки диалплана

1. Добавляем макрос "macro-crm"

[macro-crm]

;1-CMD,2-TYPE,3-CALLID,4-CALLERID(num),5-TOEXT

exten => s,1,Set(ARRAY(CMD,TYPE,CALLID)=${ARG1},${ARG2},${ARG3})

exten => s,n,Set(TYPE=${IF($[${EXISTS(${DIALSTATUS})}]?${IF($["${DIALSTATUS}" = "ANSWER"]?COMPLETED:CANCELLED)}:${TYPE})})

exten => s,n,Set(CRMPATH=https://api.macrocrm.ru/call/asterisk/num/token/)

exten => s,n,Set(URL=${CRMPATH}?cmd=${CMD}&type=${TYPE}&callid=${CALLID}&phone=${ARG4}&user=${ARG5})

exten => s,n,Goto(s-${CMD},1)

exten => s-contact,1,Set(TOEXT=${SHELL(/usr/bin/curl '${URL}')})

exten => s-event,1,System(/usr/bin/curl '${URL}'); или wget -O - --quiet если нет curl

;логирование если нужно exten => _s-.,n,System(/bin/echo -e "${STRFTIME(${EPOCH},,%d-%m-%Y %H:%M:%S)} ${ARG1} ${ARG2} ${ARG3} ${ARG4} ${ARG5}" >> /tmp/aster-crm.log)

2. Устанавливаем уникальный идентификатор звонка.

exten => _XXX,n,Set(__CRMCALLID=${SIPCALLID})

3. Можно определить внутренний номер ответственного менеджера

exten => _XXXX,n,Macro(crm,contact,"INCOMING",${CALLID},${CALLERID(num)})

Если такой не найден то устанавливаем значение по умолчанию

exten => _XXXX,n,Set(TOEXT=${IF(${EXISTS(${TOEXT})}?${TOEXT}:${EXTEN})})

Пример:

Есть клиент Воробьева, ее менеджер - Овсянников

При звонке с номера +7 (965) 482-3264 нужно получить его sip-id 7735 чтобы перевести звонок на него

Для тестирования можно перейти по ссылке:

https://api.macrocrm.ru/call/asterisk/num/token/?cmd=contact&type=INCOMING&callid=1234567&phone=79654823264

в ответе будет {"contact_name":"Воробьева Нина Константиновна","responsible_ext":"101","responsible_phone":"+7.9001234567"}

https://api.macrocrm.ru/call/asterisk/num/token/?cmd=responsible_ext&type=INCOMING&callid=1234567&phone=79654823264

вернет только 101

4. Отправляем событие принятого входящего звонка в CRM

exten => _XXXX,n,Dial(SIP/${TOEXT},20,g||M(crm^event^INCOMING^${CALLID}^${CALLERID(num)}^${TOEXT}))

Для тестирования:

https://api.macrocrm.ru/call/asterisk/num/token/?cmd=event&type=INCOMING&callid=1234567&phone=79654823264&user=7735

5. Отправляем событие принятого исходящего звонка в CRM

exten => _[78]9XXXXXXXXX,1,Macro(crm,event,"OUTGOING",${SIPCALLID},${EXTEN},${CALLERID(num)})

Для тестирования:

https://api.macrocrm.ru/call/asterisk/num/token/?cmd=event&type=OUTGOING&callid=12345678&phone=79654823264&user=7735

6. Отправляем результат звонка в CRM

exten => h,1,Macro(crm,event,${DIALSTATUS},${CALLID},${EXTEN},${CALLERID(num)},${TOEXT})

Для тестирования:

https://api.macrocrm.ru/call/asterisk/num/token/?cmd=event&type=COMPLETED&callid=1234567&phone=79654823264&user=7735

Пример настройки при использовании freePBX

globals_custom.conf

CRMPATH = https://api.macrocrm.ru/call/asterisk/num/token/

extensions_custom.conf

[sub-crm]

exten => s,1,Noop(MacroCRM Export Start)

exten => s,n,Set(CMD=${ARG1})

exten => s,n,Set(TYPE=${ARG2})

exten => s,n,Set(STATUS=${ARG3})

exten => s,n,Goto(s-${CMD},1)

exten => s-event,1,Goto(s-event-${TYPE},1)

exten => s-event-incoming,1,Set(URL=${CRMPATH}?cmd=${CMD}&type=INCOMING&callid=${CRMCALLID}&phone=${CRMCALLERID}&user=${MASTER_CHANNEL(CONNECTEDLINE(num))})

exten => s-event-incoming,n,Noop(MacroCRM URL=${URL})

exten => s-event-incoming,n,ExecIf($["${CRMCONTEXT}"="ext-group"]?System(/usr/bin/curl '${URL}'))

exten => s-event-incoming,n,Goto(crm,1)

exten => s-event-outgoing,1,Noop(MacroCRM s-event-outgoing)

exten => s-event-outgoing,n,Goto(crm,1)

exten => s-event-hangup,1,Noop(MacroCRM s-event-hangup)

exten => s-event-hangup,n,Set(TYPE=${IF($[${EXISTS(${DIALSTATUS})}]?${IF($["${DIALSTATUS}" = "ANSWER"]?COMPLETED:CANCELLED)}:${TYPE})})

exten => s-event-hangup,n,Set(URL=${CRMPATH}?cmd=${CMD}&type=${TYPE}&callid=${CRMCALLID}&phone=${CRMCALLERID}&user=${MASTER_CHANNEL(CONNECTEDLINE(num))}&recording_id=${CDR(recordingfile)})

exten => s-event-hangup,n,ExecIf($["${CRMCONTEXT}"="ext-group"]?System(/usr/bin/curl '${URL}'))

exten => s-event-hangup,n,Goto(crm,1)

exten => crm,1,Noop(MacroCRM event=${ARG1} type=${ARG2} status=${ARG3})

exten => crm,n,Noop(MacroCRM CRMPATH=${CRMPATH})

exten => crm,n,Noop(MacroCRM CRMCALLID=${CRMCALLID} CRMCONTEXT=${CRMCONTEXT} CRMCALLERID=${CRMCALLERID})

exten => crm,n,Noop(MacroCRM DIALSTATUS=${DIALSTATUS} HANGUPCAUSE=${HANGUPCAUSE})

exten => crm,n,Noop(MacroCRM CALLERID(name)=${CALLERID(name)} CALLERID(num)=${CALLERID(num)})

exten => crm,n,Noop(MacroCRM BLKVM_CHANNEL=${BLKVM_CHANNEL} CHANNEL=${CHANNEL})

exten => crm,n,Noop(MacroCRM DIAL_TRUNK=${DIAL_TRUNK} DIAL_NUMBER=${DIAL_NUMBER} OUTNUM=${OUTNUM})

exten => crm,n,Noop(MacroCRM MASTER_CONNECTEDLINE(num)=${MASTER_CHANNEL(CONNECTEDLINE(num))} DIALEDPEERNUMBER=${DIALEDPEERNUMBER})

exten => crm,n,Noop(MacroCRM CONNECTEDLINE(num)=${CONNECTEDLINE(num)} EXTTOCALL=${EXTTOCALL})

exten => crm,n,Return()

extensions_override_freepbx.conf

[macro-auto-blkvm]

include => macro-auto-blkvm-custom

exten => s,1,Set(__MACRO_RESULT=)

exten => s,n,Set(CFIGNORE=)

exten => s,n,Set(MASTER_CHANNEL(CFIGNORE)=)

exten => s,n,Set(FORWARD_CONTEXT=from-internal)

exten => s,n,Set(MASTER_CHANNEL(FORWARD_CONTEXT)=from-internal)

exten => s,n,Macro(blkvm-clr,)

exten => s,n,ExecIf($[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]?Set(MASTER_CHANNEL(CONNECTEDLINE(num))=${DIALEDPEERNUMBER}))

exten => s,n,ExecIf($[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]?Set(MASTER_CHANNEL(CONNECTEDLINE(name))=${DB(AMPUSER/${DIALEDPEERNUMBER}/cidname)}))

exten => s,n,Gosub(sub-crm,s,1(event,incoming,answered))

;--== end of [macro-auto-blkvm] ==--;

[macro-hangupcall]

include => macro-hangupcall-custom

exten => s,1(start),GotoIf($["${USE_CONFIRMATION}"="" | "${RINGGROUP_INDEX}"="" | "${CHANNEL}"!="${UNIQCHAN}"]?theend)

exten => s,n(delrgi),Noop(Deleting: RG/${RINGGROUP_INDEX}/${CHANNEL} ${DB_DELETE(RG/${RINGGROUP_INDEX}/${CHANNEL})})

exten => s,n(theend),ExecIf($["${ONETOUCH_RECFILE}"!="" & "${CDR(recordingfile)}"=""]?Set(CDR(recordingfile)=${ONETOUCH_RECFILE}))

exten => s,n,Gosub(sub-crm,s,1(event,hangup,hangup))

exten => s,n,Hangup

exten => s,n,MacroExit()

;--== end of [macro-hangupcall] ==--;

[macro-user-callerid]

include => macro-user-callerid-custom

exten => s,1,Set(TOUCH_MONITOR=${UNIQUEID})

exten => s,n,Set(__CRMCALLID=${UNIQUEID})

exten => s,n,Set(__CRMCONTEXT=${MACRO_CONTEXT})

exten => s,n,Set(__CRMCALLERID=${CALLERID(num)})

exten => s,n,Set(AMPUSER=${IF($["${AMPUSER}" = ""]?${CALLERID(number)}:${AMPUSER})})

exten => s,n,GotoIf($["${CUT(CHANNEL,@,2):5:5}"="queue" | ${LEN(${AMPUSERCIDNAME})}]?report)

exten => s,n,ExecIf($["${REALCALLERIDNUM:1:2}" = ""]?Set(REALCALLERIDNUM=${CALLERID(number)}))

exten => s,n,Set(AMPUSER=${DB(DEVICE/${REALCALLERIDNUM}/user)})

exten => s,n,GotoIf($["${AMPUSER}" = "none"]?limit)

exten => s,n,Set(AMPUSERCIDNAME=${DB(AMPUSER/${AMPUSER}/cidname)})

exten => s,n,GotoIf($["${AMPUSERCIDNAME:1:2}" = ""]?report)

exten => s,n,Set(AMPUSERCID=${IF($["${ARG2}" != "EXTERNAL" & "${DB_EXISTS(AMPUSER/${AMPUSER}/cidnum)}" = "1"]?${DB_RESULT}:${AMPUSER})})

exten => s,n,Set(__DIAL_OPTIONS=${IF($["${DB_EXISTS(AMPUSER/${AMPUSER}/dialopts)}" = "1"]?${DB_RESULT}:${DIAL_OPTIONS})})

exten => s,n,Set(CALLERID(all)="${AMPUSERCIDNAME}" <${AMPUSERCID}>)

exten => s,n,GotoIf($["${ARG1}"="LIMIT" & ${LEN(${AMPUSER})} & "${DB(AMPUSER/${AMPUSER}/concurrency_limit)}">"0" & "${GROUP_COUNT(${AMPUSER}@concurrency_limit)}">="${DB(AMPUSER/${AMPUSER}/concurrency_limit)}"]?limit)

exten => s,n,ExecIf($["${ARG1}"="LIMIT" & ${LEN(${AMPUSER})}]?Set(GROUP(concurrency_limit)=${AMPUSER}))

exten => s,n,ExecIf($["${DB(AMPUSER/${AMPUSER}/language)}" != ""]?Set(CHANNEL(language)=${DB(AMPUSER/${AMPUSER}/language)}))

exten => s,n,GosubIf($[${LEN(${DB(AMPUSER/${AMPUSER}/ccss/cc_agent_policy)})} & "${DB(AMPUSER/${AMPUSER}/ccss/cc_agent_policy)}" != "never"]?sub-ccss,s,1(${MACRO_CONTEXT},${CALLERID(dnid)}))

exten => s,n(report),GotoIf($[ "${ARG1}" = "SKIPTTL" | "${ARG1}" = "LIMIT" ]?continue)

exten => s,n(report2),Set(__TTL=${IF($["foo${TTL}" = "foo"]?64:$[ ${TTL} - 1 ])})

exten => s,n,GotoIf($[ ${TTL} > 0 ]?continue)

exten => s,n,Wait(${RINGTIMER})

exten => s,n,Answer

exten => s,n,Wait(1)

exten => s,n,Playback(im-sorry&an-error-has-occured&with&call-forwarding)

exten => s,n,Macro(hangupcall,)

exten => s,n(limit),Answer

exten => s,n,Wait(1)

exten => s,n,Playback(beep&im-sorry&your&simul-call-limit-reached&goodbye)

exten => s,n,Macro(hangupcall,)

exten => s,n,Congestion(20)

exten => s,n(continue),Set(CALLERID(number)=${CALLERID(number):0:40})

exten => s,n,Set(CALLERID(name)=${CALLERID(name):0:40})

exten => s,n,Set(CDR(cnum)=${CALLERID(num)})

exten => s,n,Set(CDR(cnam)=${CALLERID(name)})

exten => s,n,Set(CHANNEL(language)=${MASTER_CHANNEL(CHANNEL(language))})

exten => h,1,Macro(hangupcall,)

;--== end of [macro-user-callerid] ==--;

Last updated