With our Vocabulary ready we can now focus on modeling the rules. Let’s begin with the first Rulesheet, which will model the rules in the Raise Alerts substep.

Before we build or model anything, we need to think about how to approach this part of the problem.

The business rule we identified for the Raise Alerts substep examines all items in a customer’s shopping cart and determines which items (if any) come from the Liquor department.

As you may remember, each Item has a barcode. The department code occupies the 4th thru 6th characters of the barcode. Let’s assume that the department code for liquor is 291. So if an item has 291 occupying the 4th through 6th characters of the barcode, the cashier must be alerted to check the customer’s identification.

Keeping this in mind, we will define two rules in Corticon Studio:

  • The first will determine the department code for every item in the shopping cart
  • The second will determine if any of the items come from the Liquor department and if so, the rule will raise an alert of some kind.

As you can see, there isn’t always a one-to-one correlation between the business rule defined in a business scenario and the corresponding rules modeled in Corticon Studio. This is normal. A good guideline is to keep your individual rules relatively simple and let them work together to perform more complex logic defined by the business rules.

Create the Rulesheet

Before we start defining the rules, we need to create a Rulesheet.

Name the Rulesheet checks, and then click Next.

media/image33.png

Click groceryStore.ecore as the Vocabulary.

media/image34.png

We’ve named this Rulesheet checks as a way of reminding ourselves of the overall organization—this Rulesheet will perform any necessary checks and raise alerts as required. Click Finish.

Define rule scope

We need to choose the “point of view” in the Vocabulary that best represents the terms required by the rules themselves. This is called the scope of the rule. The scope changes from Rulesheet to Rulesheet.

Scope is a powerful and important concept. Scope determines which entity instances and attributes are evaluated and acted upon by a rule. For the first Rulesheet, we want to define rules that act only on Items that are associated with a ShoppingCart, which in turn is associated with a Customer. Using Customer as the “root” entity and working with the associated shoppingCart and its items makes sense because it’s a Customer’s transaction that is processed by the Checkout step. This will form the scope of the rules in the Rulesheet.

media/image35.png

Let’s define the scope. Display the Scope pane of the Rulesheet by ensuring that checks.ers is open and active and selecting Rulesheet > Advanced View.

media/image36.png

The Scope pane opens in the Rulesheet. Drag and drop the Customer entity from the Rule Vocabulary view into the Scope pane.

media/image37.png

Drag shoppingCart (under Customer) into the Scope pane and drop on Customer..

media/image38.png

To complete the Scope, drag and drop item (under shoppingCart) into the Scope pane.

media/image39.png

Next, let’s enter an Alias for a customer’s shopping cart and call it currentCart. To do this, double-click shoppingCart in the Scope pane and enter currentCart. From now on, when we model rules involving a customer’s shopping cart, we’ll use the Alias currentCart to represent the perspective of a customer’s shopping cart.

media/image40.png

We know that a shopping cart can contain many items. Let’s define another Alias that represents all the items in a customer’s shopping cart. Give it the Alias items.

media/image41.png

Assigning meaningful alias names is a good practice and using the plural form of item reminds us that the Alias represents all the items in the customer’s shopping cart.

Using Aliases is optional in many cases – they serve to simplify and shorten rule expressions. But in certain cases, using aliases is mandatory. For example, applying collection operators to sets or collections of data in rules requires the use of aliases. Since we’ll be working with the collection of items in a customer’s shopping cart a bit later, we must have the items alias defined and ready.

Aliases will always insert themselves automatically when terms are dragged and dropped from the Scope section or Vocabulary window to the Rulesheet. Since all Studio expressions are case-sensitive, it’s better to drag and drop terms instead of typing them manually, which can cause errors.

Model the first rule

We decided earlier that in order to model the business rule for the Raise Alerts substep, we need to create two rules in Corticon Studio in the checks Rulesheet:

  • Rule 1: Determine the department code for every item in the shopping cart.
  • Rule 2: Use the department code to determine if any of the items come from the Liquor department and if so, raise an alert.
Let’s start modeling the first rule—determining the department codes. We know an item’s department is identified by the 4th through 6th characters in the item’s barCode. So using the items alias, let’s add an action-only rule in an Actions row of Column 0 using the String operator .substring as shown.
Note: A preferred user language might use different separator symbols than those documented for decimal values, list ranges, and dates. Here, you might need to write substring(4;6).

media/image42.png

The expression items.department=items.barCode.substring(4,6) extracts the characters from positions 4 to 6 in the barcode string and assigns the substring to items.department. The checkbox in the corresponding cell of Column 0 indicates that this is an action-only rule. The rule fires whenever any data is received by the Rulesheet. Action-only rules fire first in the Rulesheet. In our example, this is useful because we need to extract the department code first before we can identify if any items come from the Liquor department.

Remember that the alias items represents the collection of all items associated with a customer’s shopping cart. So this rule will evaluate and process every item in a customer’s shopping cart, extract the department code for each, and then assign that code to the item’s department attribute. This iteration is a natural behavior of the rule engine: it will automatically process all data that matches the rule’s scope.

Notice that when you dragged the terms barcode and department from the Vocabulary to the Action row, they were automatically added to the Scope pane. Over time, the Scope pane becomes a reduced version of our Vocabulary, containing only those terms used by the rules in that Rulesheet.

Save the Rulesheet.

Test the first rule

Next, let’s test our first rule. Create a Ruletest

Name the Ruletest checks, and then choose the test subject checks.ers.

In the Input pane of the Ruletest, define a customer with an associated shopping cart containing two items—one of which is from the Liquor department.

First, drag and drop the Customer entity into the Input panel. Then, drop shoppingCart (under Customer) onto the Customer entity. Finally, drag and drop item (under shoppingCart) onto the shoppingCart entity twice. Note: It is critical to drop the items from the Vocabulary into the Input panel of the Ruletest in the order indicated so that we duplicate the Scope of the rule which will be processing this data.

When finished, enter test data as shown.

Note: A preferred user language might use different separator symbols than those documented for decimal values, list ranges, and dates. Here, you might need to write the price of Miller Beer as:
6,990000

As you can see, one of the items is from the Liquor department (remember that the department code for Liquor is 291 and this occupies the 4th to 6th characters in the barcode).

Finally, execute the Ruletest. The output should look like this.

Our first rule has worked as expected. Characters 4-6 have been successfully parsed from each item’s barCode and assigned to its department attribute.

By modeling a rule and then immediately testing it, we have demonstrated a good Studio modeling practice. Testing right away will help expose flaws in our rules as we go along.

Model the second rule

Now that department codes are readily available for every item in a customer’s shopping cart, we need to determine if any came from the Liquor department.

This requires us to “look inside” our Collection of Items to see if there exists an item with department = ‘291’. Since we only need one “check ID” alert per checkout transaction, this is a job for a collection operator.

A collection operator, because it “acts on” collections, will evaluate once per collection and not once per item as the previous rule did. In other words, we only need one “check ID” alert if the shopping cart contains any liquor. We don’t need, say, 5 alerts if the shopping cart contains 5 liquor items.

Making use of the items alias, let’s add a Condition for the second rule that determines if any Liquor items exist in the customer’s shopping cart. To do this, we use the Collection operator →exists. The →exists operator checks if a specific value exists for an attribute in the entity instances in the collection. In this case the collection is items. So the condition expression is items->exists(department=‘291’). Note: Always use plain single-quote marks to specify a text string.

Then define an Action for the second rule to assign a value of true to the shopping cart’s checkID attribute if any are found. (We’re assuming that the checkID term will act as the alerting mechanism to signal the cashier that an ID check is required during this checkout transaction.)

The second rule will look like this:

As mentioned earlier, using aliases to represent collections is mandatory when collection operators (like →exists) are used.

Add rule statements for each rule as shown:

media/image47.png

Test the second rule

Now, let’s re-run the same Ruletest as before:

media/image48.png

As you can see, our Condition/Action rule has worked as expected. A customer’s shopping cart containing an item from the Liquor department has been identified, and the checkID attribute is set to true to alert the cashier to check the customer’s ID. Notice that the business rule statement has also been posted in the Message Box. Often, a simple message is all we need to raise an alert or warning.

Note: Ordinarily, we’d check for Conflicts and Completeness before testing with data. But since we are focusing on advanced rule modeling features in this Tutorial we are skipping the Analyze phase of the rule development lifecycle.

Add more rules to the checks Rulesheet

We have implemented two rules representing the first business rule in the checks Rulesheet. We will use this Rulesheet to model two more rules:

  • Check if a customer has a preferred account
  • Add the total price of items in a shopping cart

We will use the output of the first rule in the next Rulesheet to filter out customers who do not have preferred accounts, since it contains promotional rules that apply only to preferred account holders.

The second rule, that calculates total price, must be included in the first Rulesheet, since the second Rulesheet filters out customers who don’t have preferred accounts, and we want to calculate the total price for every customer.

Check if a customer has a preferred account

Any customer who has a Preferred Account will have an associated preferredCard. So, let’s begin by defining the scope. Drag and drop preferredCard under Customer in the Rule Vocabulary to the Scope pane. Give it the Alias account.

media/image49.png

The account alias represents a “potential collection”, that is, a customer will have a Preferred Card only if they have a Preferred Account. And the “many-to-one” nature of the association means a customer will have at most one account. Other customers (as with a family) may share the same Preferred Account. For Customers who don’t have Preferred Accounts, the alias account represents an empty collection (the collection contains no elements).

The →notEmpty collection operator checks a collection for the existence of at least one element in the set. We can use this operator to check if a customer has a preferred card. Because notEmpty is “acting on” a collection, the account alias must be used with it.

Model a Boolean condition in row b in the Conditions pane that uses the →notEmpty collection operator as shown. If the account alias is not empty, we know the customer has a preferred account.

media/image50.png

Let’s add an action to this rule that assigns the value of true to the isPreferredMember attribute (from the Customer entity) and posts an informational message as shown. Recall that isPreferredMember is a transient attribute. Its value will only be used in the rules.

media/image51.png

Now, whenever we need to know if a customer is a preferred customer, we simply refer to the value of the isPreferredMember attribute. This method of “flagging” an entity with a Boolean attribute (also known as a “flag”) is convenient when modeling larger Ruleflows. The value of the flag, like all attributes, will carry over to other rules in this and other Rulesheets in the same Ruleflow.

Now, let’s test this rule. For our rule to detect the presence of a Preferred Card account associated with a customer, we need to provide the appropriate test data. Drag and drop the preferredCard entity onto the Customer entity in the Ruletest Input. Note: If you don’t get the identical indented structure as shown, delete the entity and try again.

media/image52.png

Run the Ruletest.

Notice that the isPreferredMember transient attribute has been inserted and assigned a value of true, and that an informational message has been posted. Our rule has worked as expected.

Calculate the total price of items in a shopping cart

Finally, we’ll add one more action-only rule to calculate the totalAmount of all items in a customer’s shopping cart. To do this, use the collection operator →sum as shown. The →sum operator will add up the price attributes of all elements in the items alias, and then assign that value to the totalAmount attribute.

Now, add a rule statement for this rule. Adding rule statements is good practice, even if you don’t post them as messages.

Finally, let’s test this rule. In the Input pane of the Ruletest shown here, we have a customer with two items in their shopping cart. Let’s see if our last rule calculates the totalAmount for the items in the Customer’s shopping cart.

Run the Ruletest.

A lot has happened in this Ruletest. First, note that our rules to determine if an ID check is required and if the customer is a Preferred Card holder still work as before. It’s always good to double-check cumulative test results to make sure nothing has broken along the way. Also, notice that the totalAmount attribute has returned a value of 8.98, which is the correct sum of the prices of items 1 and 2. This shows that our latest rule also works as expected.

We have now completed modeling and testing our first Rulesheet.