{"id":2581,"date":"2020-07-06T12:30:49","date_gmt":"2020-07-06T11:30:49","guid":{"rendered":"https:\/\/www.cyber-cottage.eu\/?p=2581"},"modified":"2020-07-06T13:28:05","modified_gmt":"2020-07-06T12:28:05","slug":"asternic-stats-and-recording-outgoing-calls","status":"publish","type":"post","link":"https:\/\/www.cyber-cottage.co.uk\/?p=2581","title":{"rendered":"Asternic Stats and recording outgoing calls."},"content":{"rendered":"\n<p><a rel=\"noreferrer noopener\" href=\"http:\/\/www.asternic.net\" target=\"_blank\">Asternic stats <\/a> has the ability to record your outgoing calls in the stats database so they can be accessed from stats package. <\/p>\n\n\n\n<p>But a customer noted two problems with this, firstly they wanted to set a different Music on Hold for outgoing calls and secondly &#8220;no answer&#8221; calls where the agent hungup before the callee answered.<\/p>\n\n\n\n<p>Firstly we will deal with the Music on hold, Changing the MoH class caused calls not to be recorded in the database correctly.  Code below is the reason for this as it causes the dial string to have 2 macros called, This is not possible.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><strong><em>extension_additional.conf:-<\/em><\/strong>\nexten =&gt; s,n,ExecIf($[\"${MOHCLASS}\"!=\"default\" &amp; \"${MOHCLASS}\"!=\"\" &amp; \"${FORCE_CONFIRM}\"=\"\" ]?Set(DIAL_TRUNK_OPTIONS=<strong>M<\/strong>(setmusic^${MOHCLASS})${DIAL_TRUNK_OPTIONS}))\n\n<strong><em>extensions_custom_asternic_outbound_freepbx.conf:-<\/em><\/strong>\nexten =&gt; _X.,n,Dial(${QDIALER_CHANNEL},300,g<strong>M<\/strong>(queuedial-answer^${UNIQUEID}^${GM}^${QDIALER_QUEUE}^${QDIALER_AGENT}^${ST}^${AMPUSER})${DIAL_TRUNK_OPTIONS})\n<\/pre>\n\n\n\n<p>The fix is very simple for this one and required just 2 changes. one line added to set MoH in the dialplan and another to use Trunk_options and not the the one created in extensions_additional.conf<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><strong>exten =&gt; _X.,n,Set(CHANNEL(musicclass)=${MOHCLASS}) ; Added to set the Music on hold class for the outgoing call Fixes bug in normal code<\/strong>\nexten =&gt; _X.,n,Dial(${QDIALER_CHANNEL},300,gM(queuedial-answer^${UNIQUEID}^${GM}^${QDIALER_QUEUE}^${QDIALER_AGENT}^${ST}^${AMPUSER})<strong>${TRUNK_OPTIONS}<\/strong>) ;Was ${DIAL_TRUNK_OPTIONS} changed to set the Music on hold class for the outgoing call Fixes bug in normal code<\/pre>\n\n\n\n<p>The second problem is also fairly straight forward but took a bit of creative thinking, The problem was when an agent hung up on an outbound call the dialstatus returned to the dialplan was &#8220;CANCEL&#8221; and this is not reported upon by the asternic stats package. SO as the call is for all intents abandoned we added a line that if the dialstatus was &#8220;CANCEL&#8221; we would change it to &#8220;ABANDON&#8221;. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">exten =&gt; h,n,Set(DIALSTATUS=${IF($[\"${DIALSTATUS}\"=\"CANCEL\"]?ABANDON:${DIALSTATUS})}) ;Added By Ian Plain to fix cancelled calls not showing in Asternic stats<\/pre>\n\n\n\n<p>This is a simple fix and now means calls are recorded as ABANDONED and with the time the Agent waited before hanging up.<\/p>\n\n\n\n<p>Below is our version of the file <strong><em>extensions_custom_asternic_outbound_freepbx.conf<\/em><\/strong> with all the changes.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[macro-dialout-trunk-predial-hook]\nexten =&gt; s,1,Noop(Test Track Outbound)\nexten =&gt; s,n,Noop(Trunk is ${OUT_${DIAL_TRUNK}})\nexten =&gt; s,n,Noop(Dialout number is ${OUTNUM})\nexten =&gt; s,n,Noop(Dial options are ${DIAL_TRUNK_OPTIONS})\nexten =&gt; s,n,Set(QDIALER_TRUNK_OPTIONS=${DIAL_TRUNK_OPTIONS})\nexten =&gt; s,n,Set(QDIALER_AGENT=${DB(AMPUSER\/${AMPUSER}\/cidname)})\nexten =&gt; s,n,GotoIf($[\"${QDIALER_AGENT}\" != \"\"]?nextcheck)\nexten =&gt; s,n,Noop(NO AMPUSER, exit normally with no tracking outbound)\nexten =&gt; s,n,MacroExit()\nexten =&gt; s,n(nextcheck),GotoIf($[\"${CDR(accountcode)}\" != \"\"]?bypass)\nexten =&gt; s,n,Noop(NO ACCOUNTCODE, exit normally with no tracking outbound)\nexten =&gt; s,n,MacroExit()\nexten =&gt; s,n(bypass),Set(PREDIAL_HOOK_RET=BYPASS)\nexten =&gt; s,n,Goto(queuedial,${OUTNUM},1)\nexten =&gt; s,n,MacroExit()\n;; Dialplan for storing OUTBOUND campaing in queue_log\n;; Goto(queuedial,YYYXXXXXXXX,1) where YYY is the queue-campaign code\n;; and XXXXXXXX is the number to dial.\n;; The queuedial context has the outobound trunk hardcoded\n[queuedial]\n; this piece of dialplan is just a calling hook into the [qlog-queuedial] context that actually does the\n; outbound dialing - replace as needed - just fill in the same variables.\nexten =&gt; <em>X.,1,Set(QDIALER_QUEUE=${CDR(accountcode)}) ;exten =&gt; _X.,n,Set(QDIALER_AGENT=Agent\/${AMPUSER}) exten =&gt; _X.,n,Set(QDIALER_AGENT=${DB(AMPUSER\/${AMPUSER}\/cidname)}) ; custom trunk check exten =&gt; _X.,n,Set(custom=${CUT(OUT<\/em>${DIAL_TRUNK},:,1)})\nexten =&gt; <em>X.,n,GotoIf($[\"${custom}\" = \"AMP\"]?customtrunk) ; it is normal trunk, not custom exten =&gt; _X.,n,Set(QDIALER_CHANNEL=${OUT<\/em>${DIAL_TRUNK}}\/${EXTEN})\nexten =&gt; <em>X.,n,GotoIf($[\"${OUT<\/em>${DIAL_TRUNK}<em>SUFFIX}\" == \"\"]?continuequeuedial) exten =&gt; _X.,n,Set(QDIALER_CHANNEL=${OUT<\/em>${DIAL_TRUNK}}\/${EXTEN}${OUT_${DIAL_TRUNK}<em>SUFFIX}) exten =&gt; _X.,n,Goto(continuequeuedial) ; it is a custom trunk exten =&gt; _X.,n(customtrunk),Set(pre_num=${CUT(OUT<\/em>${DIAL_TRUNK},$,1)})\nexten =&gt; <em>X.,n,Set(the_num=${CUT(OUT<\/em>${DIAL_TRUNK},$,2)})\nexten =&gt; <em>X.,n,Set(post_num=${CUT(OUT<\/em>${DIAL_TRUNK},$,3)})\nexten =&gt; _X.,n,GotoIf($[\"${the_num}\" = \"OUTNUM\"]?outnum:skipoutnum)\nexten =&gt; _X.,n(outnum),Set(the_num=${OUTNUM})\nexten =&gt; _X.,n(skipoutnum),Set(QDIALER_CHANNEL=${pre_num:4}${the_num}${post_num})\nexten =&gt; _X.,n(continuequeuedial),Noop(Qdialer channel = ${QDIALER_CHANNEL})\nexten =&gt; _X.,n,Set(QueueName=${QDIALER_QUEUE})\nexten =&gt; _X.,n,Goto(qlog-queuedial,${EXTEN},1)\n[qlog-queuedial]\n; We use a global variable to pass values back from the answer-detect macro.\n; STATUS = U unanswered\n; = A answered (plus CAUSECOMPLETE=C when callee hung up)\n; The 'g' dial parameter must be used in order to track callee disconnecting.\n; Note that we'll be using the 'h' hook in any case to do the logging when channels go down.\n;\nexten =&gt; <em>X.,1,NoOp(Outbound call -&gt; A:${QDIALER_AGENT} N:${EXTEN} Q:${QDIALER_QUEUE} Ch:${QDIALER_CHANNEL} Dialoptions:${TRUNK_OPTIONS}) exten =&gt; _X.,n,Set(ST=${EPOCH}) ;exten =&gt; _X.,n,Set(GM=${QDIALER_AGENT}) exten =&gt; _X.,n,Set(GM=${REPLACE(QDIALER_AGENT, ,<\/em>)})\nexten =&gt; _X.,n,Set(GLOBAL(${GM})=U)\nexten =&gt; _X.,n,Set(GLOBAL(${GM}ans)=0)\nexten =&gt; _X.,n,Macro(queuelog,${ST},${UNIQUEID},${QDIALER_QUEUE},${QDIALER_AGENT},ENTERQUEUE,-,${EXTEN})\nexten =&gt; _X.,n,Set(CHANNEL(musicclass)=${MOHCLASS}) ; Added to set the Music on hold class for the outgoing call Fixes bug in normal code\nexten =&gt; _X.,n,Dial(${QDIALER_CHANNEL},300,gM(queuedial-answer^${UNIQUEID}^${GM}^${QDIALER_QUEUE}^${QDIALER_AGENT}^${ST}^${AMPUSER})${TRUNK_OPTIONS}) ;Was ${DIAL_TRUNK_OPTIONS} changed to set the Music on hold class for the outgoing call Fixes bug in normal code\nexten =&gt; _X.,n,Set(CAUSECOMPLETE=${IF($[\"${DIALSTATUS}\" = \"ANSWER\"]?C)})\n; Trapping call termination here\nexten =&gt; h,1,NoOp( \"Call exiting: status ${GLOBAL(${GM})} answered at: ${GLOBAL(${GM}ans)} DS: ${DIALSTATUS}\" )\nexten =&gt; h,n,Set(DB(LASTDIAL\/${QDIALER_AGENT})=${EPOCH})\nexten =&gt; h,n,Goto(case-${GLOBAL(${GM})})\nexten =&gt; h,n,Hangup()\n; Call unanswered\nexten =&gt; h,n(case-U),Set(WT=$[${EPOCH} - ${ST}])\nexten =&gt; h,n,Noop(unanswered ${DIALSTATUS})) ;Added By Ian Plain to fix cancelled calls not showing in Asternic stats\nexten =&gt; h,n,Set(DIALSTATUS=${IF($[\"${DIALSTATUS}\"=\"CANCEL\"]?ABANDON:${DIALSTATUS})}) ;Added By Ian Plain to fix cancelled calls not showing in Asternic stats\nexten =&gt; h,n,Macro(queuelog,${EPOCH},${UNIQUEID},${QDIALER_QUEUE},${QDIALER_AGENT},${DIALSTATUS},1,1,${WT})\nexten =&gt; h,n,UserEvent(AgentComplete,Queue: ${QDIALER_QUEUE},TalkTime: 0,Channel: ${CHANNEL})\nexten =&gt; h,n,Hangup()\n; call answered: agent\/callee hung\nexten =&gt; h,n(case-A),Set(COMPLETE=${IF($[\"${CAUSECOMPLETE}\" = \"C\"]?COMPLETECALLER:COMPLETEAGENT)})\nexten =&gt; h,n,Noop(answered ${DIALSTATUS})) ;Added By Ian Plain to fix cancelled calls not showing in Asternic stats\nexten =&gt; h,n,Set(WT=$[${GLOBAL(${GM}ans)} - ${ST}])\nexten =&gt; h,n,Set(CT=$[${EPOCH} - ${GLOBAL(${GM}ans)}])\nexten =&gt; h,n,Macro(queuelog,${EPOCH},${UNIQUEID},${QDIALER_QUEUE},${QDIALER_AGENT},${COMPLETE},${WT},${CT})\nexten =&gt; h,n,UserEvent(AgentComplete,Queue: ${QDIALER_QUEUE},TalkTime: ${CT},Channel: ${CHANNEL})\nexten =&gt; h,n,Hangup()\n[macro-queuedial-answer]\n; Expecting $ARG1: uniqueid of the caller channel\n; $ARG2: global variable to store the answer results\n; $ARG3: queue name\n; $ARG4: agent name\n; $ARG5: enterqueue\n;\nexten =&gt; s,1,NoOp(\"Macro: queuedial-answer UID:${ARG1} GR:${ARG2} Q:${ARG3} A:${ARG4} E:${ARG5}\")\nexten =&gt; s,n,Set(QDIALER_QUEUE=${ARG3})\nexten =&gt; s,n,Set(QDIALER_QUEUE=${REPLACE(QDIALER_QUEUE, ,_)})\nexten =&gt; s,n,GotoIf($[\"${CUT(DB(AMPUSER\/${ARG6}\/recording),=,3)}\" = \"Always\"]?mixmonitor)\nexten =&gt; s,n,GotoIf($[\"${DB(AMPUSER\/${ARG6}\/recording\/out\/external)}\" = \"always\"]?mixmonitor)\nexten =&gt; s,n,Goto(continue)\nexten =&gt; s,n(mixmonitor),MixMonitor(${MIXMON_DIR}${YEAR}\/${MONTH}\/${DAY}\/out-${QDIALER_QUEUE}-${ARG1}.wav,b,\/usr\/local\/parselog\/update_mix_mixmonitor.pl ${ARG1} ${MIXMON_DIR}${YEAR}\/${MONTH}\/${DAY}\/out-${QDIALER_QUEUE}-${ARG1}.wav)\nexten =&gt; s,n,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes)\nexten =&gt; s,n(continue),Set(NOW=${EPOCH})\nexten =&gt; s,n,Set(WD=$[${NOW} - ${ARG5}])\nexten =&gt; s,n,Macro(queuelog,${NOW},${ARG1},${ARG3},${ARG4},CONNECT,${WD})\nexten =&gt; s,n,Set(GLOBAL(${ARG2})=A)\nexten =&gt; s,n,Set(GLOBAL(${ARG2}ans)=${NOW})\nexten =&gt; s,n,NoOp(\"Macro queuedial-answer terminating\" )\n[macro-queuelog]\n; The advantage of using this macro is that you can choose whether to use the Shell version\n; (where you have complete control of what gets written) or the Application version (where you\n; do not need a shellout, so it's way faster).\n;\n; Expecting $ARG1: Timestamp\n; $ARG2: Call-id\n; $ARG3: Queue\n; $ARG4: Agent\n; $ARG5: Verb\n; $ARG6: Param1\n; $ARG7: Param2\n; $ARG8: Param3\n;\n;exten =&gt; s,1,System( echo \"${ARG1},${ARG2},${ARG3,${ARG4},${ARG5},${ARG6},${ARG7},${ARG8}\" &gt;&gt; \/var\/log\/asterisk\/queue_log )\nexten =&gt; s,1,QueueLog(${ARG3},${ARG2},${ARG4},${ARG5},${ARG6}|${ARG7}|${ARG8})<\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Asternic stats has the ability to record your outgoing calls in the stats database so they can be accessed from stats package. But a customer noted two problems with this, firstly they wanted to set a different Music on Hold for outgoing calls and secondly &#8220;no answer&#8221; calls where the agent hungup before the callee [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":365,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"content-type":"","advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Asternic Call Center Stats and errors in recording outgoing calls. ","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[11,7],"tags":[23,179,204,178,40,205],"class_list":["post-2581","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-knowledge","category-technical","tag-asterisk","tag-asternic","tag-callcenter","tag-fop2","tag-freepbx","tag-reports"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.cyber-cottage.co.uk\/wp-content\/uploads\/2012\/12\/dial.jpg?fit=286%2C216&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p5daZy-FD","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/2581","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2581"}],"version-history":[{"count":2,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/2581\/revisions"}],"predecessor-version":[{"id":2583,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/2581\/revisions\/2583"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=\/wp\/v2\/media\/365"}],"wp:attachment":[{"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2581"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2581"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cyber-cottage.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2581"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}