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