Let’s take a quick look at what you did in the first Rulesheet
(checks.ers):
Defined an action-only rule to extract the department code from the
barcode of each item.
Defined a rule to identify the presence of any items from the Liquor
department, and if present, to raise an alert.
Defined a rule to check if a customer is a preferred card holder.
Finally, you defined another action-only rule to calculate the total
price of items in the shopping cart.
Now, you are ready to model the second Rulesheet. Recall that the second
Rulesheet corresponds to the second substep in the Checkout process.
In the second Rulesheet, you apply some promotional rules to the preferred
account holders when they spend a pre-defined amount of money or buy items from specific
departments at the store. The promotions may change frequently, but modeling them in
Corticon makes future changes much easier.
Create the Rulesheet
Create a second Rulesheet under the MyAdvancedTutorial rule project.
Name it coupons.
Ensure that it uses the groceryStore.ecore Vocabulary.
Define the rule scope
To define the rule scope:
Open the Scope pane, by selecting Rulesheet > Advanced View.
Like in the checks.ers Rulesheet, build the scope around the Customer
entity, to apply promotional rules to each preferred customer.
Define the rule scope as shown:
Assign the alias currentCart to a customer’s shopping cart, just like
in the checks.ers Rulesheet.
Create two new aliases (allItems and sodaItems)to define the
currentCart.item perspective of the data.
Use the account alias to represent the preferredCard account
associated with the customer.
Save the Rulesheet.
Create a Ruleflow
Before you define rules in the coupon.ers Rulesheet, let’s create
a Ruleflow and add the checks.ers and the coupons.ers Rulesheets to it.
When multiple Rulesheets are included in a Ruleflow (a single .erf
file), the Rulesheets execute in a sequence determined by their Rulesheet order in the
Ruleflow.
At this point, it is good to create a Ruleflow so that instead of
testing only the Rulesheet as you develop it, you can test the whole Ruleflow, which
represents the decision step that needs to be automated. It enables you to test not only
the rules as you define them in the Rulesheet, but also how the Ruleflow works, and how
the rules behave as part of the Ruleflow. This way, you can detect and fix problems
earlier in the lifecycle.
Create a Ruleflow as follows:
Right-click the MyAdvancedTutorial rule project in the
Project Explorer view and select File > New > Ruleflow.
In the Create New Ruleflow wizard, in the File name
field, type MyAdvancedTutorial, and click Next.
Confirm that groceryStore.ecore is selected as the Vocabulary, and then click
Finish.
The Ruleflow opens in its editor.
Now let's add Rulesheets to the Ruleflow:
Drag checks.ers from the Rule Vocabulary view, and
drop it in the Ruleflow editor.
Drag coupons.ers from the Rule Vocabulary view, and
drop it to right of the checks.ers Rulesheet.
Click Connection in the Palette pane.
Note: The Ruleflow Palette
for JavaScript does not have the Service Call-out and Iterative
options.
Select and hold checks.ers, and drag the connection to
coupon.ers. The Ruleflow shows the Rulesheet processing sequence.
Save the Ruleflow.
Define a Filter in the coupons.ers
Rulesheet
Now, let’s go back to the coupons.ers Rulesheet. Before you
continue modeling promotional rules, filter out customers who do not have preferred
accounts because the promotional rules apply only to customers who have a preferred
account card.
Define a Filter expression. A Filter expression, which acts to limit or
reduce the data in working memory to only that subset whose members satisfy the
expression. A filter does not permanently remove or delete any data, it simply excludes
data from evaluation by the rules in the same Rulesheet.
The data satisfying the Filter expression survives the filter, and data
that does not satisfy the expression is filtered out. Data that has been filtered out is
ignored by other rules in the same Rulesheet.
Note: Data filtered out in one Rulesheet is
not also filtered out in other Rulesheets unless you include the Filter expression in
those Rulesheets, too.
Create a Filter expression in the Filters pane.
The Filter expression (Customer.isPreferredMember=T) filters out
all non-preferred customers by allowing only those customers with an
isPreferredMember attribute value of true to pass (survive).
Those customers whose isPreferredMember attribute value is not
true are filtered out and not evaluated by other rules in this
Rulesheet.
Define a rule to calculate
cashBackEarned
The first rule you define in the coupons.ers Rulesheet is to
calculate cash back for every preferred customer.
Define an action-only rule (with a rule statement) as shown:
The action row A in column 0 calculates the
cashBackEarned for a customer’s total purchase. This rule defines the
formula as the totalAmount of all items in the customer’s shopping cart
multiplied by 0.02, which is the same as 2% of totalAmount.
Note: Often, it’s desirable to
use another Vocabulary attribute (a parameter) to hold a value, such as the
percentage used in this formula, rather than hard-coding it (as in 0.02). If the
value of an attribute such as cashBackRate is derived by other rules or
maintained in an external database then it can be changed without changing the
rule that uses it.
Save the Rulesheet.
Test this rule as part of the Ruleflow. Testing at the Ruleflow
level ensures that Rulesheets are processed in the correct sequence and allows the
values derived in prior Rulesheets to be used in subsequent Rulesheets.
Create a Ruletest named coupons1. Ensure that the test
subject of the Ruletest is the MyAdvancedTutorial.erf Ruleflow.
To test the rule, provide input data where the customer is a
preferred account holder. Add a few items to the shoppingCart and enter names
and prices for each of them by entering details in the Input pane of the
Ruletest:
Note: According to this rule, the
shopping cart of a preferred cardholder should earn cash back worth 2% of
the totalAmount in the shopping cart.
Note: Because the list of items
contains an item from the Liquor department, based on the rules in the
checks.ers Rulesheet, (part of this Ruleflow), an alert should be
raised.
Run the Ruletest.
The rule has worked as expected. The totalAmount attribute now
has a value of $98.99 (as calculated by a rule in checks.ers) and the
cashBackEarned attribute has been assigned a value of $1.9798 or 2% of
$98.99.
After calculating the cash back earned, you need a rule to add it to
cumulative cash back.
Note: In our third
Rulesheet, you define a rule to address the scenario where a customer wants to apply
their cumulative cash back to a purchase.
Define an action-only rule as shown:
Action row B in Column 0 calculates
cumulativeCashBack amount in a customer’s account by incrementing its value
(using the += Decimal operator) by cashBackEarned in the current shopping
cart.
Add a rule statement with dynamic data
You should define rule statements that contain dynamic data—where the
value of an attribute is extracted and added to the rule message. It can provide more
meaningful and informative rule messages.
In this case, the value of cashBackEarned and
cumulativeCashBack to be part of the rule message, so enclose the attributes
in curly braces in the rule statement as shown:
Save the Rulesheet.
Test the rule
Create a Ruletest named coupons2.ert that uses
MyAdvancedTutorial.erf as its test subject.
To test that cash back earned is being added to cumulative cash
back:
note the starting amount for cumulative cash back and the total amount for the
shopping cart.
In the test input define a customer who is a preferred account holder, whose
cumulative cash back is $10, and whose total amount (for the shopping cart) is
$100.
Note: Because you have already
tested this Ruleflow’s ability to sum up the prices of each individual item to
calculate a totalAmount, do not enter individual item prices again.
Define the input as shown here:
Note: When building
Ruletests, if a Rulesheet’s Filters are not satisfied, they may prevent the rules
from executing. This Rulesheet has a Filter expression that filters out all
customers who aren’t Preferred Card members. So this test has a customer who is a
preferred account holder in our test, to ensure that the Filter is satisfied, and
the new rule model has a chance to execute.
Run the test. The rule works as expected. It calculates the cash back earned ($2) based on
the total amount ($100), and adds it to the cumulative cash back ($10), giving it the
updated value of $12. Notice that the rule message also contains this data.
Define a promotional rule for customers
purchasing from the Floral department
Now that the cumulative cash back rule is complete, let’s move on the
next business rule:
For every item purchased from the Floral department, a coupon must be
issued for a free balloon. Let’s assume that the Floral department has the department
code 290.
Define a rule in coupons.ers.
The first Condition in this Rulesheet is used to identify any items
purchased from department 290 (the Floral Department). For each item identified,
give the customer a coupon (using the Entity operator .new) for a free
balloon.
You assign the value of 12/31/9999 to the
expirationDate attribute, which is one way to indicate that the expiration
date is indefinite. This is the appropriate date format for this use case. Your
preferred format might be 31/12/9999 or any one of the dozen date
formats defined in Corticon.
Note: While
JavaScript has one output format for a dateTime, its input format for a dateTime can be
any of several familiar formats.
Note: There are other ways to set an
indefinite expiration date. For example, the entity CouponDefine a rule to
calculate cumulative cash might have a Boolean attribute named expires, to which
a true or false value could be assigned inside the .new expression.
Save the Rulesheet.
Testing the rule
Create a Ruletest named coupons3.ert
Define the input data.
Ensure that when an item has been purchased from the Floral
Department (department 290), a new Coupon is created entitling
the customer to one free balloon.
Set cumulativeCashBack to 0 for this test. One of the
rules in the coupons.ers Rulesheet (in Action row B, column 0)
needs a real initial value of cumulativeCashBack to increment. If its initial
value is null, the rule will not fire.
Run the test.
Note: In the JavaScript product
the default output format for dateTime as:
The rule has worked as expected. Department 290 has been recognized and
the informational message has been posted. The new Coupon entity has been
created, displaying a value of One Free Balloon in the description
attribute and 12/31/9999 in the expirationDate attribute, indicating that
the coupon will not expire.
The new message has been posted containing the value of
allItems.name embedded in it.
Define a promotional rule for customers
purchasing more than 3 soda/juice items
Let’s move on to the next business rule:
This rule must create a $2 off coupon when a customer buys three or
more items from the Soda/Juice department. While determining whether any items from the
Floral Department were in the shopping cart, you used the allItems
alias. But to determine if three or more items were purchased from the Soda/Juice
department, you do not need to count all items in a shopping cart, just those from the
Soda/Juice department. You use the sodaItems alias you defined earlier in the
scope section.
To reduce the collection of items in the shopping cart to only those
you want to count, use a Filter expression to filter the sodaItems alias.
Let’s assume that the department code for the Soda/Juice department is 285.
Define a Filter expression as shown:
The filter in row 2 ensures that the surviving members of the
sodaItems alias all have a department code of 285.
Now, let’s model the rule. The Collection operator →size counts
the number of elements in a collection. You use this operator to check how many soda or
juice items are in the shopping cart. Define a condition as shown:
If the number of items counted by the →size operator in the
sodaitems collection is three or more, then a $2 off coupon is issued to the
customer. Define this action for this as shown:
The action creates a new Coupon. The expirationDate attribute
derives its value from the Date operator .addYears, set here to 1, so the coupon
expires one year from its date of issue.
Save the Rulesheet.
Next, let’s test this rule.
Create a Ruletest named coupons4.ert that uses the
MyAdvancedTutorial.erf Ruleflow as its test subject.
To test this rule, the shopping cart must contain three or more
items from the Soda/Juice Department (department 285).
The customer must be a preferred account holder so that the data passes the filter
Customer.isPreferredMember=T in this Rulesheet.
The cumulative cash back must be set to 0, to enable an earlier rule to fire,
where cashBackEarned is added to cumulativeCashBack (and it cannot be
added to a null value).
Define the input as shown:
Run the Ruletest.
The rule works as expected. The items from the Soda/Juice department
have been identified and counted. A coupon has been added with a $2 off next
purchase description and an expirationDate of 07/13/23 (which is 1 year
from the date this test was run).
Note: In
JavaScript, the output is in the format:
The other rules have fired as well. For example, the total amount of
the shopping cart and the cash back earned have been calculated. The cash back earned
has been added to the cumulative cash back (which was set to 0).
Note: You should run multiple tests
with different data to make sure that the rules work as expected in different scenarios.
For example, you could change the department code of one of the items to 291 (liquor)
and another one to 290 (floral). When you run the test with the new data, the alert to
check the customer’s ID (liquor) and the free balloon coupon (floral) should be
generated. However, the soda coupon should not get generated as you no longer have three
soda items.
Define a promotional rule for customers
purchasing more than $75 in this cart
Let’s now model the last rule in the coupons Rulesheet:
The last rule checks if the total amount is $75 or more, and if so,
issues a coupon for 10% off of a future gasoline purchase. Define this rule as
shown:
The rule condition identifies when the totalAmount of a
customer’s shopping cart is $75 or more. The rule action creates a new coupon (again,
using the .new operator) for 10% discount on a future gasoline purchase. The
expirationDate attribute derives its value from the Date (or DateTime)
operator .addMonths, set here to 3, so the coupon expires in three months
from its date of issue.
As always, it is a good practice to add a corresponding rule statement,
explaining in clear language what the business rule does.
Let’s test this rule.
Create a new Ruletest named coupons5.ert that uses the
MyAdvancedTutorial.erf Ruleflow as its test subject.
Include items in the shopping cart that add up to more than $75 in
order to generate a 10% off gas coupon. Define the input as shown.
Run the test.
Note: The dateTime output in the
JavaScript product is in the format:
This rule has worked as expected. The items have been totaled and the
amount exceeds the $75 threshold so the 10% off coupon is created.
You have now modeled all the rules in the Calculations, Promotions
and Coupons substep of the Checkout process.