Интеграция с АТС 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