Jarvis Pizzeria: Fourth step in Implementing the Order Processing, Decision Model

In our previous blog we gave an overview of the various type of decisions that are available for a Decision Model. In this blog we show by means of an example that Decision Models can also be used for making complex decisions. We are going to make a decision model that determines the order of preparation of the pizzas in an order.
The order of preparation is determined by the baking time, the total preparation time of each pizza and the number of available ovens (1 pizza per oven). Let's assume that we have an order for the following 9 pizzas:

  1. Small Margherita
  2. Large Margherita
  3. Small Pepperoni
  4. Medium Pepperoni
  5. Medium Pepperoni
  6. Large Pepperoni
  7. Small Quarttro Stagioni
  8. Medium Quarttro Stagioni
  9. Large Quarttro Stagioni

Expected outcome

The pizzas with the longest baking time are prepared first. When pizzas have the same baking time, the total preparation time is also taken into account to determine the order. As a result, to determine the sort order we first need to determine the baking time and total preparation time for each pizza. 
Because not all pizzas can be prepared at the same time, pizzas that are not in the oven will have a waiting time. Once we have established the order, we can also determine the waiting time per pizza. We explain this with the help of the figure below.

This image shows the desired output of the decision model when using 2 oven. Result is sorted based on the longest baking time and total preparation time. As soon as a pizza is baked, the next one is picked up. So as soon as the first one is finished, the third pizza is put in the oven, and as soon as the second one is finished, the fourth one is put in the oven. And then when the third is ready we go on with the fifth. And so on. Based on the sorting, however, the second has a shorter time as the first one. The order of the first two pizzas is therefore reversed. For the same reason, the order of the first 3 must be reversed for 3 ovens and the order of the first 4 for 4 ovens.
It may be difficult to see, but the waiting time for the different pizzas is determined as follows: - the first 2 can immediately go into the oven. They have no waiting time. - third waits for the first - fourth is waiting for the second - fifth waits for the first and third - sixth waits for second and fourth - seventh is waiting for first, third and fifth - eighth wait for second, fourth and sixth - ninth finally wait for first, third, fifth and seventh And for the completeness, when using 3 ovens we expect the following outcome:
And with 4 ovens:
For now we are determining the order of the pizzas within one of the orders, using this logic on multiple orders to determine what pizzas to prepare first is not supported yet.

Steps from Input to Output

Now lets see how to come from the input to the required output. We have the following steps to get from the input to the output:

  1. calculate baking time and total preparation time
  2. sort order by time
  3. apply sort order correction
  4. calculate waiting time

1. Calculate baking time and total preparation time

1.1 Pizza Level

We start by calculation the baking time. The baking time depends on the pizza type and size. For this we made a reusable function with a decisiontable in it.

For the duration another custom ‘getPreparationTime’’ function is used. This function determines how long it will take to prepare the pizza bottom or to add the filling.

Without getting into all the details, this function shows the usage of some default functions like ‘list’, ‘index of’, ‘number’ and ‘string’. This function returns 2 for a small pizza, 3 for a medium and 4 for a large pizza. When the size is none of these the functions return 0.

After getting the baking time the total duration can be determined. For this we have created a simple expression function.

1.2 Order Level

Now that we have defined the reusable functions to calculate the baking time and the total duration we need to apply these functions on the list of pizzas in the order.

Again we have defined a custom function. The function contains an expression with a for loop. For every pizza in the order, the following custom function (updatePizzaDetails) is called. In this call we also see that the previously defined functions for determining the times are used.

The ‘updatePizzaDetails’ function is a simple setter. A context with expressions.
Now we have also defined the function to perform the time calculations on the list. Calling this function is the last step for this part.
After calling this function we have the list that can be sorted.

2. Sort the order

For this, we will use the standard 'sort' operation. The sorting criteria that we use here are defined in a separate function.
The sorting criteria is in the Sorter.desc function.
Here we see, as mentioned earlier, that there is sorting on the baking time and on the total preparation time.

3. Sort order correction

At the expected output we have indicated that the order at the beginning of the list must be adjusted depending on the number of ovens. So first we have to define how many ovens there are. This can easily done by defining a 'constant' for the number of available ovens.
By changing this value, it is determined which of the above outputs the decision model gives. Next we defined a custom function with an if-then-else decision to correct the sort order.
Again we see the use of a number of standard functions. In this case all list related functions. In the 'then' part the first x-pizzas (depending on the number of ovens) are reversed. In the 'else' part the list remains unchanged. Normally, the list could simply be returned here, but this is currently not working properly. This results in a type casting error. As work-around the sublist function can be used, which also selects the entire list in our situation. Finally we have to apply this function on the order/list.

4. Calculate waiting time

As the fourth and last step, the waiting time has yet to be calculated. Earlier in this blog we have already indicated how the waiting time is calculated. This we have incorporated into a decision table. This is shown below. The point of attention in this table is the used hit policy. This is C. Which means as much as "The output consists of a list of all matching rules".

And ofcourse apply this function.

Expected outcome summarized

We have summarized these 4 steps in a context.
As outcome of the overall decision model we are only interested in the outcome of the fourth step. To complete the order, the customer data is also added. The final output of the complete decision model then becomes:

This output is available in the PCS process that is using the Decision Model.

Jarvis Pizzeria: The various Decisions of a Decision Model

In one of our next posts we will implement the Decision Model in the Order Process. Before we do that we first explain the various type of decisions that are available for a Decision Model.

The Decision Model editor in PCS (Process Cloud Service) or the later OIC (Oracle Integration Cloud) supports the DMN (Decision Modeling Notation) standard version 1.1, and uses FEEL (Friendly Enough Expression Language) to make decision modeling easier and more intuitive.

In DMN all decision logic is represented as ‘boxed expressions’. A ‘boxed expression’ is a graphical notation for decision logic. Within OIC we recognize the following boxed expressions:

The expressions in the boxes are FEEL expressions. A Decision Model is a tree of simple decisions notated as FEEL expressions. In the remainder of this blog we will give an example of the various boxed expressions.

The first example is a boolean expression with the name ‘SmallPizza’. The expression is true when the size of the pizza is ‘Small’. Otherwise it’s false.

In the second example we have the named (crustArea) expression to calculate the pizza crust area.

Next we have the if-then-else construction. Actually, this is no more than a combination of 3 expressions. The first determines which of the following 2 is returned as a result.

This construction could also be defined with the following single expression

Decision Table

The Decision Table is by far the most complex and ridge boxed expression. In this post we limit ourselves to a single example and an explanation of the available hit policies.

The following table returns the required baking time for each type of pizza. The baking time is independent of the size, except for the Quattro Stagioni, the Small pizza requires a minute less than the other sizes. To get the correct outcome from the Decision Table we have to set the hit policy. By default it is set to U(nique). But that will not work for this. There are 2 rules that a small Quarttro Stagioni meets. We want the first rule to be met. We do this by setting the hit policy to F(irst) in the upper left corner.

The following list shows the available Hit Policies. Here we are not going to treat them in detail.

The Unique hit policy is used when at most 1 rule can match the input
The Any hit policy is used when multiple rules can match the input, but the output value is the same for all matching rules
The First hit policy is used when multiple rules can match the input. The first hit by rule order is returned.
The Priority hit policy is used when multiple rules can match the input.The matching rule with the highest output priority is returned.The priority is defined by the order of output values in the decision table output column header
The Collect hit policy is used when multiple rules can match the input, and a list of output values for all the matching rules is desired
The Collect with sum hit policy is used when multiple rules can match the input, and the sum of the output values for all the matching rules is desired
The Collect with min hit policy is used when multiple rules can match the input, and the smallest output value for all matching rules is desired
The Collect with max hit policy is used when multiple rules can match the input, and the largest output value for all matching rules is desired
The Collect with count hit policy is used when multiple rules can match the input, and the count of the matching rules is desired

Next we come to the context box. A context is a list of key-value pairs.
In this example a list of 'constants'. The key must be unique, when duplicated, only the last one survives. In the example we used expressions, but it is possible to use any type that suits your needs, for example decision tables. In a context it is possible to reference entries that are defined higher in the context (like the fullname, that is using size and name).

A context is a list of key-value pairs and a list is a list of values without the key. It’s pretty straight forward.

Next is a relation. A relation is a shorthand for multiple contexts (a list of contexts).

Let’s convert this relation into a flat FEEL expression. We will do this in two steps. The first step is to present the relation as a list.

The next / second step is to transform this list into one single expression.

The last one is the function. Functions are used to get a reusable piece of code. You can feed them with parameters. A function can contain any of the other boxed types in its body. But that is not that special. Without explicitly mentioning it we already did it before. In the context we used nested expressions.

The following function checks whether the pizza size is 'Small', 'Medium' or 'Large'. If that is the case, the cooking time is calculated. For a 'Small' pizza that is 2, a 'Medium' 3 and for a 'Large' it is 4 minutes.

The ‘index of’ function returns all occurrences of the size in the list. For our solution this could only be one occurrence. We get this single occurrence as an entry in a list. That’s why the first entry is selected and convert to a string and thereafter into a number.
In this function we used a few of the available build-in functions. We won’t get into details about all of them in this blog. In a later blog we will pay special attention to these build-in functions.

Jarvis Pizzeria: Activating activities and attaining milestones

In our previous blogs we have given a brief overview of the look-and-feel of the dynamic process possibilities within PCS. In this blog we take a dive into the activation of activities, how milestones can be attained and how rules are configured to make sure that the correct actions are triggered when conditions are met.

Let's take a look at our dynamic Jarvis overview first. In the picture below we came up with three stages: ordering, preparation and delivery.

Obviously we start the preparation phase after the ordering stage has completed. This configuration is shown below:

In here we have selected the “Preparation”-stage and clicked the edit-pencil. In the “Conditions”-tab one can choose to add Activation conditions and Termination conditions. Because we want to start preparing the pizza after the order stage completes, our activation condition is configured as in the picture below:

There is no need for us to specify termination conditions. When all activities in the preparation phase are completed and when the Prepared milestone has occurred then the stage will auto-complete. A possible use-case for termination can be that an event comes in that the order has been cancelled. Let’s see how that would look like. We create a global activity “Order Cancellation” (for the example it doesn’t really matter what type of activity this is)

Now we can configure the termination condition for the preparation phase:

One might notice that our stage has two icons added to it showing the presence :

Another way of adding a condition is by means of data, hence the “Data driven” name. To do this we have to add a Data Object that tells us whether the order has been cancelled.

The orderCancelled boolean can be set by an activity to flag that the order has been cancelled. In the Termination settings we can then specify which value “orderCancelled” must have in order to meet the condition:

Which will lead to the following result:

We have configured the activation and termination conditions of the Preparation stage. The same holds for the configuration of activities.
For milestones however, we can configure when a milestone completes. In our example, the Prepared-milestone is completed when the “Prepare Pizza” activity is completed.

Note that revoking milestones is not possible. The stage of a milestone is either “Created” or “Occur”, as is depicted below:

This wraps up the blog about activation and termination. The ones familiar with Oracle ACM might notice the look-and-feel which has improved drastically. The readability of the case as a whole has become very easy. PCS dynamic processes supports the user by provisioning the drop-down boxes with all the names of the processes and activities, making the life of the developers very easy. The only noticeable difference we encountered was the lack of the possibility to revoke a milestone. However, this might end up having dynamic process that is less complicated!