
Today we will talk about the integration of Asterisk with a CRM system. We will not consider the question from the CRM side, it’s enough to know that CRM wants to know about all calls (both incoming, outgoing and transferred)
What
we want to get:
')
For each call, 2 events should be sent to CRM: start and stop. Naturally with a bunch of arguments.
To do this, we will call the sh script:
System(/etc/asterisk/scripts/crm.sh start ${GROUP} ${DSTNUM} ${CIDNUM} ${ID}); System(/etc/asterisk/scripts/crm.sh stop ${GROUP} ${DSTNUM} ${CIDNUM} ${ID} ${CDUR});
The content of the script itself is not interesting to us, the meaning is that it passes these arguments to the CRM itself, and sometimes even returns something back.
${GROUP} - / ${DSTNUM} - , ( popup ) ${CIDNUM} - ${ID} - ID ( , ). ID ${UNIQUEID} ${CDUR} -
We will write these two scripts in a macro (by the way, macros in ael work / are called a little differently than in extensions.conf, for this the Gosub command is used. You need to know about this if you want to call a macro, for example, in the Dial command when the handset is picked up by subscriber B Ie to use not M (x) as in extensions.conf, but U (x))
macro crm (GROUP, DSTNUM, CIDNUM, ID) { System(/etc/asterisk/scripts/crm.sh start ${GROUP} ${DSTNUM} ${CIDNUM} ${ID}); return; } macro crm-end (GROUP, DSTNUM, CIDNUM, ID) { MSet(CDUR=${CDR(billsec)}); System(/etc/asterisk/scripts/crm.sh stop ${GROUP} ${DSTNUM} ${CIDNUM} ${ID} ${CDUR}); return; }
For the organization of outgoing calls, the task turned out to be elementary;
context outgoing { _X. => { Set(GROUP=office1); Set(DSTNUM=${EXTEN}); Set(CIDNUM=${CALLERID(num)}); Set(ID=${UNIQUEID}); &record-crm(${STRFTIME(,,%G/%m/%d/)}${ID}); &crm(${GROUP},${DSTNUM},${CIDNUM},${ID}); Dial(SIP/trunk/${DSTNUM}); }; }
The rules for handling incoming calls are a bit more interesting. Welcomes us with a proposal to dial an extension number, if the number is not dialed, then send a call to CRM:
context inc { 2758725 => { MSet(DSTNUM=${EXTEN}); MSet(GLOBAL(GROUP)=office1); Gosub(inc-crm,s,1(${EXTEN},${CALLERID(num)},${UNIQUEID})) ; }; } context inc-crm { s => { MSET(DSTNUM=${ARG1}); MSET(GLOBAL(CIDNUM)=${ARG2}); MSet(GLOBAL(ID)=${ARG3}); Background(welcome_message); &crm(${GROUP},${DSTNUM},${CIDNUM},${ID}); Gosub(redirect,${DB(crm/key)},1); }; }
We need the context inc in case we have more than one number for incoming calls, we assign some of the variables globally, as they will accompany us in different parts of the dialplan.
& crm ($ {GROUP}, $ {DSTNUM}, $ {CIDNUM}, $ {ID});
We send the first request to CRM. If the client is permanent, then CRM will return the number of the responsible manager, and our script will write it to AstDB (asterisk -rx "database put crm key XXX"). If a client is new or a responsible manager is not assigned to him, then CRM will return the group / queue number (this was a bit of a hassle in terms of sending start / stop requests)
Having received a treasured combination of numbers from CRM, we go on.
context redirect { 1000 => { &record-crm(${STRFTIME(,,%G/%m/%d/)}${ID}); &crm-group(${QUEUE_MEMBER_LIST(first)},,); Queue(first,tT,,,15,,,set-arg); }; _1XX => { &record-crm(${STRFTIME(,,%G/%m/%d/)}${ID}); &crm(${GROUP},${DSTNUM},${CIDNUM},${ID}); Dial(SIP/${EXTEN}); }; h => { NoOP(${MEMBERINTERFACE}); if ( ${EXISTS(${MEMBERINTERFACE})} ) { MSet(DSTNUM=${MEMBERINTERFACE:4}); &crm-end(${GROUP},${DSTNUM},${CIDNUM},${ID}); Hangup; }; &crm-group-end(${QUEUE_MEMBER_LIST(first)},,); }; }
1000 is the group number, a queue will be called here. In our example, the queue will be limited to 3 agents. If you want to increase the number of queue agents, add commas after $ {QUEUE_MEMBER_LIST (first)} and a few lines to macro crm-group / crm-group-end. Commas are needed to call a macro, i.e. you need to pass as many arguments as the macro waits, you can more accurately pass more arguments, but if you mention this in the dialplan, it will curse and will not work. $ {QUEUE_MEMBER_LIST (first)} Contains agents in the queue, in the end it turns out that we pass more than 3 arguments to the macro (agents + two empty arguments), but this is no longer a problem. The main thing is that there are no more agents than the accepted arguments in the macro, otherwise not everyone will get a popup window.
macro crm-group ( member1, member2, member3 ) { if (${EXISTS(${member1:4})) { MSet(DSTNUM=${member1:4})); &crm(${GROUP},${DSTNUM},${CIDNUM},${ID}); }; if (${EXISTS(${member2:4})) { MSet(DSTNUM=${member2:4}); &crm(${GROUP},${DSTNUM},${CIDNUM},${ID}); }; if (${EXISTS(${member3:4})) { MSet(DSTNUM=${member3:4}); &crm(${GROUP},${DSTNUM},${CIDNUM},${ID}); }; return; }
We check if there is an agent, designate it as the one who accepts the call and send a request for a pop-up window.
After that, the call goes to the first queue
Queue(first,tT,,,15,,,set-arg);
The main thing is not to get confused in commas. It seems to be written in the habr rules that you should not use smiles / brackets, but here I could not resist =)
The set-arg macro is called with the Gosub command, if the macro were recorded in extensions.conf, the call would have been written a comma earlier.
macro set-arg () { &crm-group-end(${QUEUE_MEMBER_LIST(first)},,); return; }
I failed to pass arguments from the Queue command, so I had to resort to this small macro.
macro crm-group-end ( member1, member2, member3 ) { if ( ${EXISTS(${member1:4}) ) { if (${member1:4}!=${CHANNEL(peername)}){ MSet(DSTNUM=${member1:4}); &crm-end(${GROUP},${DSTNUM},${CIDNUM},${ID}); }; }; if ( ${EXISTS(${member2:4}) ) { if (${member2:4}!=${CHANNEL(peername)}){ MSet(DSTNUM=${member2:4}); &crm-end(${GROUP},${DSTNUM},${CIDNUM},${ID}); }; }; if ( ${EXISTS(${member3:4}) ) { if (${member3:4}!=${CHANNEL(peername)}){ MSet(DSTNUM=${member3:4}); &crm-end(${GROUP},${DSTNUM},${CIDNUM},${ID}); }; }; return; }
Again, as with the start request, we check the presence of agents, compare the queue agent with the one who picked up the phone ($ {CHANNEL}) and, if there is no match, send the stop (we don’t need a pop-up window).
The manager talked with the client, the conversation is over, and we need to inform our CRM about it. Returning to the redirect context
h => { if ( ${EXISTS(${MEMBERINTERFACE})} ) { MSet(DSTNUM=${MEMBERINTERFACE:4}); &crm-end(${GROUP},${DSTNUM},${CIDNUM},${ID}); Hangup; }; &crm-group-end(${QUEUE_MEMBER_LIST(first)},,); };
Here we check the availability of $ {MEMBERINTERFACE}, in other words, whether the call was processed by one of the agents, if so, send to CRM stop for this agent, if the call is broken, then we send the stop to all agents of the queue.
It remains for us to consider the option with call transfer. In order not to lose clients during the transfer, we use the involved transfer (in features.conf I assigned #) to it. To supplement the transfer function of sending requests to CRM, reassign context for it. In my case, this is done for all calls, because I just added TRANSFER_CONTEXT = transfer in the globals section;
Go to the context itself:
context transfer { _1XX => { MSET(DSTNUM=${EXTEN}); &crm(${GROUP},${DSTNUM},${CIDNUM},${ID}); Dial(SIP/${DSTNUM}); }; h => { &crm-end(${GROUP},${DSTNUM},${CIDNUM},${ID}); }; }
We receive an incoming call, click # 100, CRM goes to start with number 100 (to whom we transfer the call) and customer number. The manager with the number 100 receives a popup window, his colleague can add a few words about the mood of the client and hang up. The transfer is complete. At this stage, a stop request is sent to call one manager to another.
At the end of the manager's conversation with the client, two stop requests will be sent - for the first and second managers, because they both talked to the client.
Author: system administrator of the
company Centos-admin.ru artzcom .