[RE-POST from individual to Group]
Since you mentioned the Play Application block, I perceive that you are starting in a .workflow file, creating your object and giving the object its data. Then, you use the Play Application block to specify a .callflow file, and you open your call flow file in Composer and expect to have that data to work with.
That's not going to happen.
Call flows can pass to sub callflows and workflows can pass to sub workflows, but you can't pass directly between callflows and workflows.
BUT THERE IS A METHOD that does work. You have to utilize user data or "KVPs".
But first, an explanation.
The Orchestration server (ORS) loads and executes workflows that have been converted to SCXML, while a different server altogether, the Media Control Processor server (MCP) loads and executes call flows that have been converted to VXML.
Since workflows and callflows are loaded and executed
on different servers, the only way to share data is through the common server that is talking to them both -
SIP server. ORS can read-write to user data that's passed to SIP server, and so can MCP server.
So! This is the simplest method, and other developers may pipe in here and offer suggestions that will work just fine. We each have our own best practices.
1) In your WORKFLOW, open the variable editor and create a variable, either project variable or user variable. Set its value to {} - just like that... an open curly bracket and a closed curly bracket. This indicates to the ECMA engine that its an object. Its unnecessary though. you could just as well leave it undefined. But using this {} as a value will convey to other developers that we have an object.
2) In you WORKFLOW, use an ECMA block to add keys and values to your object, as discussed in the previous post. Then use the genesys function setuData() to send the key/value pars in that object to SIP server to be stored in user data (as well as in local ORS memory for that interaction). You can find this function in Expression builder on the left if you search on 'setuData'. Here is an example:
_genesys.ixn.setuData(j_vehicles, system.InteractionID)
There is no return value - it is known as 'void' - so you don't have to assign a variable like you do with other functions.
3) In your WORKFLOW, use a PlayApplication block to launch your callflow.
4) in your CALLFLOW,
create variables WITH THE EXACT SAME NAMES as any of the KEYS that you used in your object in your workflow. For example, in my workflow, I created j_vehicles, and it had this data:
j_vehicles.color = "Maroon"
j_vehicles.model = "F150"
j_vehicles.make = "Ford"
When I used the j_vehicles object in the setuData() function to write user data, ORS sent three key/value pairs of data to the SIP server: {"color":"Maroon","model":"F150","make":"Ford"}. So in my CALLFLOW, I have to create variables that match the names of those keys: 'color' and 'model' and 'make'.
5) In your CALLFLOW, use the Interaction Data block to select variables that, with a variable name matching the KEY name from user data, will be filled with the values from user data.
a) Set property 'Operation' to the value "get" (should be the default)
b) click on the 'Values' property and the VALUES window will pop up where you can click the check box next to
the variables you created.
Now, your data from the ORS workflow is sitting in the MCP server's call flow variables.
But guess what? SIP server has them too! When the CALLFLOW is finished executing and ORS regains control after the Play Application block, you may want to delete several of those KVPs in User data, depending on what you created. (alternately, write new KVPs or change existing KVP data to pass data back to ORS)
To delete a KVP in user data, in your WORKFLOW, use an ECMA block to call the deleteuData() function and specify the keys you want to delete. Example:
_genesys.ixn.deleteuData('color',system.InteractionID);
If you are daring, you can send a string of JSON (object notation) as a KVP so that you can perform a JSON.parse([variable]) and extract your KVPs as you would from an object. Afterward, you only have one KVP to delete. But I would master this method in DEV first, then use more advanced methods for your production run.
Keep in mind that ICON gets access to all the KVPs for reporting, and that too many KVPs will slow down your SIP server performance, so use them smartly, do your clean up and keep them wisely.
Happy coding!
------------------------------
Todd McCall
Bank of America
------------------------------
Original Message:
Sent: 08-22-2018 14:56
From: Amauri de Oliveira
Subject: Session persistence between callflows and subcallflows
Hello Todd.
I tried your approach and its working fine for me, perhaps I found a problem while passing tje JSON object to a callflow as a parameter. If I print the JSON object on the workflow prior to pass it to a callflow as a parameter, everything appears to be fine, perhaps if I log the input parameter right after the entry block on the callflow, it appears to me on the mcp logs as "undefined".
I´m wondering if this has something to do with the way how the Play Application Block works (via gvp communication dn on the sip server). Could you please let me know if you have this working on your projects (passing the json object as a parameter to a callflow)
Thanks in advance,
------------------------------
Amauri de Oliveira
Alctel Telecom
http://amaurioliveira.com
Original Message:
Sent: 08-17-2018 09:51
From: Todd McCall
Subject: Session persistence between callflows and subcallflows
I LOVE objects! They're extremely useful and ORS uses them almost exclusively.
First lest get some terms straight: JSON - Java Script Object Notation.
If I want to show you what is in my object, I will use the notation of an object as defined byJavaScript (technically ECMA) . To say "I am using a JSON object" is redundant. "My JavaScript object is represented using JSON."
Enough of semantics. :-)
Here is an example of declaring an object and assigning its contents using JSON:
var j_vehicles = {"make":"Ford","model":"F150","color";'Maroon"};
My object has three key:value pairs:
j_vehicles.make == "Ford"
j_vehicles.model == "F150"
j_vehicles.color == "Maroon"
Optional methods for declaring an object variable:
var j_vehicles = new Object();
var j_vehicles = {};
Declaring the object these last two methods requires a specific method for creating keys and values as described later.
These methods of declaring all work for me in a Composer ECMA block, but we would need a Java developer to chime in here to tell us what the best method is and why. :-)
Now for manipulation of data:
To convert the object into a string variable, I would use the JSON.stringify() function like this:
var s_vehicles = JSON.stringify(j_vehicles);
This method is REQUIRED to put an object's contents in a LOG file, otherwise you get "object:object" in the log.
The s_vehicles string variable now has the string '{"make":"Ford","model":"F150","color";'Maroon"}'.
Conversely, I can make the string into an object using JSON.parse(). Example:
j_vehicles = JSON.parse('{"make":"Ford","model":"F150","color";'Maroon"}'); (make sure you use a string)
If you want to get a specific value from an object, like the value of the key 'model', specify the variable name and the key value like this:
s_model = j_vehicle.model;
The s_model string variable now has the string 'F150' in it.
To change the value of an object key, I can directly reference it in the same way:
j_vehicles.color = 'Blue';
Lets add a new key and its value to the existing object variable:
j_vehicles['year'] = "1997";
Now put your thinking cap on as I explain my favorite use of searching through objects, the For loop:
for (var k in j_vehicles){
if(k = 'color'){
s_color = j_vehicles[k];
}//end if
}//end for
In this example, I defined the variable "k" and the for loop gives that variable the value of each key in the object with every loop, and stops looping when it runs out of keys.
Within each loop, variable "k" is the name of the key for comparison's sake, and that key's value can be referenced using square brackets to reference the key name.
If "k" = 'color', then j_vehicles[k] returns "Maroon" (or "Blue" if you are holding me to a higher standard of programming) :-)
Another cool trick:
var a_keys = Object.keys(j_vehicles);
Variable a_keys is now an array variable with the contents ["make","model","color","year"] and the function a_keys.indexOf("color") returns integer value 2.
Finally, any key in the object can contain another list of key:value pairs, defining multiple, complex levels of data. Example:
j_vehicles =
{
"summer":{
"type":"boat","color":"white"
}
,"winter":{
"type":"snowmobile", "color":"black"
}
}
Fetch values from the object:
j_vehicles.winter.color == "black"
j_vehicles["winter"]["color"] == "black"
Fetch values using variables for key names:
s_season = "winter";
s_param = "color";
j_vehicles[s_season][s_param] = "black"
There's more to learn at https://www.w3schools.com/js/js_objects.asp. W3Schools formed the foundation of my knowledge of JavaScript.
Composer is building JavaScript that Orchestration Server executes, and ORS 8.1 has the JavaScript ECMA version called SpiderMonkey from 2015, so you have to be careful about using newer JS functions that work in your JavaScript tester. They may not work in ORS. ('undefined' errors abound) You are free to use all of these object examples I am showing you in ORS 8.1.
Happy coding!
------------------------------
Todd McCall
Bank of America
Original Message:
Sent: 08-16-2018 09:25
From: Amauri de Oliveira
Subject: Session persistence between callflows and subcallflows
Hello Todd McCall.
Thanks for your suggestions.
The JSON approach should be enough to achieve what I want. Do you have any example that I can use as a template ?
As I mentioned on the initial post, I've done something like this in the past but the ECMA Script library to handle the JSON was not available in composer by default. It was a proprietary one that we developed in our team.
Thanks again for your quick response.
------------------------------
Amauri de Oliveira
Alctel Telecom
Original Message:
Sent: 08-13-2018 12:22
From: Todd McCall
Subject: Session persistence between callflows and subcallflows
Amauri,
You can pass variables to the subcallflow using the Parameters property of the Subdialog block. Create a variable in your SUBcallflow and change it from type 'user' to type 'input'. then when calling the subcallflow, use Parameters to specify the values you will be passing to the input variable in the subcallflow.
Consider creating object (JSON) variables so that with one pass, you have multiple values to use.
The other method is to use ApplicationRoot variables, which are available to all callflows in the project. You can define root variables by editing the /src/ComposerRoot.vxml file. This file is specified in the Entry block of your main callflow and will be executed to create those variables you specify.
If you pass variables to a subcallflow, and you change them, and you want them to perist, MAKE SURE that in the EXIT block of your SUBcallflow, you pass back the variables you changed.
------------------------------
Todd McCall
Bank of America
Original Message:
Sent: 08-10-2018 11:04
From: Amauri de Oliveira
Subject: Session persistence between callflows and subcallflows
Hello There.
Is there any standard implementation of a session object to be used with composer voice applications ? The idea is to add parameters to a session object using the ECMA script blocks and pass a single session object containing whatever was added in the call flow to the next subcallflow.
I remeber using a proprietary support library to implement this concept of session in composer a few years ago, perhaps it was a proprietary script. Life was a lot easier while handling variables between subcallflows.
Thank you all in advance.
------------------------------
Amauri de Oliveira
Alctel Telecom
------------------------------