Jump to content

Tom Wellige

Root Moderator
  • Posts

    4,309
  • Joined

  • Last visited

  • Days Won

    117

 Content Type 

Profiles

SwyxPEDIA Wiki

Zendesk Integration

Persistent Variables

Longest Waiting

VBScript build in functions

GSE build in functions (VBScript)

Server Script API (VBScript)

GSE build in functions (Lua)

Server Script API (Lua)

Function Collection (VBScript)

Function Collection (Lua)

IPS Integration

Jira Service Integration

Forums

Blogs

Downloads

Blog Entries posted by Tom Wellige

  1. Tom Wellige
    VBScript
     
    Inspired by a question in the forum I spent a little bit more time not just giving a few hints as answer in the forum, but instead made a complete call routing script from it.
     
    There are cases in which you need to be able to replace an existing announcement of a user by recording a new one from within a call routing script.
     
    If this is done within the call routing of the user you need to replace the announcement for, this is a very straight forward task. 
     
     
    Lets assume the user has an announcement file "welcome.wav" which you need to replace by an new announcement.
     
     
    The idea for the call routing here is, that it checks if the caller is authorized to replace the announcement first. There are multiple ways to get this done, e.g.
     
    by checking the caller number ("Call" condition block, and then "Calls from caller ID (calling party number)") by asking the caller for a pin ("Get DTMF String" block and then "Evaluate" block to validate the entered pin, an example can be found here) check for specific post dialing digits (instead of asking the caller for a pin) or a combination of the above  
     
    You place this call routing on top of the list of rules in the call routing manager. This makes sure that regardless of what other call routing the user has activated, you will be able to call in and replace the announcement. If your call routing script figures that it is not you who is calling it just leaves the script via the "Rule skipped" exit to let let the rest of the users call routing handle this call.
     
    So once you have identified and authorized the caller your call routing could do the following:
     
    Play the current "Welcome.wav" announcement to make sure that this really is the announcement you want to replace Record a new announcement by using the "Record Message" block Save/upload this newly recorded message file into the SwyxWare database with the name "Welcome.wav". By doing so you overwrite the existing one. Play the "Welcome.wav" announcement again, to make sure that your recorded announcement has really been updated.  
    Of course this is just a suggestion. You can do what ever else you want/need to here. This just demonstrates how to do the replacement.
     
     
    The call routing script looks as simple as this:
     

     
    The "Call" block just does a simple caller verification and authentication by the caller number.
     

     
    The "Record Message" block places the name of the newly recorded wav file into the "sNewWelcome" variable.
     

     
    The "Insert Script Code" blok uses the PBXUser.UploadFile function from the Server Script API to upload the recorded file into the database and store it there with the name "welcome.wav". The previously existing file will be overwritten.
     

     
     
    You can download this simple rule via the following link:
     
    Replace Announcement.rse
     
    Open a new GSE rule, import this file via the "File | Import..." menu and save the rule.
     
    Now move the new rule on top of the list of your rules.
     

     
     
     
     
    Enjoy!
     
    PS: don't miss to take a look into the ECR Useful Link Collection.
     
     
  2. Tom Wellige
    VBScript Lua
     
    When it comes to develop call routing scripts with some own VBScript code in it, it might become handy to be able to have a look on what your code is doing.
     
    There are lots of so called "debugging" possibilities, but at this point you have to believe me, the only really reliably working method is placing your own log/trace information into the server trace file. 
     
    Before you say that those trace files are way too large and confusing for you, they are not, once you know how to read them and how to filter the stuff you are interested in out. In the forum post "How to filter SwyxWare traces for call routing output of a single call" I have explained already in detail how this can easily be done. So lets focus on how to get your own information into the server trace file.
     
    This can simply be done with PBXScript.OutputTrace (Vbs)/ PBXScript.OutputTrace() (Lua).
     
    For VBScript based Call Routing:
    PBXScript.OutputTrace "Hello World!"  
    For Lua based Call Routing:
    PBXScript.OutputTrace("Hello World")  
    So what should be written into the server trace and what not? And how will I find my own trace output quickly and easily?  
     
    By taking a look into the server trace file you figure that the SwyxWare traces quite a lot of stuff, not only errors but also tons of other information and events. You should do the same in your own VBScript/Lua code as well. Do not only trace errors your run into but also every kind of information that might become useful later on when you have to analyse the call routing if for some reason it doesn't work anymore like the many months before. The more information you place into the trace file the more easy it will become to pin point a problem later on. You might not even have to get into the script and work yourself into it if the traces are already informative enough.
     
    Lets assume you have written yourself a VBSscript/Lua function to do what ever you need to do, placed it into the Start block and call it later on e.g. in an Evaluate block.
     
    Taking all said above into consideration, that following is something like a "best practice" function template in terms of tracing.
     
    For VBScript based Call Routing:
    Function DoWhatever ( Parameter1, Parameter2 ) PBXScript.OutputTrace "---------> DoWhatever" PBXScript.OutputTrace "Parameter1 = " & Parameter1 PBXScript.OutputTrace "Parameter2 = " & Parameter2 On Error Resume Next Dim bReturn bReturn = False ' do what ever your function needs to do ' ... If Err <> 0 Then PBXScript.OutputTrace "Error while doing something!" PBXScript.OutputTrace "(Err) " & Err.Description Else PBXScript.OutputTrace "Successfully did something" End If ' if you "calculate" something, it is always a good idea to trace the result of it Dim sSQL sSQL = "SELECT * FROM MyTable WHERE value1 = " & Parameter1 & " AND value2 = " & Parameter2 PBXScript.OutputTrace sSQL DoWhatever = bReturn PBXScript.OutputTrace "bReturn = " & bReturn PBXScript.OutputTrace "<--------- DoWhatever" End Function  
    For Lua bsed Call Routing:
    function DoWhatever ( Parameter1, Parameter2 ) PBXScript.OutputTrace ("---------> DoWhatever") PBXScript.OutputTrace ("Parameter1 = " .. Parameter1) PBXScript.OutputTrace ("Parameter2 = " .. Parameter2) local bReturn = false local oResult = nil -- do what ever your function needs to do -- ... if (oResult == nil) then PBXScript.OutputTrace ("Error while doing something!") else PBXScript.OutputTrace ("Successfully did something") end -- if you "calculate" something, it is always a good idea to trace the result of it local sSQL sSQL = "SELECT * FROM MyTable WHERE value1 = " .. Parameter1 .. " AND value2 = " .. Parameter2 PBXScript.OutputTrace ("sSQL = " .. sSQL) PBXScript.OutputTrace ("bReturn = " .. tostring(bReturn)) PBXScript.OutputTrace ("<--------- DoWhatever") return bReturn end  
     
    Lets go through the template, step by step...
     
    The first and the last thing you function should do it to trace that you have entered and left it again.
     
    For VBScript based Call Routing:
    PBXScript.OutputTrace "---------> DoWhatever" PBXScript.OutputTrace "<--------- DoWhatever"  
    For Lua based Call Routing
    PBXScript.OutputTrace ("---------> DoWhatever") PBXScript.OutputTrace ("<--------- DoWhatever")  
    The arrows should tell you that you go into your function and go out of it again. All trace lines in between these two arrow lines will be made by your function. So they also help to find your stuff quickly.
     
     
    If your function takes parameters it is a good idea to trace them. If your function doesn't work and it get already come crap parameters it is not surprising that it fails later on.
     
    For VBScript based Call Routing:
    PBXScript.OutputTrace "Parameter1 = " & Parameter1 PBXScript.OutputTrace "Parameter2 = " & Parameter2  
    For Lua based Call Routing:
    PBXScript.OutputTrace ("Parameter1 = " .. Parameter1) PBXScript.OutputTrace ("Parameter2 = " .. Parameter2)  
     
    For VBScript based Call Routing: If you have disabled the standard error handling (will be part of a future blog post) you need to check every "dangerous" call yourself, if it succeeded or not. For example you try to write something into a text file it could happen that the file doesn't exist or is read only. Or you try to access a database which is currently not reachable. So if you check for the outcome of such a call do not only trace errors but also that it succeeded.
    If Err <> 0 Then PBXScript.OutputTrace "Error while doing something!" PBXScript.OutputTrace "(Err) " & Err.Description Else PBXScript.OutputTrace "Successfully did something" End If  
    For Lua based Call Routing:
    if (oResult == nil) then PBXScript.OutputTrace ("Error while doing something!") else PBXScript.OutputTrace ("Successfully did something") end  
     
    If you calculate something within your function, e.g. build an SQL statement to run against a database and use some current values (e.g. the function parameters) to do so, it is a good idea to write the result of this into the trace. To stay with the SQL statement example this will enable you later on to copy&paste the statement from the trace file and test it directly against your database.
     
    For VBScript based Call Routing:
    Dim sSQL sSQL = "SELECT * FROM MyTable WHERE value1 = " Parameter1 & " AND value2 = " & Parameter2 PBXScript.OutputTrace sSQL  
    For Lua based Call Routing:
    local sSQL sSQL = "SELECT * FROM MyTable WHERE value1 = " .. Parameter1 .. " AND value2 = " .. Parameter2 PBXScript.OutputTrace ("sSQL = " .. sSQL)  
     
    And finally, if your function returns a value, just trace this value.
     
    For VBScript based Call Routing:
    PBXScript.OutputTrace "bReturn = " & bReturn  
    For Lua based Call Routing:
    PBXScript.OutputTrace ("bReturn = " .. tostring(bReturn))  
     
    You don't need to put all trace stuff into your function from the beginning, while you are still developing it. But once it is finished and tested you should put trace output in it.  You can't trace too much information, just too few. The more information you trace the more easy it will become later on to identify a problem if the call routing script ceases to work.
     
     
    Enjoy!
     
    PS: don't miss to take a look into the ECR Useful Link Collection
     
  3. Tom Wellige

    VBScript
    VBScript → Lua
     
    Please note: there is also a version for Lua based Call Routing available: #17: Be more flexible on dates! (Part 2 - Lua)
     
     
    Within the GSE of you have a Time block which can be used to check (beside others) for time spans:
     

     
    You might noticed already that in here it is not possible to take the dates (or times) from within variables. So only hard coded time spans can be checked with this block.
     
    In case you need it more flexible and use variables this block can't be used. But the GSE wouldn't be the GSE if there wouldn't be another easy solution for this problem.
     
    We just have to do the comparison by ourselves with a little bit of VBScript. Within VBScript there is a DateDiff function available, which returns the difference of two dates in any needed unit, like days, weeks, months, years.
     
    Dim nDifference nDifference = DateDiff( "d", CDate("01.09.2019"), CDate("30.09.2019") )  
    This example calculates the difference between the 01.09.2019 and 30.09.2019 in days and stores it into a variable.
     
    If the second date is larger/later than the first date, the result is a positive number. If the second date is smaller/earlier than the first date, the result is a negative number. The function CDate converts a given date into a VBScript "date" data type.
     
    So to check if the current date is within a given time span, we need to call DateDiff two times. The first time to check if the current date is larger/later than the start date. The second time to check if the current date is smaller/earlier than the end date.
     
    To do this, we simply use two Evaluate blocks in a row. To check if the current date is within a given time span, where the start date and end date is given in variables, we can simply use two such blocks:
     

     
    with
     

     
    and 
     

     
    and
     

     
     
    Please note: in this example the start and end date are included in the time span. If you want them to be excluded from the time span just check for "> 0" instead of ">= 0".
     
    The current date is taken from the GSE build in function CurDate(). It would also be possible to use the VBSript function Now. The difference between both functions is, that CurDate() returns the date according the configured location time zone of the script user, while Now simply returns the date of the server machine.
     
    To put everything together into a handy little script I have configured the two variables for start and end date as parameters of the GSE script, so they can be easily set from the call routing manager. If I am on vacation my voicemail will be started, otherwise I want my regular call routing to be executed.
     

     
     
    Rule properties:
     

     

     
     
    And this is how it looks in the call routing manager:
     

     

     
     
    So with a little bit of VBscript and two Evaluate blocks we are able to check for time spans ourselves and don't need the static/hard coded Time block.
     
    You can download this tiny script from here:
     
    Vacation.rse
     
     
    Enjoy!
     
    PS: don't miss to take a look into the ECR Useful Link Collection
     

  4. Tom Wellige

    VBScript
    VBScript
     
    There is always one colleague in the group who is never answering group calls! Does this sound familiar to you?
     
    When connecting a call to a group it depends on the group configuration, how the call will be signaled to the group members:
     

     
    Parallel - all phones of all members ring simultaneously Random - one member is picked randomly from the group Rotary - the first call goes to member 1, the second call to member 2, a.s.o. Sequential - the call goes to member 1, if member one is not available (timeout, busy, not logged in) it goes to member 2, if member 2 is not available it goes to member 3, a.s.o. The next new call will go first to member one  
     
    In many cases these hunt group selections are sufficient, but there is one selection missing in the list which is getting asked for every once in a while: Longest Waiting/Idle
     
    The call routing of the SwyxWare wouldn't be the call rouging if this problem couldn't be fixed in there  
     
    What is needed is a reliable source of information when a certain user had is latest call (disconnect time). This information can be taken from the call detail records. For the ease of usage, they need to be written into a database instead of a text file (refer to Enreach Help Center article Write Call Details Records into a database).  Without going too much into details, we will add a small trigger onto this table. This trigger will be called for every newly added record, takes user name and disconnect time from it and stores it also into an additional table "LongestWaiting" into the database. When it is necessary to know when a certain user had his latest disconnect, one only needs to look into "LongestWaiting" table.
     
    We use a small GSE Action (comparable with a function in any programming language, it is just "written" with the GSE). 
     
    This GSE Action takes the group the call should be connected to as parameter (refer to my blog article #6: Make it easy!). It uses the GetUserByAddress method of the PBXConfig Server Script API to resolve all users from the given group. With the list of users the database (LongestWaiting" table will be queried to get a list of all users in the order of old disconnect time first. The GSE Action tries now to connect the call to the users in the list, starting with the first one. If this user is not available (timeout, busy, not logged in) it goes on with the second in the list, a.s.o.. It goes on until the call is either connected or the call wasn't taken by any user.
     
    The usage of this GSE Action is actually quite simple, it replaces the standard "Connect To" block
     

     
    by
     

     
     
    The GSE action takes a few parameters, with the "Destination" being the most important one. This is the group which the call should be delivered to with the new "longest waiting/idle" hunt group type.
     

     
     
    A complete description, manual and download can be found in the Longest Waiting Hunt Group project, being a part of the Open ECR Extensions project here on Swyx Forum.
     
     
    Enjoy!
     
    PS: don't miss to take a look into the ECR Useful Link Collection
     
  5. Tom Wellige
    VBScript
     
    Inspired by a question in the forum I spent a little bit more time not just giving a few hints as answer in the forum, but instead made a complete call routing script from it.
     
    Task: an incoming call should be provided to 4 different engineers, while in week 1 engineer 1 will get the call, in week 2 engineer 2 will get the call, a.s.o.
     
    In the following I will describe the my approach solving this problem and also how to use the resulting call routing scrpt.
     
    VBscript provides a function DatePart which can be used to evaluate the current week of the year. With that number it should be possible to identify a responsible engineer. 
     
    There are two approaches possible:
    somehow calculate the engineer from the week of the year number use a list of assigned weeks per engineer to identify the engineer from   
    I have decided to use a list of assigned weeks per engineer as this opens a very easy way of changing the call distribution in case of e.g. annual leave of one engineer. 
     
    Dim AssignedWeeks(4) AssignedWeeks(1) = "1,5,9,13,17,21,25,29,33,37,41,45,49" AssignedWeeks(2) = "2,6,10,14,18,22,26,30,34,38,42,46,50" AssignedWeeks(3) = "3,7,11,15,19,23,27,31,35,39,43,47,51" AssignedWeeks(4) = "4,8,12,16,20,24,28,32,36,40,44,48,52"  
    With having that the rest of the implementation is easy. I have implemented a function GetAssignedEngineer which simply returns the extension of an engineer (which are set via rule parameters in the final script).
     
    This function gets the week of the year number by the already above mentioned DatePart function and then loops through all 4 engineers if this number is part of their assigned weeks list.
    Function GetAssignedEngineer PBXScript.OutputTrace "----> GetAssignedEngineer" Dim sReturn sReturn = sDefaultExtenstion Dim nCurrentWeek nCurrentWeek = DatePart("ww", Now) PBXScript.OutputTrace "nCurrentWeek = " & nCurrentWeek Dim i For i = 1 To 4 If IsInAssignedWeeksList(i, nCurrentWeek) Then sReturn = Engineer(i) End If Next GetAssignedEngineer = sReturn PBXScript.OutputTrace "sReturn = " & sReturn PBXScript.OutputTrace "<---- GetAssignedEngineer" End Function  
    To check for each engineer if the current week is in his list of assigned weeks I have implemented a function IsInAssignedWeeksList which splits the above defined list of weeks into an array and then simply loops through this array to see if the current week is in it.
    Function IsInAssignedWeeksList ( nEngineer, nCurrentWeek ) PBXScript.OutputTrace "----> IsInAssignedWeeksList" PBXScript.OutputTrace "nEngineer = " & nEngineer PBXScript.OutputTrace "nCurrentWeek = " & nCurrentWeek Dim bReturn bReturn = False Dim aWeeks aWeeks = Split(AssignedWeeks(nEngineer), ",") Dim y, nWeek For y = LBound(aWeeks) To UBound(aWeeks) nWeek = CInt(aWeeks(y)) PBXScript.OutputTrace "nWeek = " & nWeek If nWeek = nCurrentWeek Then bReturn = True Next IsInAssignedWeeksList = bReturn PBXScript.OutputTrace "bReturn = " & bReturn PBXScript.OutputTrace "<---- IsInAssignedWeeksList" End Function  
    Please note, that in case the current week can not be found in any of the lists, the function GetAssignedEngineer returns a default destination. This will make sure that if the lists are getting modified and a week will be forgotten to be added, the function will provide a valid destination to connect the call to.
     
     
    The call routing script becomes straight forward with having all the logic implemented in VBScript code:
     

     
    All VBScript code can be found in the Start block. The Insert Script Code block is just used to copy the extensions from each engineer which can be comfortable configured as rule parameters into the VBScript code part of the call routing script.
     

     
    There is also a 5th parameter which defines the default number the call should be delivered to in case a week can't be found in any of the week lists.
     
    To connect the call to an engineer the Connect To block directly calls the GetAssignedEngineer function:
     

     
    If the call can't be delivered I have just added a Voicemail option to play it simply here. 
     
     
    And this sums the entire call routing up. One might say its overdone, but this is simply my style of call routing scripts, even including tracing information in case one needs to debug the script.
     
    You can use the following link to download the script (please note, that you need to be a logged in user of this forum in order to be able to download any file from here):
     
    EngineerRotation.rse
     
    To use this file simply open a new empty call routing rule with the GSE and the use File | Import... to import the above .rse file.
    A more complete explanation on how to get call routing functionality from A to B can be found in this blog article:
    #4: Take me to your leader!  
    In case you want to learn all the details behind the used rule parameters in this script, the following blog article will enlighten you:
    #6: Make it easy!  
    Enjoy!
     
    PS: don't miss to take a look into the ECR Useful Link Collection
     
  6. Tom Wellige

    General
    VBScript Lua
     
    If you have ever wondered if it is possible to use the SwyxWare call routing to build your own speaking clock, the answer is yes. Of course, otherwise I wouldn't blog about it here  
     
    As a matter of fact this was the very first call routing example in the Swyx Knowledgebase (kb2249) many moons ago (October 2002). As Swyx is taking the Knowledgbase out of service (and replaces it by articles in the Swyx Help Center) I have spent some time to scan through old articles and found this 17 years old example of a speaking clock (written by my former colleague Uwe). 
     
    I took the liberty and updated it a little bit (replaced some old techniques by Server Script API functionality which wasn't available back then) and provide it here again. 
     
    For VBScript based Call Routing:
    SpeakingClock.zip
     
    For Lua based Call Routing:
    SpeakingClock_Lua.zip
     
    How to use it?
    Take the .rse file from the above download and import it into the call routing of your desired user. If you need some help on this please refer to my previous blog post #4: Take me to your leader! You will also find a couple of .wav files in the above download. You need to upload them for the desired user as well. You can do this from within the GSE Play Announcement block
     

     
     
    or via the file properties of the server within the SwyxWare Administration (see above linked blog post for details).
     
    How does it work?

     
     
    The script welcomes the caller by saying "Good morning", "Good day" or "Good Evening" (depending of the time of the day) and the announces the current date.
      Afterwards it announces "At the next beep it is ..." followed by the time until the next full 10 seconds. It then waits until the next full 10 seconds are reached and play a beep. 
      From here on it repeats from step 2 until the caller disconnects the call  
     
    Hope you will find it useful. We have it running here in our SwyxWare now for 17 years.  I just figured that next year it will get of age  
     
     
    Enjoy!
     
    PS: don't miss to take a look into the ECR Useful Link Collection
     
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and have taken note of our Privacy Policy.
We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.