Skip to content

Calculations

Benjamin Mwalimu edited this page Jun 9, 2020 · 1 revision

Calcualtions

Calcualtions using rules engine

OpenSRP Client Native Forms is now integrated with a rules engine for complex fields calculations. We use the J-Easy Library which can be found Here. Rules are defined in yaml configuration files that are stored in the assets/rule folder. You can define multiple rules in multiple configs to be used by one json form

When defining the calculations for your forms keep Calculations in a separate file. e.g if i am doing a form called physical_exam , under assets/rules i should have two files namely physical-exam-calculations-rules.yml

You can name the files any thing you want so long as you don't mix calculations and relevance definitions.

Separating and naming the files this way per form is however the recommended approach

The j-easy library uses MVEL expression language which is java like to define its rules. There are a few subtle differences but those can be found in the MVEL Documentation Here

Once you have the rules defined, you need to reference them like this in the form's json

{
        "key": "happiness_level",
        "openmrs_entity_parent": "",
        "openmrs_entity": "person_attribute",
        "openmrs_entity_id": "calculation_happiness_level",
        "type": "edit_text",
        "calculation": {
          "rules-engine": {
            "ex-rules": {
              "rules-file": "sample-calculation-rules.yml"
            }
          }
        }
      }

In the example above, the calculations for the edit text with key happiness_level are defined in theassets/rule/sample-calculation-rules.yml files. The calculation setting here means that the value for this field is calculated rather than entered, its calculation rules being defined in the sample-calculation-rules.yml file.

The Sample App now has the various sections separated for easier reference. Once you run the app , clicking on the RULES ENGINE LOGIC button guides you through various configurations for relevance and calculations. You can check out the corresponding rules files under assets/rule to see how they are configured.

NB:

  • When defining rules, always prefix with the step name they reference e.g. if its a key age in step 1 then the field reference in the condition should be as step1_age e.g. condition: "step1_hepb_immun_status < 60 || step1_hepb_immun_status > 100" or if field contains a value which is a list like the checkbox widget step2_super_heroes.contains('batman')

  • The name of the rule should be the key of the field it configures also be prefixed with its step e.g. name: step1_happiness_level

  • The action of a calculation should always be an assignment to the key calculation e.g.

    actions:
     - "calculation = calculation + 1"
    

You can also inject global values in the root of the json form and they can be used during the relevance/calculation evaluations. useful e.g. if you want to inject external settings that are part of the logic

,
 "global": {
   "has_cat_scan": true,
   "stock_count": 100
 },

Here is complete example definition of the calculation for happiness level which is configured in the sample app. Its value depends on the first name from step 1 being set to Martin (case sensitive) and a global value for has_cat_scan being set to true.

name: step1_happiness_level
description: Happiness level calculation
priority: 1
condition: "step1_First_Name == 'Martin' && global_has_cat_scan == 'true' "
actions:
  - "calculation = 1"

OTHER EXAMPLES condition: 'helper.formatDate(step1_Date_Birth,"y") <= 2' checks whether the date of birth is less than or equal to 2 years - 'calculation = helper.formatDate("19-12-2020","y")' gets number of weeks from passed date. you can also use d for days m for months w for weeks - 'calculation = helper.formatDate("19-12-2020","wd")' outputs special format 28 weeks 5 days