Skill Based Routing - Fehler im Skript

@Stefan,

I was a little bit too fast, the skill based routing script seems not to work correctly.
I tried with three agents with the same skill and each one get a call.
But now I tried with two agents with the same skill and one agent with a lower skill but still the lower skilled agents get calls even though the other are available.

I switched on the outputs in your script but cannot see the error.

Actually I cannot see any ouput from the sbr-script

The only thing I see: the extra script (set_topic) return nothing (‘db value is:’)

Do you have any idea?

Greetings Arne

Hi Arne,

I’ve modified set_topic script, please see above. One part was redundant.

In SBR script you can uncomment line

ast_verbose("Agent " … member.membername … " scores " … my_metric)

and in addition you can put the following line after the comment “somebody else is…”

ast_verbose("Agent " … other_member.membername … " has better score " … other_metric … " than " … member.membername … " with score " … my_metric)

Lets see what the output will be…

Kind regards,
Stefan

@Stefan

there seems to be something wrong with our configuration.
I debugged it now and it seems that there is absolutely no value for

channel[‘MDC_SKILL-’ … id]:get()

Our skill is in MDC_SKILL-23 so I tried to output it manually

for id=1,70 do
ast_verbose(channel[‘MDC_SKILL-23’]:get())
local level = channel[‘MDC_SKILL-’ … id]:get()
if level ~= nil and level ~= ‘’ then
table.insert(tt,id)
end
end

But I get an error in asterisk cli

pbx_lua.c:1438 exec: Error executing lua extension:
/etc/asterisk/mdc_extensions.lua:16: attempt to call global ‘ast_verbose’ (a nil value)

So why am I not getting the value back? Do you have any ideas?

Thanks for your support.

Cheers Arne

Hi Arne,

Please try to put logger inside the if block

if level ~= nil and level ~= '' then
   app.verbose('skill with id ' .. id .. ' has value ' .. level)
   table.insert(tt,id)
end

Kind regards,
Stefan

@Stefan,

that is what I tried first but without any logging.
So it seems that the line

local level = channel[‘MDC_SKILL-’ … id]:get()

will never get any return for the id 1 to 70. That is why I belive something is wrong with our config of the pascom?

Cheers
Arne

Do you set a skill value in some of the call routers or in the pre action of the queue? Also it should be set before invocation of the set_topic script.

Kind regards,
Stefan

@alipfert

Could you solve the problem with the weighted skill based routing?

@Stefan

Hello Stefan

Sorry we haven’t contacted you so long. We tried to solve the problem directly with the support, without success.

We have entered the above script in our frontend, but the effect is no different.

We would like to have a skill test first, then all agents with the highest skill should be selected and only then should the reputation strategy take effect. Example.
Agent 1 Skill 10
Agent 2 Skill 10
Agent 3 Skill 8
Agent 4 Skill 7
With an inbound, agents 1 & 2 are selected first, then the call is assigned according to the selected call strategy.

Enclosed you will find the script we are currently working with.

function init(queue)
** – ast_verbose("**** QUEUE " … queue.name)**
end

function cleanup()
** – ast_verbose("**** Cleanup ")**
end

function enter_queue(entry,vars)
** – ast_verbose("**** Enter queue")**
** for key,value in pairs(vars) do**
** _, , skill_id = string.find(key, "^MDC_SKILL%-(%d+)$")*
** if skill_id ~= nil then**
** – ast_verbose("Found skill " … skill_id)**
** ast_queue_log(entry.queuename,entry.uniqueid,“NONE”,“INFO”,“REQSKILL” … “|” … key … “|”… value)**
** end**
** end**
end

function calc_metric(member,entry,vars)

** – lookup the skills table for this agent**
** skillset = agent_skills[member.membername]**

** score=0**

** – traverse required skills**
** for key,value in pairs(vars) do**
** _, , skill_id = string.find(key, "^MDC_SKILL%-(%d+)$")*
** if skill_id ~= nil then**
** requiredlevel = tonumber(value)**
** – we can skip skills with a level of zero**
** if requiredlevel > 0 then**
** if skillset == nil then**
** – we require a skill but the agent does not have ANY skills,**
** – so skip this agent**
** – ast_verbose(“Agent " … member.membername …” has no skills")**
** return -1**
** end**
** – lookup required skill**
** level = tonumber(skillset[key])**
** if level == nil then**
** – Agent does not have the required skill**
** – so skip this agent**
** – ast_verbose(“Agent " … member.membername …” misses skill " … key)**
** return -1**
** end**
** if level<requiredlevel then**
** – Agents skill level is to low**
** – so skip this agent**
** – ast_verbose(“Agent " … member.membername …” skill " … key …" level to low: " … level …"<" …requiredlevel)**
** return -1**
** end**
** – sum up score (if using score )**
** score = score + level**
** end**
** end**
** end**
ast_verbose(“Agent " … member.membername …” has score " … score)
** – example for score calculation: negate score because lower value wins**
** – return 10000 - score**

** – zero means: consider this agent but use standard asterisk strategy for calling**
** return 0**
end

== Spawn extension (sub_hangup, unavailable, 1) exited non-zero on ‘Local/team-31@mdc_localdevice-13-000020e3;2’
– SIP/N7WhltJqLuxBHKw-000d7c35 is ringing
– Local/team-30@mdc_localdevice-13-000020e4;1 is ringing
– Local/101@mdc_multidial-101-000020e0;1 is ringing
– SIP/N7WhltJqLuxBHKw-000d7c35 answered Local/team-30@mdc_localdevice-13-000020e4;2
– Local/team-30@mdc_localdevice-13-000020e4;1 answered Local/team@mdc_locallocation-13-000020e2;2
– Local/team@mdc_locallocation-13-000020e2;1 answered Local/101@mdc_diallocation-000020e1;2
– Local/101@mdc_diallocation-000020e1;1 answered Local/101@mdc_multidial-101-000020e0;2
– Local/101@mdc_multidial-101-000020e0;1 answered SIP/mdc_trunk_conf-2-000d7c34
– Stopped music on hold on SIP/mdc_trunk_conf-2-000d7c34
== Spawn extension (mdc_localdevice-13, team-30, 7) exited non-zero on ‘Local/team-30@mdc_localdevice-13-000020e4;2’
== Spawn extension (mdc_locallocation-13, team, 3) exited non-zero on ‘Local/team@mdc_locallocation-13-000020e2;2’
– Locally bridging SIP/mdc_trunk_conf-2-000d7c34 and SIP/N7WhltJqLuxBHKw-000d7c35
== Spawn extension (mdc_diallocation, static, 1) exited non-zero on ‘Local/101@mdc_diallocation-000020e1;2’
== Spawn extension (mdc_multidial-101, 101, 8) exited non-zero on ‘Local/101@mdc_multidial-101-000020e0;2’
– Manager ‘phpasm’ from 127.0.0.1, hanging up channel: SIP/N7WhltJqLuxBHKw-000d7c35
– Executing [h@sub_main-139:1] Gosub(“SIP/mdc_trunk_conf-2-000d7c34”, “def_hangup,s,1(139,CALL)”) in new stack
– Executing [s@def_hangup:1] NoOp(“SIP/mdc_trunk_conf-2-000d7c34”, “>>>def_hangup:: EXTEN: 139 DIALSTATUS: QUEUESTATUS: REASON: CALL”) in new stack
== Spawn extension (sub_main-139, ext, 5) exited non-zero on ‘SIP/mdc_trunk_conf-2-000d7c34’
pascom*CLI> – Executing [ext@sub_prefix-139:73] Return(“SIP/mdc_trunk_conf-2-000d7c34”, “”) in new stack
– Started music on hold, class ‘Wartemusik_Auto’, on SIP/mdc_trunk_conf-2-000d7c34
— Agent Local/104@mdc_multidial-104 has score 10
— Agent Local/103@mdc_multidial-103 has score 10
— Agent Local/102@mdc_multidial-102 has score 10
— Agent Local/101@mdc_multidial-101 has score 8
– Called Local/101@mdc_multidial-101

should go to 104, 103 or 102

– Executing [ext@sub_prefix-139:73] Return(“SIP/mdc_trunk_conf-2-000d7c30”, “”) in new stack
– Executing [139-dial@mdc_team-4:3] Answer(“SIP/mdc_trunk_conf-2-000d7c30”, “3000”) in new stack
– Executing [139-dial@mdc_team-4:4] Gosub(“SIP/mdc_trunk_conf-2-000d7c30”, “sub_main-139,ext,1”) in new stack
– Executing [ext@sub_main-139:1] Set(“SIP/mdc_trunk_conf-2-000d7c30”, “__MDC_QUEUE_RINGINUSE=0”) in new stack
– Executing [ext@sub_main-139:2] Set(“SIP/mdc_trunk_conf-2-000d7c30”, “TMP_QUEUE_DIALOPTIONS=C”) in new stack
– Executing [ext@sub_main-139:3] ExecIf(“SIP/mdc_trunk_conf-2-000d7c30”, “0?Set(TMP_QUEUE_DIALOPTIONS=)”) in new stack
– Executing [ext@sub_main-139:4] Set(“SIP/mdc_trunk_conf-2-000d7c30”, “__PICKUPMARK=139”) in new stack
– Executing [ext@sub_main-139:5] Queue(“SIP/mdc_trunk_conf-2-000d7c30”, “IVR_Dextra,C,100”) in new stack
– Started music on hold, class ‘Wartemusik_Auto’, on SIP/mdc_trunk_conf-2-000d7c30
— Agent Local/104@mdc_multidial-104 has score 8
— Agent Local/103@mdc_multidial-103 has score 10
— Agent Local/102@mdc_multidial-102 has score 8
— Agent Local/101@mdc_multidial-101 has score 7
– Called Local/101@mdc_multidial-101

same same

@Stefan

Hello Stefan
do you have an idea how we could solve the problem mentionned above?
do we have to get in touch with your sales team directly?

Kindly
Sven

Hi @Sven,

Sorry for the late response. As far as I can see from the logs you need to uncomment line

return 10000 - score

and remove the next line

return 0

Kind regards,
Stefan

Hello Stefan

Thank you very much for your response. We have changed the skript.
Unfortunately the call allocation does not work properly yet. As you can see in the examples below, the lower priority agent is called first, then the agent with the highest skill. The call strategy works, but the skill levels are not taken into account. Do you have another idea?

Greetings

function init(queue)
– ast_verbose("**** QUEUE " … queue.name)
end

function cleanup()
– ast_verbose("**** Cleanup ")
end

function enter_queue(entry,vars)
– ast_verbose("**** Enter queue")
for key,value in pairs(vars) do
_, , skill_id = string.find(key, "^*MDC_SKILL%-(%d+)$")
if skill_id ~= nil then
– ast_verbose("Found skill " … skill_id)
ast_queue_log(entry.queuename,entry.uniqueid,“NONE”,“INFO”,“REQSKILL” … “|” … key … “|”… value)
end
end
end

function calc_metric(member,entry,vars)

-- lookup the skills table for this agent
skillset = agent_skills[member.membername]

score=0

-- traverse required skills
for key,value in pairs(vars) do
	_, _, skill_id = string.find(key, "^_*MDC_SKILL%-(%d+)$")
	if skill_id ~= nil then
		requiredlevel = tonumber(value)
		-- we can skip skills with a level of zero
		if requiredlevel > 0 then
			if skillset == nil then
				-- we require a skill but the agent does not have ANY skills,
				-- so skip this agent
				-- ast_verbose("Agent " .. member.membername .." has no skills")
				return -1
			end
			-- lookup required skill
			level = tonumber(skillset[key])
			if level == nil then
				-- Agent does not have the required skill
				-- so skip this agent
				-- ast_verbose("Agent " .. member.membername .." misses skill " .. key)
				return -1
			end
			if level<requiredlevel then
				-- Agents skill level is to low
				-- so skip this agent
				-- ast_verbose("Agent " .. member.membername .." skill " .. key .." level to low: " .. level .."<" ..requiredlevel)
				return -1
			end
			-- sum up score (if using score )
			score = score + level
		end
    end
end

ast_verbose(“Agent " … member.membername …” has score " … score)
– example for score calculation: negate score because lower value wins

-- zero means: consider this agent but use standard asterisk strategy for calling

end

– Executing [ext@sub_main-139:4] Set(“SIP/mdc_trunk_conf-2-00000e60”, “__PICKUPMARK=139”) in new stack
– Executing [ext@sub_main-139:5] Queue(“SIP/mdc_trunk_conf-2-00000e60”, “IVR_Dextra,C,100”) in new stack
– Started music on hold, class ‘Wartemusik_Auto’, on SIP/mdc_trunk_conf-2-00000e60
— Agent Local/106@mdc_multidial-106 has score 2
— Agent Local/105@mdc_multidial-105 has score 2
— Agent Local/102@mdc_multidial-102 has score 2
— Agent Local/101@mdc_multidial-101 has score 1
— Agent Local/100@mdc_multidial-100 has score 8
– Called Local/101@mdc_multidial-101


– Started music on hold, class ‘Wartemusik_Auto’, on SIP/mdc_trunk_conf-2-00000e63
— Agent Local/106@mdc_multidial-106 has score 2
— Agent Local/105@mdc_multidial-105 has score 2
— Agent Local/102@mdc_multidial-102 has score 2
— Agent Local/101@mdc_multidial-101 has score 1
— Agent Local/100@mdc_multidial-100 has score 8
– Executing [100@mdc_multidial-100:1] Wait(“Local/100@mdc_multidial-100-00001236;2”, “0.1”) in new stack
– Called Local/100@mdc_multidial-100

Hello @Sven

Maybe because of the bad formatting of the code but I can’t see that score is returned like I stated in my previous comment. Please check if

return 10000 - score

is invoked on the end

Kind regards,
Stefan

skript_13_09_2018.txt (2,0 KB)

Hello Stefan

Attached please find the script.

Kindly

Hi @Sven

sorry for the late responding, I was out of office for a longer time.
Today I took myself some time and debugged the script. Finally it is working, there was a little bug.

Find attached files and replace the set_topic script and the skill based routing script

Than you have to follow the guide from Stefan, include the set topic after you defined the label, but before entering the queue.

I hope it will help you a bit, I made a bunch of calls and it seems to work perfectly now.

Cheers
Arne

set_topic.txt (336 Bytes)
skill_based_routing.txt (5.3 KB)

Hello Arne

Thank you very much for your reply. Which values in the scripts need to be adjusted?
We are working with skilllevels 0-100.
Currently the appliance shows the following message:

tsk050202 : . Starte [luac -p /var/www/mobydickcmd//tmp/mdc_queue-4.lua]
2018-11-15 09:18:43 . Exit: [0]
2018-11-15 09:18:43 . Starte [luac -p /var/www/mobydickcmd//tmp/mdc_script-35.lua]
luac: /var/www/mobydickcmd//tmp/mdc_script-35.lua:145: ‘end’ expected (to close ‘function’ at line 122) near <eof>
2018-11-15 09:18:43 . Exit: [1]
2018-11-15 09:18:43 Validierung der Datei [mdc_script-35.lua] ist fehlgeschlagen
2018-11-15 09:18:43 . Starte [luac -p /var/www/mobydickcmd//tmp/tmp_script-36.lua]
2018-11-15 09:18:43 . Exit: [0]
2018-11-15 09:18:43 . Starte [luac -p /var/www/mobydickcmd//tmp/tmp_script-38.lua]
2018-11-15 09:18:43 . Exit: [0]
2018-11-15 09:18:43 Child-Task 050202 wurde mit [] beendet

Hi Sven,

i guess you need to modify the set_topic script. set the loop to your requirements:

for id=1,120 do

should be OK

I have no idea, why the script has an error, I will give you again mine which had no Problem when saving it.
By the way, we have the pascom 17 installed. I don’t know if it is important if you have an other version.skill_based_routing.txt (5.4 KB)