Dismiss Notice
We would like to remind you that we’re updating our login process for all 3CX forums whereby you will be able to login with the same credentials you use for the Partner or Customer Portal. Click here to read more.

Find amount of available Call Queue agents

Discussion in 'Call Flow Designer' started by SECOIT GmbH, Jun 24, 2017.

Thread Status:
Not open for further replies.
  1. SECOIT GmbH

    Joined:
    Apr 3, 2017
    Messages:
    66
    Likes Received:
    25
    Good afternoon,
    Unfortunately I must admit my programming skills became a bit rusty over the years and even I managed to get some CFD code running I'm stuck with this one.

    What I'm looking for:
    A function that returns the number of available agents for a certain queue so I can use it with a buffer variable at the following flow control condition.

    How do I define the amount of available agents for a certain queue?
    Imagine queue 800 has five agents: 101, 102, 103, 104, 105
    101 is logged into 800 but is talking right now - 101 available: 0
    102 is not logged into 800 - 102 available: 0
    103 is logged into 800, status is available, not talking at the moment - 103 available: 1
    104 is logged into 800, status is available, not talking at the moment - 104 available: 1
    105 is logged into 800, status is away, not talking at the moment - 105 available: 0

    So in this example the query for available queue 800 agents should return "2" (Sum of 0+0+1+1+0)

    I consider an agent available when ALL these conditions are met:
    - logged into queried queue
    - status available
    - not talking

    I was already digging through the 3CXObjectModel.2.0.0.0_v15.chm file but honestly I'm a bit lost with selecting the right methods. Also I'm not clear on how to use C# arrays within CFD.

    Any help or guideline is much appreciated!
    Thanks in advance!
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  2. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    1,611
    Likes Received:
    126
    Hi @SECOIT GmbH,

    To do this, you need to run some C# code from a Launch External Script component.

    For each extension, you need to check each of these properties:
    1) The property Extension.CurrentProfile contains the current profile of the extension (available, away, out of office, etc.). You can check the Extension.CurrentProfile.Name property to see which profile is active, and add 1 or not depending on that.

    2) In order to check if an extension is talking or not, you need to check the ActiveConnections for that extension. You can do that invoking:
    PhoneSystem.Root.GetDNByNumber("101").GetActiveConnections().Length > 0

    That expression will return true if the extension is talking, and false when it doesn't have any active call.

    3) The Extension.QueueStatus will tell you if the extension is logged in or not. Available values are QueueStatusType.LoggedIn and QueueStatusType.LoggedOut.


    Forgot to tell that first, you need to get the Extension object, so you can later check its properties. To do that, you can use:
    Extension ext101 = (Extension) PhoneSystem.Root.GetDNByNumber("101");


    Hope the information helps.

    Kind regards.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  3. SECOIT GmbH

    Joined:
    Apr 3, 2017
    Messages:
    66
    Likes Received:
    25
    Hi Ernesto,

    Great, many thanks!
    I'll give it a try and let you know if I managed to get it running and if so I'll share the complete code here.

    Best Regards,
    Michael
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  4. SECOIT GmbH

    Joined:
    Apr 3, 2017
    Messages:
    66
    Likes Received:
    25
    Hi Ernesto,

    One more thing...
    The only parameter I want to pass to this function to return the amount of available agents will be the Queue number.
    So before I can actually start with what you wrote above I guess I will need to get the queue agents first.

    I found "Members"property for the "Queue" class in the API documentation. Is that the right place where I can find all the agents assigned to a given call queue?


    Thanks,
    Michael
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
    #4 SECOIT GmbH, Jun 26, 2017
    Last edited: Jun 26, 2017
  5. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    1,611
    Likes Received:
    126
    Hi Michael,

    Yes, the Queue.Members property will return a "DN[]". You can iterate that array of DN objects, and cast them to Extension, so you can check the properties that I mentioned.

    Kind regards.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  6. SECOIT GmbH

    Joined:
    Apr 3, 2017
    Messages:
    66
    Likes Received:
    25
    Many thanks again! Great support!
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  7. SECOIT GmbH

    Joined:
    Apr 3, 2017
    Messages:
    66
    Likes Received:
    25
    Ok, thanks to Ernesto's help I got it working.

    In case someone's interested I'm sharing it here.
    Apologies for the ugly code, I'm a Network/Server/Phone guy and no programmer. But at least all seems to work.


    1. Create a text file "CountFreeAgents.cs", add the following code to it, place it into "Libraries" folder of your CFD project.

    Code:
    using TCX.Configuration;
    
    namespace FAgentsCount
    {
        public class FreeAgentsCount
        {
            public int CountFreeAgents(string strExtNumber)
            {
                Queue quCallQueue = (Queue) PhoneSystem.Root.GetDNByNumber(strExtNumber);
                DN[] dnQueueMembers  = quCallQueue.Members; /* Array dnQueueMembers contains all agents for the specified queue */
                bool bAgentFree = false;
                bool bAgentLoggedIn = false;
                bool bAgentAvailable = false;
                int iFreeAgents = 0;
    
                foreach (DN dnAgent in dnQueueMembers)
                {
                    Extension extAgent = (Extension) dnAgent;
                    bAgentFree = dnAgent.GetActiveConnections().Length==0;  /* No active calls */
                    bAgentLoggedIn = extAgent.QueueStatus == QueueStatusType.LoggedIn; /* Agent logged into queue */
                    bAgentAvailable = extAgent.CurrentProfile.Name == "Available"; /* Agent status equals to "Available" */
                    if (bAgentFree && bAgentLoggedIn && bAgentAvailable)
                    {
                        iFreeAgents += 1;
                    }
                }
                return iFreeAgents;
            }
        }
    }
    

    2. Add a "Launch external Script" component to your project and give it the following values:

    upload_2017-6-27_10-31-4.png

    Note: strExtNumber (in my test case 801) is the queue you want to check.

    I gave the component a name of "CountFreeQueueAgents"
    upload_2017-6-27_10-33-51.png


    3. Finally within the next blocks you can use the integer output by accessing "CountFreeQueueAgents.ReturnValue".

    upload_2017-6-27_10-35-50.png
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  8. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    1,611
    Likes Received:
    126
    Hey Michael, thanks for sharing and glad to see that you have it working!
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  9. clydevanwyk

    Joined:
    Aug 26, 2016
    Messages:
    2
    Likes Received:
    2
    This is probably one of the best community posts I have seen. @SECOIT GmbH mentions that he saw found "Members"property for the "Queue" class in the API documentation. where is this API Documentation? I would like to see what methods and objects and properties are available to me in C#.net core but I see nuget doesnt have a 3cx package. Where do we can a dll or something that can help us with all the object and properties and classes?
     
    teldata1 likes this.
  10. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    1,611
    Likes Received:
    126
    Hi @clydevanwyk,

    Take a look at this page:
    https://www.3cx.com/blog/docs/call-control-api/

    Download the ZIP containing the samples. The ZIP also includes a help file (extension CHM), which you can browse to get all the details of the 3CX API.

    Kind regards.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  11. SECOIT GmbH

    Joined:
    Apr 3, 2017
    Messages:
    66
    Likes Received:
    25
    Hey Ernesto,

    Guess I need to bother you again with this.
    I found a limitation of the code above - it checks only if an agent is globally logged in to all queues but it doesn't make a difference if he/she is logged on to the individual queue or not.

    Checking the docs looks like QueueAgent.QueueStatus is what I need to check if an agent is logged into an individual queue but after adding the code the results stayed exactly the same.
    So I wrote a quick program only checking how many agents are logged into an individual queue and doesn't matter if the agent is logged into the queue and/or globally - no difference. The result is always: QueueAgent.QueueStatus == QueueStatusType.LoggedIn so as soon as an agent is assigned to a queue it will count as LoggedIn.

    This is the code for the simple test program:

    Code:
    Queue quCallQueue = (Queue) PhoneSystem.Root.GetDNByNumber(strExtNumber);
    QueueAgent[] quQueueAgents = quCallQueue.QueueAgents;
    bool bAgentIndivLoggedIn = false;
    int iFreeAgents = 0;
    foreach (QueueAgent quQueueAgent in quQueueAgents)
    {
           bAgentIndivLoggedIn = quQueueAgent.QueueStatus == QueueStatusType.LoggedIn;
           if (bAgentIndivLoggedIn)
           {
               iFreeAgents += 1;
           }
    }
    return iFreeAgents;
    
    Is it possible that this is caused by QueueStatus being "For future use. (not supported yet)" according to the docs and therefore always returns "QueueStatusType.LoggedIn"?
    If that's the case is there any other way to check if an agent is logged into an individual queue (and not just the global login via Extension.QueueStatus)?

    On the other hand "Queue.QueueAgents" also says in the docs: "For future use. Array of queue agents." but it works perfectly well.
    Is there some "current" doc that shows what's actually implemented and what not? 3CXObjectModel.2.0.0.0_v15.chm seems not completely up to date.

    Thanks,
    Michael
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
    #11 SECOIT GmbH, Jun 28, 2017
    Last edited: Jun 28, 2017
  12. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    1,611
    Likes Received:
    126
    Hi Michael,

    That documentation is the latest version we have. Have you checked if "Queue.QueueAgents" returns the same elements than "Queue.Members" when some agent has logged out from a specific queue? I'm not sure, because I have not tried that part of the API, but maybe Queue.Members has the list of all members, while Queue.QueueAgents has only the ones logged in. Can you check that?

    Thanks.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  13. SECOIT GmbH

    Joined:
    Apr 3, 2017
    Messages:
    66
    Likes Received:
    25
    Good Morning Ernesto,

    Thank you for your help!
    I just tested it. Both "Queue.QueueAgents" and "Queue.Members" arrays always return the amount of agents assigned to a given call queue, no matter if they are logged into the individual queue or not and also if they are logged in globally to the queues or not. I even tested an extension that is offline (IP phone not connected) but it makes no difference.
    Both DN[] (for Queue.Members) and the QueueAgent[] (for Queue.QueueAgents) always show the amount of agents assigned to a certain queue. No matter what their status is.


    Best Regards,
    Michael
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  14. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    1,611
    Likes Received:
    126
    Hi Michael,

    I have the information you need. The individual queue status is saved in the property "LOGGED_IN_QUEUES" for the extension. But also, you will need to check if the active profile is overriding the queue status, so the method you would have to use in order to check if an extension is logged in to a queue or not is the following:
    Code:
    private bool GetQueueStatus(Extension ext, string qNum)
    {
        //Here we need to veryfy queue status which should be applied by system
        //we need to care about:
        //ext.IsOverrideActiveNow, ext.CurrentProfileOverride.ForceQueueStatus, ext.CurrentProfile.ForceQueueStatus
        //so:
        var status = ext.QueueStatus; // default value
        try
        {
            //currently active profile can force queue status
            //so if profile specifies something not equal -1 (means use global status) then we need to show status specified by profile.
            int profilequeuestatus = ext.IsOverrideActiveNow ? ext.CurrentProfileOverride.ForceQueueStatus : ext.CurrentProfile.ForceQueueStatus;
            if (profilequeuestatus != -1) //means overriden
            {
                status = (QueueStatusType)profilequeuestatus;
            }
        }
        catch
        {
            //status left as global
        }
        if (status == QueueStatusType.LoggedOut)
            return false;
        var prop = ext.GetPropertyValue("LOGGED_IN_QUEUES");
        if (prop == null)
            return true;
        if (string.IsNullOrEmpty(prop))
            return false;
        string[] strs = prop.Split(',');
        return strs.Contains(qNum);
    }
    
    That will give you the "desired" status (what the user has configured using the different login/logout options in profiles, login/logout to specific queue, etc.). But there is something else to consider, if the extension is not registered in 3CX, then the Queue Manager will consider the agent logged out, no matter what the previous function returns. So if you need a complete picture, you would have to also check if the extension is registered or not, but maybe for simplicity you can ignore that case...

    Kind regards.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  15. SECOIT GmbH

    Joined:
    Apr 3, 2017
    Messages:
    66
    Likes Received:
    25
    Hi Ernesto,
    First of all - many thanks!

    Still another question on this:
    The last line "return strs.Contains(qNum);" didn't work until I added "using System.Linq;".

    Now with this DLL for System.Linq I'm struggling with Linux. I really wanted to fix it myself but I'm giving up after a few hours.
    According to this https://www.3cx.com/docs/manual/cfd-troubleshooting/ the DLL needs to be present at "/usr/lib/3cxpbx" which it already was. Looks like it was already put to that location during installation amongst many others.
    After placing the DLL in various locations and even giving 777 permissions it's still keeps throwing the same exception:
    ERROR: Error executing last component: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'System.Linq, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

    So I installed a 3CX PBX in Windows, uploaded the app and got the same exception. This time the System.Linq.dll was supposed to be present at "C:\Program Files\3CX Phone System\Instance1\Bin" but it wasn't so I downloaded the file which was already present on my Linux PBX and copied it to Windows, restarted the services and now the app works on Windows.
    Btw, it works completely as expected there with all various options tested. Many thanks for this!

    But with Linux looks like I'm missing something. Copying the System.Linq.dll from Linux to Windows causes it to work in Windows but it's failing in Linux.
    Is there something in Linux that needs to be done like registering the DLL? I'm out of ideas after googling, reading manuals, trying various things...

    Thanks,
    Michael
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  16. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    1,611
    Likes Received:
    126
    Hi Michael,

    I think I know what is causing this problem. In the 3CX server the library System.Linq.dll is version 4.1.0, while in the CompilerDependencies of the 3CX CFD it's version 4.1.1. That's why in Linux that DLL can't be found, because the DLL found has a different version. In Windows the runtime must be accepting a slightly different version, but not in Linux.

    Please try this:
    1) Copy System.Linq.dll from the 3CX linux server to the CompilerDependencies folder in your CFD installation folder (C:\Program Files\3CX Call Flow Designer\CompilerDependencies).
    2) Re-build your CFD app
    3) Deploy it again to the Linux server.

    Please let me know if this solves the issue. We'll need to update the DLL in the CFD installer.

    Kind regards.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  17. SECOIT GmbH

    Joined:
    Apr 3, 2017
    Messages:
    66
    Likes Received:
    25
    Hi Ernesto,
    Thank you very much! That worked!

    Does it make sense if I use any other libraries when writing code to copy the library from the Linux PBX to the CFD compiler dependencies before actually compiling?

    Best Regards,
    Michael
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  18. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    1,611
    Likes Received:
    126
    Thank you very much for your confirmation Michael, we'll be including that version of the DLL in the final release.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  19. Ben FSUK

    Joined:
    Sep 10, 2017
    Messages:
    14
    Likes Received:
    3
    Hi all,

    I've been reading this thread with great interest, and will be showing it to the company that manages my 3cx system in the hope they can replicate something similar.

    If I am understanding this correctly, this process identifies if there are any agents in a particular queue and will only route the call to the queue if there are agents there to answer it, and if not then will check queue 2, then queue 3, etc.

    I can't help but wonder though, what would happen to the call if there were no agents available in either queue?
     
  20. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    1,611
    Likes Received:
    126
    Hi @Ben FSUK

    You can do whatever you want in that case. You can transfer the call to a specific extension, you can drop it, you can play a message, etc. That's up to you as the developer of the app...

    Kind regards.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
    jed likes this.
Thread Status:
Not open for further replies.