Logic Basics

When implementing a solution for customer, you’re dealing mostly with two things - data tables and logics. Logics define the calculation of prices, what is rendered on dashboards, which input fields the user is adding, and many more.

Logic Purpose/Types

There are many different kinds of tasks you might need to use to implement a solution for a customer, and for each kind we have different type/nature of logics. Let’s name some examples here, namely those, which are discussed in the CCE course:

  • Price List Line Item calculation

  • Quote

    • Line Item calculation

    • Header Calculation

  • Approval Workflow construction

  • Data Enrichment

    • of Master Data tables

    • of Analytics tables

  • Dashboard - Prepare the content of Portlets.

  • And approx. 45 other types (see Logic Types in References).

What Is a Logic

A logic is a program in Groovy programming language written as a sequence of one or more Groovy scripts executed in the defined order.

Sample Groovy script from a Logic for Pricelist calculation

def productGroup = api.product("ProductGroup") def marginAdjPct = api.vLookup("MarginAdj", productGroup) if(marginAdjPct == null) { api.addWarning("Unable to look up Margin Adjustment with the Product Group") } return marginAdjPct

On the backend server, such Groovy script is compiled into bytecode then executed by the calculation engine in JVM (Java Virtual Machine).

Figure 1. Process of Logic compilation and execution

The compiled code is used at the time when the calculation engine needs to calculate the prices for a product (i.e., prices for line item of a Price List).

Calculation Logic is also called:

  • "Logic" - A shorter name used instead of Calculation Logic on many places in documentation.

  • "Price Logic" / "Price Method" - Is typically used for Price List or Quote logic.

  • "Formula" - Former name (because of the name of the previously used language for writing calculation logics).

Formerly, Pricefx used also another language called "Formula" language. It was a functional language, kind of similar to functions found in MS Excel.

This Formula language is still available in Pricefx, however it is not used in new projects anymore due to various limitations.

Sample of calculation in Formula language

BasePrice * VLookup("Prod_Class_Adj", Product("Prod. Class"))

Pros and cons of Formula language:

  • Pros: Easier to understand, designed for non-programmers.

  • Cons: Not flexible enough, slower execution than Groovy (because Formula was interpreted language), required a lot of elements because of lack of variables and end up in complex formula not well readable for humans.

What the Logic Does

From highlevel perspective, the Logic does the job, which is required by the business requirements, e.g., calculates a Price List, handles configuration of a product/service when creating a Quote, provides the user with analytical charts, etc.

Inside of a Logic, you can do all the necessary parts to achieve the goal:

  • Read Input from user.

  • Read Data from tables.

  • Error handling.

  • Price calculation.

  • Provide calculated result.

    • Note: Most of the logics cannot explicitly write data. The logic only calculates the results which are then persisted by the calculation engine.

  • Alert user about violation of business rules, etc.

Logic Structure

Figure 2. Structure of any Pricefx Logic

Elements

So now you know, that Logic is a piece of code in Groovy language. For several reasons it’s practical to split the Logic script into more parts, which are stored separately in Elements.

Element name

Groovy script

Element name

Groovy script

BasePrice

return api.productExtension("ProductCost")?.getAt(0)?.attribute1 //❶

❶ The api binding variable is provided by Pricefx engine, and gives you access to plenty of functions to interact with Pricefx.

MarginPct

ListPrice

❶ The out binding variable gives you access to results of previous Elements.

Elements:

  • Are executed in sequential order - top to down.

  • If the Groovy script returns a value, it will become a result/output of the element.

    • Because of that, Elements are sometimes refered as "outputs" of the logic.

  • Elements are compiled into classes and the script (i.e., the content of the Element) represents the "run" method of that Groovy class. Such class has an artificial name, partially based on the Element name.

Reasons for Split into Elements

  • Technical:

    • Providing more results from one logic - e.g., you need to calculate several values for a Price List line item. Explanation Note: Logic usually does not write data to DB. Instead, the engine takes the results of the Elements and stores them into DB for you.

  • Practical:

    • Re-use of result values - e.g., to avoid calculation of the same value again and again. Instead, one element can pre-calculate some value and sub-sequent elements can simply read the result value and use it.

    • Keep reasonable size of code.

    • Easier to test - It’s much easier to see intermediate results, when you return them as results of separate Elements.

Properties

The properties are influencing the behavior of the Logic or Element when used in Pricefx system.

Logic Type and Nature

The most important property of a Logic is its Type and Nature, because it defines for what purpose the logic can be used.

Logic purpose

Type

Nature

Logic purpose

Type

Nature

Pricelist Line Item calculation

Pricing Logic

Default (Generic)

Quote Header calculation

Pricing Logic

Quote Header

Library of reusable functions

Pricing Logic

Library

Approval Workflow steps creation

Workflow Logic

Default

There are two types of logics and they represent the superclass of the logic. Most of the logics are of a type Pricing Logic and only few of Workflow Logic type.

Logic Name

Logic name is important identifier, because it’s used on many places to refer to the logic.

So you should pay attention to construction of a name of the logic:

Logic Validity

One Logic (e.g., calculation of specific Price List) can have more versions - simply because the business calculation rules evolve in time. To accomodate such business requirement, each Logic has also property ValidAfter, which describes, from which date is this version of the logic valid.

As you can have more versions of the same Logic, the Name of the logic is not enough to select the proper logic to be used for calculation - it’s always a combination of Name and ValidAfter.

Note: The Logic does not have any "ValidTo" or "Expiration" date, instead, the system selects the proper version only based on the ValidAfter property.

Whenever the execution engine executes any logic, it always uses "execution date" (in Pricefx called Target Date) to distinguish, which version of the logic to use.

From the picture you can also see that the actual real date "Today" does not matter when the logic is executed.

Of course, if you tried to execute logic on a TargetDate, when the Logic is not valid, the execution would fail and Pricefx would complain that there’s no Logic available.

Therefore, if you have only one version of your logic, there’s a recommended practice to set the logic’s Valid After to a date in the past, to avoid such issue.

Element Type

Element’s Type distinguishes the language in which the code is written. Use Groovy type here, which is the default. All the other types were related to Formula language, and are not used anymore.

Element Name

The Name of the Element should describe, what is the Element’s result, what kind of outcome we can expect as a result of execution of the Element’s code. If the Element’s result value is not important (e.g., it only has some debugging output), then give it a name based on the action it performs.

The Name can be also used inside of subsequent Logic Elements, when they need to read the result value of the element.

Ensure to use the best practice naming conventions for the name of the Element.

Element Display Mode

This property is used in those types of Logics, where the calculation engine takes the results of the Elements and store them into database, for example in Price List Line Item calculation, Quote Line Item calculation and Master Data enrichment. In some other cases, like Approval Workflow steps creation or Quote Header calculation, it does not have any usage.

There are several values of DisplayModes, but in majority of cases you will use two:

  • Everywhere - It means the Element’s result value can be displayed to the user and will also be stored in the database.

  • Never - Such Element’s result will not be presented to the User (but still might be stored in the database - this depends on the Logic type).

How the Logic Does Its Job

Besides making actual math operations and data transformation using Groovy language, the Groovy code stored in Elements must be able to interact with the Pricefx application.

Groovy API

For that purpose, there are many Pricefx functions available - in summary, we call that set of functions "Pricefx Groovy API". Because Pricefx is written in Java, those functions are available as methods of Java classes.

Your Logic’s Groovy code will get reference to instances of those Pricefx classes via special binding variables - the major one is called api. This function holds reference to instance of class, which implements interface net.pricefx.formulaengine.scripting.PublicGroovyAPI.

Sample of call of methods "trace" and "vLookup" available on PublicGroovyAPI, which is exposed via binding variable api

Some kinds of Logics also get references to some other class instances, which are specifically needed for certain use-case, for example binding variable, like quoteProcessor or workflow.

Some classes are also available directly (e.g. InputType), typically allowing you to use some constants defined in them, but this is minor usecase.

Binding Variables

In the previous section you learned that some class instances are available in the logic via "binding variables". The binding variables are simply variables available to your Groovy code without the need to create/define them.

Binding variables which are available to every kind of logic:

  • api – Access to instance of PublicGroovyAPI.

  • libs – Access to functions of "Library" logics, e.g., libs.MathLib.RoundingUtils.round(…​).

  • input – Access to values entered by user via UI into the input fields, e.g., input.Country.

  • out - Access to the results returned by preceding Elements' scripts, e.g., out.BasePrice.

Additional binding variables based on the type/usage of the logic:

  • quoteProcessor - Exposes QuoteBuilder and is used only in logics with nature Quote Header.

  • workflow - Exposes WorkflowDTO, which is needed by Workflow logic type, only where meaningul.

The list of those specific binding variables can be found in list of Logic Types.

Context

When the user starts some process (e.g., calculation of Price List), the engine executes your logic at a certain point of time, so that your logic calculates the prices and provides the results. The system will provide your logic with information about what it needs you to calculate - via Context object.

The most commonly used information the engine puts to context is:

  • targetDate - Date used for the execution of the process.

    • For Price List, it is the first date of validity of the Price List, for Quote it is the Effective Date.

    • For some processes, it will be the same as "today".

    • Remember: This date is also used by the engine to select proper version of your logic.

  • sku - ID of the product for which the logic will calculate the prices.

    • Note: sku is not available for all logic types, only where meaningul (e.g., in line item logics).

  • currentItem - The row being calculated.

    • Warning: This is available only in some processes.

You cannot read the Context information directly from the object, but only via provided Groovy API functions:

  • api.targetDate() - To read the Target Date information.

  • api.product("sku") - To read the SKU infomation.

  • api.currentItem() - To read the current line item data.

Reference to Element’s Class

In Groovy language you can create new functions with reusable piece of code. Inside of the same script you can call the function simply by its name, but when such function is useful in more Elements of the logic, you can call the function also from within other Elements.

For that you need to somehow refer to the class of the previous Element. Even though the actuall Class of the Element’s script has quite artificial name, you can simply refer to it by using the name of the Element.

Element name

Groovy script

Element name

Groovy script

Utils

Price

❶ Refering to the class of the previous Element via its name "Utils".

References

Documentation

Knowledge Base

Found an issue in documentation? Write to us.