← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 19480: Tracker rules engine now executes tracker program indicators. Added rulebound widget for showing ...

 

------------------------------------------------------------
revno: 19480
committer: Markus Bekken <markus.bekken@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2015-06-22 00:18:40 +0200
message:
  Tracker rules engine now executes tracker program indicators. Added rulebound widget for showing indicators in tracker capture.
modified:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/services.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app_ar.properties
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js	2015-06-18 15:15:29 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js	2015-06-21 22:18:40 +0000
@@ -485,7 +485,7 @@
 
 function getProgramIndicators( programIndicators )
 {
-    return checkAndGetD2Objects( programIndicators, 'programIndicators', '../api/programIndicators', 'fields=id,name,code,shortName,expression,displayDescription,rootDate,description,valueType,DisplayName,program[id]');
+    return checkAndGetD2Objects( programIndicators, 'programIndicators', '../api/programIndicators', 'fields=id,name,code,shortName,expression,displayDescription,rootDate,description,valueType,DisplayName,filter,program[id]');
 }
 
 function getMetaProgramRules( programs )

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/services.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/services.js	2015-06-18 15:15:29 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/services.js	2015-06-21 22:18:40 +0000
@@ -174,55 +174,6 @@
     };
 })
 
-/* factory to fetch and process programValidations */
-.factory('MetaDataFactory', function($q, $rootScope, ECStorageService) {  
-    
-    return {        
-        get: function(store, uid){
-            
-            var def = $q.defer();
-            
-            ECStorageService.currentStore.open().done(function(){
-                ECStorageService.currentStore.get(store, uid).done(function(pv){                    
-                    $rootScope.$apply(function(){
-                        def.resolve(pv);
-                    });
-                });
-            });                        
-            return def.promise;
-        },
-        getByProgram: function(store, program){
-            var def = $q.defer();
-            var obj = [];
-            
-            ECStorageService.currentStore.open().done(function(){
-                ECStorageService.currentStore.getAll(store, program).done(function(pvs){   
-                    angular.forEach(pvs, function(pv){
-                        if(pv.program.id === program){                            
-                            obj.push(pv);                               
-                        }                        
-                    });
-                    $rootScope.$apply(function(){
-                        def.resolve(obj);
-                    });
-                });                
-            });            
-            return def.promise;
-        },
-        getAll: function(store){
-            var def = $q.defer();            
-            ECStorageService.currentStore.open().done(function(){
-                ECStorageService.currentStore.getAll(store).done(function(pvs){                       
-                    $rootScope.$apply(function(){
-                        def.resolve(pvs);
-                    });
-                });                
-            });            
-            return def.promise;
-        }
-    };        
-})
-
 /* factory for handling events */
 .factory('DHIS2EventFactory', function($http, $q, ECStorageService, $rootScope) {   
     

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js	2015-06-11 18:44:52 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js	2015-06-21 22:18:40 +0000
@@ -78,6 +78,11 @@
                         $rootScope.dashboardWidgets.push($rootScope.enrollmentWidget);
                         $scope.dashboardStatus[widget.title] = angular.copy(widget);
                         break;
+                    case 'indicators':
+                        $rootScope.indicatorWidget = widget;
+                        $rootScope.dashboardWidgets.push($rootScope.indicatorWidget);
+                        $scope.dashboardStatus[widget.title] = angular.copy(widget);
+                        break;
                     case 'dataentry':
                         $rootScope.dataentryWidget = widget;
                         $rootScope.dashboardWidgets.push($rootScope.dataentryWidget);

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js	2015-06-15 15:29:59 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js	2015-06-21 22:18:40 +0000
@@ -117,10 +117,10 @@
         //If the events is displayed in a table, it is necessary to run the rules for all visible events.
         if($scope.currentStage.displayEventsInTable) {
            angular.forEach($scope.currentStageEvents, function(event) {
-               TrackerRulesExecutionService.executeRules($scope.selectedProgramId,event,$scope.eventsByStage,$scope.prStDes,$scope.selectedTei);
+               TrackerRulesExecutionService.executeRules($scope.selectedProgramId,event,$scope.eventsByStage,$scope.prStDes,$scope.selectedTei,$scope.selectedEnrollment);
            });
         } else {
-           TrackerRulesExecutionService.executeRules($scope.selectedProgramId,$scope.currentEvent,$scope.eventsByStage,$scope.prStDes,$scope.selectedTei);
+           TrackerRulesExecutionService.executeRules($scope.selectedProgramId,$scope.currentEvent,$scope.eventsByStage,$scope.prStDes,$scope.selectedTei,$scope.selectedEnrollment);
         }
     };
     

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties	2015-06-15 15:29:59 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties	2015-06-21 22:18:40 +0000
@@ -138,6 +138,7 @@
 search_from_existing=Search from existing
 name=Name
 dataentry=Data Entry
+indicators=Indicators
 custom_form=Custom form
 default_form=Default form
 menu=Menu

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app_ar.properties'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app_ar.properties	2015-06-08 08:54:37 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app_ar.properties	2015-06-21 22:18:40 +0000
@@ -114,6 +114,7 @@
 search_from_existing=\u0627\u0628\u062d\u062b \u0628\u0645\u0639\u064a\u0627\u0631 \u0645\u062a\u0649 \u062a\u0645 \u0627\u0644\u0627\u0646\u0634\u0627\u0621
 name=\u0627\u0633\u0645
 dataentry=\u0627\u062f\u062e\u0627\u0644 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a
+indicators=\u0627\u0644\u0645\u0624\u0634\u0631\u0627\u062a ( \u062c\u0648\u062c\u0644 \u062a\u0631\u062c\u0645\u0629 )
 custom_form=\u0627\u0633\u062a\u0645\u0627\u0631\u0629 \u0645\u062e\u0635\u0635\u0629
 default_form=\u0627\u0633\u062a\u0645\u0627\u0631\u0629 \u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629
 menu=\u0642\u0627\u0626\u0645\u0629

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js	2015-06-17 08:54:51 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js	2015-06-21 22:18:40 +0000
@@ -10,7 +10,7 @@
     var store = new dhis2.storage.Store({
         name: "dhis2tc",
         adapters: [dhis2.storage.IndexedDBAdapter, dhis2.storage.DomSessionStorageAdapter, dhis2.storage.InMemoryAdapter],
-        objectStores: ['programs', 'programStages', 'trackedEntities', 'trackedEntityForms', 'attributes', 'relationshipTypes', 'optionSets', 'programValidations', 'ouLevels', 'programRuleVariables', 'programRules']
+        objectStores: ['programs', 'programStages', 'trackedEntities', 'trackedEntityForms', 'attributes', 'relationshipTypes', 'optionSets', 'programValidations', 'ouLevels', 'programRuleVariables', 'programRules','constants']
     });
     return{
         currentStore: store
@@ -22,8 +22,9 @@
     
     var w = {};
     w.enrollmentWidget = {title: 'enrollment', view: "components/enrollment/enrollment.html", show: true, expand: true, parent: 'biggerWidget', order: 0};
-    w.dataentryWidget = {title: 'dataentry', view: "components/dataentry/dataentry.html", show: true, expand: true, parent: 'biggerWidget', order: 1};
-    w.reportWidget = {title: 'report', view: "components/report/tei-report.html", show: true, expand: true, parent: 'biggerWidget', order: 2};
+    w.indicatorWidget = {title: 'indicators', view: "components/rulebound/rulebound.html", show: true, expand: true, parent: 'biggerWidget', order: 1, code:'indicators'};
+    w.dataentryWidget = {title: 'dataentry', view: "components/dataentry/dataentry.html", show: true, expand: true, parent: 'biggerWidget', order: 2};
+    w.reportWidget = {title: 'report', view: "components/report/tei-report.html", show: true, expand: true, parent: 'biggerWidget', order: 3};
     w.selectedWidget = {title: 'current_selections', view: "components/selected/selected.html", show: false, expand: true, parent: 'smallerWidget', order: 0};
     w.profileWidget = {title: 'profile', view: "components/profile/profile.html", show: true, expand: true, parent: 'smallerWidget', order: 1};
     w.relationshipWidget = {title: 'relationships', view: "components/relationship/relationship.html", show: true, expand: true, parent: 'smallerWidget', order: 2};
@@ -1061,6 +1062,55 @@
     };  
 })
 
+/* factory to fetch and process programValidations */
+.factory('MetaDataFactory', function($q, $rootScope, TCStorageService) {  
+    
+    return {        
+        get: function(store, uid){
+            
+            var def = $q.defer();
+            
+            TCStorageService.currentStore.open().done(function(){
+                TCStorageService.currentStore.get(store, uid).done(function(pv){                    
+                    $rootScope.$apply(function(){
+                        def.resolve(pv);
+                    });
+                });
+            });                        
+            return def.promise;
+        },
+        getByProgram: function(store, program){
+            var def = $q.defer();
+            var obj = [];
+            
+            TCStorageService.currentStore.open().done(function(){
+                TCStorageService.currentStore.getAll(store, program).done(function(pvs){   
+                    angular.forEach(pvs, function(pv){
+                        if(pv.program.id === program){                            
+                            obj.push(pv);                               
+                        }                        
+                    });
+                    $rootScope.$apply(function(){
+                        def.resolve(obj);
+                    });
+                });                
+            });            
+            return def.promise;
+        },
+        getAll: function(store){
+            var def = $q.defer();            
+            TCStorageService.currentStore.open().done(function(){
+                TCStorageService.currentStore.getAll(store).done(function(pvs){                       
+                    $rootScope.$apply(function(){
+                        def.resolve(pvs);
+                    });
+                });                
+            });            
+            return def.promise;
+        }
+    };        
+})
+
     /* Returns a function for getting rules for a specific program */
 .factory('TrackerRulesFactory', function($q,$rootScope,TCStorageService){
     return{
@@ -1755,5 +1805,6 @@
             }
             return event;
         }
-    }; 
+    };
+    
 });

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js	2015-06-17 21:53:57 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js	2015-06-21 22:18:40 +0000
@@ -29,7 +29,7 @@
 dhis2.tc.store = new dhis2.storage.Store({
     name: 'dhis2tc',
     adapters: [dhis2.storage.IndexedDBAdapter, dhis2.storage.DomSessionStorageAdapter, dhis2.storage.InMemoryAdapter],
-    objectStores: ['programs', 'programStages', 'trackedEntities', 'trackedEntityForms', 'attributes', 'relationshipTypes', 'optionSets', 'programValidations', 'ouLevels', 'programRuleVariables', 'programRules']      
+    objectStores: ['programs', 'programStages', 'trackedEntities', 'trackedEntityForms', 'attributes', 'relationshipTypes', 'optionSets', 'programValidations', 'programIndicators', 'ouLevels', 'programRuleVariables', 'programRules','constants']      
 });
 
 (function($) {
@@ -132,6 +132,7 @@
     promise = promise.then( dhis2.tc.store.open );
     promise = promise.then( getUserRoles );
     promise = promise.then( getCalendarSetting );
+    promise = promise.then( getConstants );
     promise = promise.then( getRelationships );       
     promise = promise.then( getTrackedEntities );
     promise = promise.then( getMetaPrograms );     
@@ -146,7 +147,9 @@
     promise = promise.then( getMetaProgramRules );
     promise = promise.then( getProgramRules );
     promise = promise.then( getMetaProgramValidations );
-    promise = promise.then( getProgramValidations );    
+    promise = promise.then( getProgramValidations );   
+    promise = promise.then( getMetaProgramIndicators );
+    promise = promise.then( getProgramIndicators );
     promise = promise.then( getTrackedEntityForms );
     promise = promise.then( getOrgUnitLevels );
     promise.done(function() {
@@ -206,6 +209,16 @@
     return def.promise();
 }
 
+function getConstants()
+{
+    dhis2.tc.store.getKeys( 'constants').done(function(res){        
+        if(res.length > 0){
+            return;
+        }        
+        return getD2Objects('constants', 'constants', '../api/constants.json', 'paging=false&fields=id,name,displayName,value');        
+    });    
+}
+
 function getRelationships()
 {    
     dhis2.tc.store.getKeys( 'relationshipTypes').done(function(res){        
@@ -680,7 +693,7 @@
         def.resolve();
 
         promise = promise.done( function () {
-            mainDef.resolve( data );
+            mainDef.resolve( data.programs );
         } );
     }).fail(function(){
         mainDef.resolve( null );
@@ -823,6 +836,16 @@
     };
 }
 
+function getMetaProgramIndicators( programs )
+{    
+    return getD2MetaObject(programs, 'programIndicators', '../api/programIndicators.json', 'paging=false&fields=id,program[id]');
+}
+
+function getProgramIndicators( programIndicators )
+{
+    return checkAndGetD2Objects( programIndicators, 'programIndicators', '../api/programIndicators', 'fields=id,name,code,shortName,expression,displayDescription,rootDate,description,valueType,DisplayName,filter,program[id]');
+}
+
 function getMetaTrackeEntityAttributes( programs ){
     
     var def = $.Deferred();
@@ -1017,4 +1040,151 @@
 
         return def.promise();
     }); 
+}
+
+function getD2MetaObject( programs, objNames, url, filter )
+{
+    if( !programs ){
+        return;
+    }
+    
+    var def = $.Deferred();
+    
+    var programIds = [];
+    _.each( _.values( programs ), function ( program ) { 
+        if( program.id ) {
+            programIds.push( program.id );
+        }
+    });
+    
+    $.ajax({
+        url: url,
+        type: 'GET',
+        data:filter
+    }).done( function(response) {          
+        var objs = [];
+        _.each( _.values( response[objNames]), function ( o ) { 
+            if( o &&
+                o.id &&
+                o.program &&
+                o.program.id &&
+                programIds.indexOf( o.program.id ) !== -1) {
+            
+                objs.push( o );
+            }  
+            
+        });
+        
+        def.resolve( {programs: programs, self: objs} );
+        
+    }).fail(function(){
+        def.resolve( null );
+    });
+    
+    return def.promise();    
+}
+
+function checkAndGetD2Objects( obj, store, url, filter )
+{
+    if( !obj || !obj.programs || !obj.self ){
+        return;
+    }
+    
+    var mainDef = $.Deferred();
+    var mainPromise = mainDef.promise();
+
+    var def = $.Deferred();
+    var promise = def.promise();
+
+    var builder = $.Deferred();
+    var build = builder.promise();
+
+    _.each( _.values( obj.self ), function ( obj) {
+        build = build.then(function() {
+            var d = $.Deferred();
+            var p = d.promise();
+            dhis2.tc.store.get(store, obj.id).done(function(o) {
+                if(!o) {
+                    promise = promise.then( getD2Object( obj.id, store, url, filter, 'idb' ) );
+                }
+                d.resolve();
+            });
+
+            return p;
+        });
+    });
+
+    build.done(function() {
+        def.resolve();
+        promise = promise.done( function () {
+            mainDef.resolve( obj.programs );
+        } );
+    }).fail(function(){
+        mainDef.resolve( null );
+    });
+
+    builder.resolve();
+
+    return mainPromise;
+}
+
+function getD2Objects(store, objs, url, filter)
+{
+    var def = $.Deferred();
+
+    $.ajax({
+        url: url,
+        type: 'GET',
+        data: filter
+    }).done(function(response) {
+        if(response[objs]){
+            dhis2.tc.store.setAll( store, response[objs] );
+        }            
+        def.resolve();        
+    }).fail(function(){
+        def.resolve();
+    });
+
+    return def.promise();
+}
+
+
+function getD2Object( id, store, url, filter, storage )
+{
+    return function() {
+        if(id){
+            url = url + '/' + id + '.json';
+        }
+        return $.ajax( {
+            url: url,
+            type: 'GET',            
+            data: filter
+        }).done( function( response ){
+            if(storage === 'idb'){
+                if( response && response.id) {
+                    dhis2.tc.store.set( store, response );
+                }
+            }
+            if(storage === 'localStorage'){
+                localStorage[store] = JSON.stringify(response);
+            }            
+            if(storage === 'sessionStorage'){
+                var SessionStorageService = angular.element('body').injector().get('SessionStorageService');
+                SessionStorageService.set(store, response);
+            }            
+        });
+    };
+}
+
+function uploadLocalData()
+{
+    var OfflineECStorageService = angular.element('body').injector().get('OfflineECStorageService');
+    setHeaderWaitMessage(i18n_uploading_data_notification);
+     
+    OfflineECStorageService.uploadLocalData().then(function(){
+        dhis2.tc.store.removeAll( 'events' );
+        log( 'Successfully uploaded local events' );      
+        setHeaderDelayMessage( i18n_sync_success );
+        selection.responseReceived(); //notify angular
+    });
 }
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js	2015-06-19 06:01:29 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js	2015-06-21 22:18:40 +0000
@@ -710,13 +710,13 @@
 })
 
 /* service for building variables based on the data in users fields */
-.service('VariableService', function($rootScope,$q,TrackerRuleVariableFactory,$filter,orderByFilter,$log){
+.service('VariableService', function($rootScope,$q,TrackerRuleVariableFactory,DateUtils,CalendarService,MetaDataFactory,$filter,orderByFilter,$log){
     return {
-        getVariables: function(programid, executingEvent, allEventsByStage, allDataElements, selectedEntity) {
+        getVariables: function(programid, executingEvent, allEventsByStage, allDataElements, selectedEntity, variablesFromIndicators, selectedEnrollment) {
             var thePromisedVariables = $q.defer();
             var variables = {};
             
-            var pushVariable = function(variablename, variableValue, variableType, variablefound) {
+            var pushVariable = function(variablename, variableValue, variableType, variablefound, variablePrefix) {
                 //First clean away single or double quotation marks at the start and end of the variable name.
                 variableValue = $filter('trimquotes')(variableValue);
                 
@@ -745,138 +745,161 @@
                 variables[variablename] = {
                                 variableValue:variableValue,
                                 variableType:variableType,
-                                hasValue:variablefound
+                                hasValue:variablefound,
+                                variablePrefix:variablePrefix
                             };
             };
-            
-            TrackerRuleVariableFactory.getProgramRuleVariables(programid).then(function(programVariables){
-
-                var allEventsSorted = [];
-                var currentEvent = executingEvent;
-                var eventsSortedPerProgramStage = [];
-                
-                for(var key in allEventsByStage){
-                    if(allEventsByStage.hasOwnProperty(key)){
-                        eventsSortedPerProgramStage[key] = [];
-                        angular.forEach(allEventsByStage[key], function(event){
-                            allEventsSorted.push(event);
-                            eventsSortedPerProgramStage[key].push(event);
-                        });
-                        eventsSortedPerProgramStage[key] = orderByFilter(eventsSortedPerProgramStage[key], '-sortingDate').reverse(); 
+            MetaDataFactory.getAll('constants').then(function(constants) {
+                TrackerRuleVariableFactory.getProgramRuleVariables(programid).then(function(programVariables){
+
+                    programVariables = programVariables.concat(variablesFromIndicators);
+
+                    var allEventsSorted = [];
+                    var currentEvent = executingEvent;
+                    var eventsSortedPerProgramStage = [];
+
+                    for(var key in allEventsByStage){
+                        if(allEventsByStage.hasOwnProperty(key)){
+                            eventsSortedPerProgramStage[key] = [];
+                            angular.forEach(allEventsByStage[key], function(event){
+                                allEventsSorted.push(event);
+                                eventsSortedPerProgramStage[key].push(event);
+                            });
+                            eventsSortedPerProgramStage[key] = orderByFilter(eventsSortedPerProgramStage[key], '-sortingDate').reverse(); 
+                        }
                     }
-                }
-                allEventsSorted = orderByFilter(allEventsSorted, '-sortingDate').reverse(); 
-                
-                var allDes = allDataElements;
-                
-                angular.forEach(programVariables, function(programVariable) {
-                    var valueFound = false;
-                    if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE"){
-                        if(programVariable.programStage) {
-                            angular.forEach(eventsSortedPerProgramStage[programVariable.programStage.id], function(event) {
-                                if(angular.isDefined(event[programVariable.dataElement.id])
-                                        && event[programVariable.dataElement.id] !== null ){
+                    allEventsSorted = orderByFilter(allEventsSorted, '-sortingDate').reverse(); 
+
+                    var allDes = allDataElements;
+
+                    angular.forEach(programVariables, function(programVariable) {
+                        var dataElementId = programVariable.dataElement;
+                        if(programVariable.dataElement.id) {
+                            dataElementId = programVariable.dataElement.id;
+                        }
+
+                        var programStageId = programVariable.programStage;
+                        if(programVariable.programStage.id) {
+                            programStageId = programVariable.programStage.id;
+                        }
+
+                        var valueFound = false;
+                        if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE"){
+                            if(programVariable.programStage) {
+                                angular.forEach(eventsSortedPerProgramStage[programStageId], function(event) {
+                                    if(angular.isDefined(event[dataElementId])
+                                            && event[dataElementId] !== null ){
+                                        valueFound = true;
+                                        pushVariable(programVariable.name, event[dataElementId], allDes[dataElementId].dataElement.type, valueFound, '#');
+                                    }
+                                });
+                            } else {
+                                $log.warn("Variable id:'" + programVariable.id + "' name:'" + programVariable.name 
+                                        + "' does not have a programstage defined,"
+                                        + " despite that the variable has sourcetype DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE" );
+                            }
+
+                        }
+                        else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM"){
+                            angular.forEach(allEventsSorted, function(event) {
+                                if(angular.isDefined(event[dataElementId])
+                                        && event[dataElementId] !== null ){
                                     valueFound = true;
-                                    pushVariable(programVariable.name, event[programVariable.dataElement.id], allDes[programVariable.dataElement.id].dataElement.type, valueFound );
-                                }
+                                     pushVariable(programVariable.name, event[dataElementId], allDes[dataElementId].dataElement.type, valueFound, '#' );
+                                 }
                             });
-                        } else {
-                            $log.warn("Variable id:'" + programVariable.id + "' name:'" + programVariable.name 
-                                    + "' does not have a programstage defined,"
-                                    + " despite that the variable has sourcetype DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE" );
                         }
-                        
-                    }
-                    else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM"){
-                        angular.forEach(allEventsSorted, function(event) {
-                            if(angular.isDefined(event[programVariable.dataElement.id])
-                                    && event[programVariable.dataElement.id] !== null ){
+                        else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_CURRENT_EVENT"){
+                            if(angular.isDefined(currentEvent[dataElementId])
+                                    && currentEvent[dataElementId] !== null ){
                                 valueFound = true;
-                                 pushVariable(programVariable.name, event[programVariable.dataElement.id], allDes[programVariable.dataElement.id].dataElement.type, valueFound );
-                             }
-                        });
-                    }
-                    else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_CURRENT_EVENT"){
-                        if(angular.isDefined(currentEvent[programVariable.dataElement.id])
-                                && currentEvent[programVariable.dataElement.id] !== null ){
+                                pushVariable(programVariable.name, currentEvent[dataElementId], allDes[dataElementId].dataElement.type, valueFound, '#' );
+                            }      
+                        }
+                        else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_PREVIOUS_EVENT"){
+                            //Only continue checking for a value if there is more than one event.
+                            if(allEventsSorted && allEventsSorted.length > 1) {
+                                var previousvalue = null;
+                                var currentEventPassed = false;
+                                for(var i = 0; i < allEventsSorted.length; i++) {
+                                    //Store the values as we iterate through the stages
+                                    //If the event[i] is not the current event, it is older(previous). Store the previous value if it exists
+                                    if(!currentEventPassed && allEventsSorted[i] !== currentEvent && 
+                                            angular.isDefined(allEventsSorted[i][dataElementId])) {
+                                        previousvalue = allEventsSorted[i][dataElementId];
+                                        valueFound = true;
+                                    }
+                                    else if(allEventsSorted[i] === currentEvent) {
+                                        //We have iterated to the newest event - store the last collected variable value - if any is found:
+                                        if(valueFound) {
+                                            pushVariable(programVariable.name, previousvalue, allDes[dataElementId].dataElement.type, valueFound, '#' );
+                                        }
+                                        //Set currentEventPassed, ending the iteration:
+                                        currentEventPassed = true;
+                                    }
+                                }
+                            }
+                        }
+                        else if(programVariable.programRuleVariableSourceType === "TEI_ATTRIBUTE"){
+                            angular.forEach(selectedEntity.attributes , function(attribute) {
+                                if(!valueFound) {
+                                    if(attribute.attribute === programVariable.trackedEntityAttribute.id) {
+                                        valueFound = true;
+                                        pushVariable(programVariable.name, attribute.value, attribute.type, valueFound, '#' );
+                                    }
+                                }
+                            });
+                        }
+                        else if(programVariable.programRuleVariableSourceType === "CALCULATED_VALUE"){
+                            //We won't assign the calculated variables at this step. The rules execution will calculate and assign the variable.
+                        }
+                        else if(programVariable.programRuleVariableSourceType === "NUMBEROFEVENTS_PROGRAMSTAGE"){
+                            var numberOfEvents = 0;
+                            if( programVariable.programStage && eventsSortedPerProgramStage[programStageId] ) {
+                                numberOfEvents = eventsSortedPerProgramStage[programStageId].length;
+                            }
                             valueFound = true;
-                            pushVariable(programVariable.name, currentEvent[programVariable.dataElement.id], allDes[programVariable.dataElement.id].dataElement.type, valueFound );
-                        }      
-                    }
-                    else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_PREVIOUS_EVENT"){
-                        //Only continue checking for a value if there is more than one event.
-                        if(allEventsSorted && allEventsSorted.length > 1) {
-                            var previousvalue = null;
-                            var currentEventPassed = false;
-                            for(var i = 0; i < allEventsSorted.length; i++) {
-                                //Store the values as we iterate through the stages
-                                //If the event[i] is not the current event, it is older(previous). Store the previous value if it exists
-                                if(!currentEventPassed && allEventsSorted[i] !== currentEvent && 
-                                        angular.isDefined(allEventsSorted[i][programVariable.dataElement.id])) {
-                                    previousvalue = allEventsSorted[i][programVariable.dataElement.id];
-                                    valueFound = true;
-                                }
-                                else if(allEventsSorted[i] === currentEvent) {
-                                    //We have iterated to the newest event - store the last collected variable value - if any is found:
-                                    if(valueFound) {
-                                        pushVariable(programVariable.name, previousvalue, allDes[programVariable.dataElement.id].dataElement.type, valueFound );
-                                    }
-                                    //Set currentEventPassed, ending the iteration:
-                                    currentEventPassed = true;
-                                }
-                            }
-                        }
-                    }
-                    else if(programVariable.programRuleVariableSourceType === "TEI_ATTRIBUTE"){
-                        angular.forEach(selectedEntity.attributes , function(attribute) {
-                            if(!valueFound) {
-                                if(attribute.attribute === programVariable.trackedEntityAttribute.id) {
-                                    valueFound = true;
-                                    pushVariable(programVariable.name, attribute.value, attribute.type, valueFound );
-                                }
-                            }
-                        });
-                    }
-                    else if(programVariable.programRuleVariableSourceType === "CALCULATED_VALUE"){
-                        //We won't assign the calculated variables at this step. The rules execution will calculate and assign the variable.
-                    }
-                    else if(programVariable.programRuleVariableSourceType === "NUMBEROFEVENTS_PROGRAMSTAGE"){
-                        var numberOfEvents = 0;
-                        if( programVariable.programStage && eventsSortedPerProgramStage[programVariable.programStage.id] ) {
-                            numberOfEvents = eventsSortedPerProgramStage[programVariable.programStage.id].length;
-                        }
-                        valueFound = true;
-                        pushVariable(programVariable.name, numberOfEvents, 'int', valueFound );
-                    }
-                    else {
-                        //Missing handing of ruletype
-                        $log.warn("Unknown programRuleVariableSourceType:" + programVariable.programRuleVariableSourceType);
-                    }
-
-                   
-                    if(!valueFound){
-                        //If there is still no value found, assign default value:
-                        if(programVariable.dataElement) {
-                            var dataElement = allDes[programVariable.dataElement.id];
-                            if( dataElement ) {
-                                pushVariable(programVariable.name, "", dataElement.dataElement.type );
-                            } 
+                            pushVariable(programVariable.name, numberOfEvents, 'int', valueFound, '#' );
+                        }
+                        else {
+                            //Missing handing of ruletype
+                            $log.warn("Unknown programRuleVariableSourceType:" + programVariable.programRuleVariableSourceType);
+                        }
+
+
+                        if(!valueFound){
+                            //If there is still no value found, assign default value:
+                            if(programVariable.dataElement) {
+                                var dataElement = allDes[dhis2.tc];
+                                if( dataElement ) {
+                                    pushVariable(programVariable.name, "", dataElement.dataElement.type, false, '#' );
+                                } 
+                                else {
+                                    $log.warn("Variable #{" + programVariable.name + "} is linked to a dataelement that is not part of the program");
+                                    pushVariable(programVariable.name, "", "string",false, '#' );
+                                }
+                            }
                             else {
-                                $log.warn("Variable #{" + programVariable.name + "} is linked to a dataelement that is not part of the program");
-                                pushVariable(programVariable.name, "", "string" );
+                                pushVariable(programVariable.name, "", "string",false, '#' );
                             }
                         }
-                        else {
-                            pushVariable(programVariable.name, "", "string" );
-                        }
-                    }
-                });
-
-                //add context variables:
-                //last parameter "valuefound" is always true for event date
-                pushVariable('eventdate', executingEvent.eventDate, 'date', true );
-                
-                thePromisedVariables.resolve(variables);
+                    });
+
+                    //add context variables:
+                    //last parameter "valuefound" is always true for event date
+                    pushVariable('incident_date', executingEvent.eventDate, 'date', true, 'V' );
+                    pushVariable('enrollment_date', selectedEnrollment.dateOfEnrollment, 'date', true, 'V' );
+                    pushVariable('current_date', DateUtils.getToday(), 'date', true, 'V' );
+                    //pushVariable('value_count', executingEvent.eventDate, 'date', true, 'V' );
+                    //pushVariable('zero_pos_value_count', executingEvent.eventDate, 'date', true, 'V' );
+
+                    //Push all constant values:
+                    angular.forEach(constants, function(constant){
+                        pushVariable(constant.id, constant.value, 'int', true, 'C' );
+                    });
+
+                    thePromisedVariables.resolve(variables);
+                }); 
             });
             
             return thePromisedVariables.promise;
@@ -885,28 +908,29 @@
 })
 
 /* service for executing tracker rules and broadcasting results */
-.service('TrackerRulesExecutionService', function(TrackerRulesFactory,VariableService, $rootScope, $log, $filter, orderByFilter){
+.service('TrackerRulesExecutionService', function(TrackerRulesFactory, MetaDataFactory, VariableService, $rootScope, $log, $q, $filter, orderByFilter){
     return {
-        executeRules: function(programid, executingEvent, allEventsByStage, allDataElements, selectedEntity) {
+        executeRules: function(programid, executingEvent, allEventsByStage, allDataElements, selectedEntity, selectedEnrollment ) {
             //When debugging rules, the caller should provide a variable for wether or not the rules is being debugged.
             //hard coding this for now:
             var debug = true;
             var verbose = true;
             
             var variablesHash = {};
-                    
+            
             var replaceVariables = function(expression) {
                 //replaces the variables in an expression with actual variable values.
                 //First check if the expression contains variables at all(any dollar signs):
-                if(expression.indexOf('#') !== -1) {
+                if(expression.indexOf('#{') !== -1) {
                     //Find every variable name in the expression;
-                    var variablespresent = expression.match(/#{\w+}/g);
+                    var variablespresent = expression.match(/#{\w+.?\w*}/g);
                     //Replace each matched variable:
                     angular.forEach(variablespresent, function(variablepresent) {
-                        //First strip away any dollar signs from the variable name:
+                        //First strip away any prefix and postfix signs from the variable name:
                         variablepresent = variablepresent.replace("#{","").replace("}","");
                         
-                        if(angular.isDefined(variablesHash[variablepresent])) {
+                        if(angular.isDefined(variablesHash[variablepresent]) &&
+                                variablesHash[variablepresent].variablePrefix === '#') {
                             //Replace all occurrences of the variable name(hence using regex replacement):
                             expression = expression.replace(new RegExp("#{" + variablepresent + "}", 'g'),
                                 variablesHash[variablepresent].variableValue);
@@ -914,8 +938,49 @@
                         else {
                             $log.warn("Expression " + expression + " conains variable " + variablepresent 
                                     + " - but this variable is not defined." );
-                        }
-                            
+                        }  
+                    });
+                }
+                
+                if(expression.indexOf('V{') !== -1) {
+                    //Find every variable name in the expression;
+                    var variablespresent = expression.match(/V{\w+.?\w*}/g);
+                    //Replace each matched variable:
+                    angular.forEach(variablespresent, function(variablepresent) {
+                        //First strip away any prefix and postfix signs from the variable name:
+                        variablepresent = variablepresent.replace("V{","").replace("}","");
+                        
+                        if(angular.isDefined(variablesHash[variablepresent]) &&
+                                variablesHash[variablepresent].variablePrefix === 'V') {
+                            //Replace all occurrences of the variable name(hence using regex replacement):
+                            expression = expression.replace(new RegExp("V{" + variablepresent + "}", 'g'),
+                                variablesHash[variablepresent].variableValue);
+                        }
+                        else {
+                            $log.warn("Expression " + expression + " conains context variable " + variablepresent 
+                                    + " - but this variable is not defined." );
+                        } 
+                    });
+                }
+                
+                if(expression.indexOf('C{') !== -1) {
+                    //Find every constant in the expression;
+                    var variablespresent = expression.match(/C{\w+.?\w*}/g);
+                    //Replace each matched variable:
+                    angular.forEach(variablespresent, function(variablepresent) {
+                        //First strip away any prefix and postfix signs from the variable name:
+                        variablepresent = variablepresent.replace("C{","").replace("}","");
+                        
+                        if(angular.isDefined(variablesHash[variablepresent]) &&
+                                variablesHash[variablepresent].variablePrefix === 'C') {
+                            //Replace all occurrences of the variable name(hence using regex replacement):
+                            expression = expression.replace(new RegExp("C{" + variablepresent + "}", 'g'),
+                                variablesHash[variablepresent].variableValue);
+                        }
+                        else {
+                            $log.warn("Expression " + expression + " conains constant " + variablepresent 
+                                    + " - but this constant is not defined." );
+                        } 
                     });
                 }
                 return expression;
@@ -1034,119 +1099,196 @@
                 return answer;
             };
             
-            
-            VariableService.getVariables(programid, executingEvent, allEventsByStage, allDataElements, selectedEntity).then(function(variablesReceived){
-                TrackerRulesFactory.getProgramStageRules(programid, executingEvent.programStage).then(function(rules){
-                    //But run rules in priority - lowest number first(priority null is last)
-                    rules = orderByFilter(rules, 'priority');
-                    
-                    variablesHash = variablesReceived;
-
-                    if(angular.isObject(rules) && angular.isArray(rules)){
-                        //The program has rules, and we want to run them.
-                        //Prepare repository unless it is already prepared:
-                        if(angular.isUndefined( $rootScope.ruleeffects ) ) {
-                            $rootScope.ruleeffects = {};
-                        }
-                            
-                        if(angular.isUndefined( $rootScope.ruleeffects[executingEvent.event] )){
-                            $rootScope.ruleeffects[executingEvent.event] = {};
-                        }
-
-                        var updatedEffectsExits = false;
-
-                        angular.forEach(rules, function(rule) {
-                            var ruleEffective = false;
-
-                            var expression = rule.condition;
-                            //Go through and populate variables with actual values, but only if there actually is any replacements to be made(one or more "$" is present)
-                            if(expression) {
-                                if(expression.indexOf('#') !== -1) {
-                                    expression = replaceVariables(expression);
-                                }
-                                //run expression:
-                                ruleEffective = runExpression(expression, rule.condition, "rule:" + rule.id);
-                            } else {
-                                $log.warn("Rule id:'" + rule.id + "'' and name:'" + rule.name + "' had no condition specified. Please check rule configuration.");
-                            }
-                            
-                            angular.forEach(rule.programRuleActions, function(action){
-                                //In case the effect-hash is not populated, add entries
-                                if(angular.isUndefined( $rootScope.ruleeffects[executingEvent.event][action.id] )){
-                                    $rootScope.ruleeffects[executingEvent.event][action.id] =  {
-                                        id:action.id,
-                                        location:action.location, 
-                                        action:action.programRuleActionType,
-                                        dataElement:action.dataElement,
-                                        content:action.content,
-                                        data:action.data,
-                                        ineffect:undefined
-                                    };
-                                }
-
-                                //In case the rule is effective and contains specific data, 
-                                //the effect be refreshed from the variables list.
-                                //If the rule is not effective we can skip this step
-                                if(ruleEffective && action.data)
-                                {
-                                    //The key data might be containing a dollar sign denoting that the key data is a variable.
-                                    //To make a lookup in variables hash, we must make a lookup without the dollar sign in the variable name
-                                    //The first strategy is to make a direct lookup. In case the "data" expression is more complex, we have to do more replacement and evaluation.
-
-                                    var nameWithoutBrackets = action.data.replace('#{','').replace('}','');
-                                    if(angular.isDefined(variablesHash[nameWithoutBrackets]))
-                                    {
-                                        //The variable exists, and is replaced with its corresponding value
-                                        $rootScope.ruleeffects[executingEvent.event][action.id].data =
-                                            variablesHash[nameWithoutBrackets].variableValue;
-                                    }
-                                    else if(action.data.indexOf('#') !== -1)
-                                    {
-                                        //Since the value couldnt be looked up directly, and contains a dollar sign, the expression was more complex
-                                        //Now we will have to make a thorough replacement and separate evaluation to find the correct value:
-                                        $rootScope.ruleeffects[executingEvent.event][action.id].data = replaceVariables(action.data);
-                                        //In a scenario where the data contains a complex expression, evaluate the expression to compile(calculate) the result:
-                                        $rootScope.ruleeffects[executingEvent.event][action.id].data = runExpression($rootScope.ruleeffects[executingEvent.event][action.id].data, action.data, "action:" + action.id);
-                                    }
-                                }
-
-                                //Update the rule effectiveness if it changed in this evaluation;
-                                if($rootScope.ruleeffects[executingEvent.event][action.id].ineffect !== ruleEffective)
-                                {
-                                    //There is a change in the rule outcome, we need to update the effect object.
-                                    updatedEffectsExits = true;
-                                    $rootScope.ruleeffects[executingEvent.event][action.id].ineffect = ruleEffective;
-                                }
-
-                                //In case the rule is of type "assign variable" and the rule is effective,
-                                //the variable data result needs to be applied to the correct variable:
-                                if($rootScope.ruleeffects[executingEvent.event][action.id].action === "ASSIGNVARIABLE" && $rootScope.ruleeffects[executingEvent.event][action.id].ineffect){
-                                    //from earlier evaluation, the data portion of the ruleeffect now contains the value of the variable to be assign.
-                                    //the content portion of the ruleeffect defines the name for the variable, when dollar is removed:
-                                    var variabletoassign = $rootScope.ruleeffects[executingEvent.event][action.id].content.replace("#{","").replace("}","");
-
-                                    if(!angular.isDefined(variablesHash[variabletoassign])){
-                                        $log.warn("Variable " + variabletoassign + " was not defined.");
-                                    }
-
-                                    //Even if the variable is not defined: we assign it:
-                                    if(variablesHash[variabletoassign].variableValue !== $rootScope.ruleeffects[executingEvent.event][action.id].data){
-                                        //If the variable was actually updated, we assume that there is an updated ruleeffect somewhere:
+        var getIndicatorRules = function (programid) {
+                var def = $q.defer();
+                MetaDataFactory.getByProgram('programIndicators', programid).then(function(pis){
+                    var variables = [];
+                    
+                    var programRules = [];
+                    
+                    angular.forEach(pis, function(pi){
+                        var newAction = {
+                                id:pi.id,
+                                content:pi.displayDescription,
+                                data:pi.expression,
+                                programRuleActionType:'DISPLAYKEYVALUEPAIR',
+                                location:'indicators'
+                            };
+                        var newRule = {
+                                name:pi.name,
+                                shortname:pi.shortname,
+                                code:pi.code,
+                                program:pi.program,
+                                description:pi.description,
+                                condition:pi.filter ? pi.filter : 'true',
+                                programRuleActions: [newAction]
+                            };
+                            
+                        programRules.push(newRule);
+                        
+                        var variablesInCondition = newRule.condition.match(/#{\w+.?\w*}/g);
+                        var variablesInData = newAction.data.match(/#{\w+.?\w*}/g);
+                        
+                        var pushDirectAddressedVariable = function(variableWithCurls) {
+                            var variableName = variableWithCurls.replace("#{","").replace("}","");
+                            var variableNameParts = variableName.split('.');
+                            
+                           
+                            if(variableNameParts.length === 2) {
+                                //this is a programstage and dataelement specification. translate to program variable:
+                                variables.push({
+                                    name:variableName,
+                                    programRuleVariableSourceType:'DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE',
+                                    dataElement:variableNameParts[1],
+                                    programStage:variableNameParts[0],
+                                    program:programid
+                                });
+                            }
+                            else if(variableNameParts.length === 1)
+                            {
+                                //This is an attribute - let us translate to program variable:
+                                variables.push({
+                                    name:variableName,
+                                    programRuleVariableSourceType:'TEI_ATTRIBUTE',
+                                    trackedEntityAttribute:variableNameParts[0],
+                                    program:programid
+                                });
+                            }
+                         
+                        };
+                        
+                        angular.forEach(variablesInCondition, function(variableInCondition) {
+                            pushDirectAddressedVariable(variableInCondition);
+                        });
+                        
+                        angular.forEach(variablesInData, function(variableInData) {
+                            pushDirectAddressedVariable(variableInData);
+                        });
+                    });
+
+                    def.resolve({rules:programRules,variables:variables});
+                });
+                return def.promise;       
+            };
+            
+            
+            getIndicatorRules(programid).then(function(indicatorRulesAndVariables){
+                VariableService.getVariables(programid, executingEvent, allEventsByStage, allDataElements, selectedEntity,indicatorRulesAndVariables.variables, selectedEnrollment).then(function(variablesReceived){
+                    TrackerRulesFactory.getProgramStageRules(programid, executingEvent.programStage).then(function(rules){
+                        //Concatenate rules produced by indicator definitions into the other rules:
+                        rules = rules.concat(indicatorRulesAndVariables.rules);
+                        
+                        //Run rules in priority - lowest number first(priority null is last)
+                        rules = orderByFilter(rules, 'priority');
+
+                        variablesHash = variablesReceived;
+
+                        if(angular.isObject(rules) && angular.isArray(rules)){
+                            //The program has rules, and we want to run them.
+                            //Prepare repository unless it is already prepared:
+                            if(angular.isUndefined( $rootScope.ruleeffects ) ) {
+                                $rootScope.ruleeffects = {};
+                            }
+
+                            if(angular.isUndefined( $rootScope.ruleeffects[executingEvent.event] )){
+                                $rootScope.ruleeffects[executingEvent.event] = {};
+                            }
+
+                            var updatedEffectsExits = false;
+
+                            angular.forEach(rules, function(rule) {
+                                var ruleEffective = false;
+
+                                var expression = rule.condition;
+                                //Go through and populate variables with actual values, but only if there actually is any replacements to be made(one or more "$" is present)
+                                if(expression) {
+                                    if(expression.indexOf('{') !== -1) {
+                                        expression = replaceVariables(expression);
+                                    }
+                                    //run expression:
+                                    ruleEffective = runExpression(expression, rule.condition, "rule:" + rule.id);
+                                } else {
+                                    $log.warn("Rule id:'" + rule.id + "'' and name:'" + rule.name + "' had no condition specified. Please check rule configuration.");
+                                }
+
+                                angular.forEach(rule.programRuleActions, function(action){
+                                    //In case the effect-hash is not populated, add entries
+                                    if(angular.isUndefined( $rootScope.ruleeffects[executingEvent.event][action.id] )){
+                                        $rootScope.ruleeffects[executingEvent.event][action.id] =  {
+                                            id:action.id,
+                                            location:action.location, 
+                                            action:action.programRuleActionType,
+                                            dataElement:action.dataElement,
+                                            content:action.content,
+                                            data:action.data,
+                                            ineffect:undefined
+                                        };
+                                    }
+
+                                    //In case the rule is effective and contains specific data, 
+                                    //the effect be refreshed from the variables list.
+                                    //If the rule is not effective we can skip this step
+                                    if(ruleEffective && action.data)
+                                    {
+                                        //The key data might be containing a dollar sign denoting that the key data is a variable.
+                                        //To make a lookup in variables hash, we must make a lookup without the dollar sign in the variable name
+                                        //The first strategy is to make a direct lookup. In case the "data" expression is more complex, we have to do more replacement and evaluation.
+
+                                        var nameWithoutBrackets = action.data.replace('#{','').replace('}','');
+                                        if(angular.isDefined(variablesHash[nameWithoutBrackets]))
+                                        {
+                                            //The variable exists, and is replaced with its corresponding value
+                                            $rootScope.ruleeffects[executingEvent.event][action.id].data =
+                                                variablesHash[nameWithoutBrackets].variableValue;
+                                        }
+                                        else if(action.data.indexOf('{') !== -1)
+                                        {
+                                            //Since the value couldnt be looked up directly, and contains a dollar sign, the expression was more complex
+                                            //Now we will have to make a thorough replacement and separate evaluation to find the correct value:
+                                            $rootScope.ruleeffects[executingEvent.event][action.id].data = replaceVariables(action.data);
+                                            //In a scenario where the data contains a complex expression, evaluate the expression to compile(calculate) the result:
+                                            $rootScope.ruleeffects[executingEvent.event][action.id].data = runExpression($rootScope.ruleeffects[executingEvent.event][action.id].data, action.data, "action:" + action.id);
+                                        }
+                                    }
+
+                                    //Update the rule effectiveness if it changed in this evaluation;
+                                    if($rootScope.ruleeffects[executingEvent.event][action.id].ineffect !== ruleEffective)
+                                    {
+                                        //There is a change in the rule outcome, we need to update the effect object.
                                         updatedEffectsExits = true;
-                                        //Then we assign the new value:
-                                        variablesHash[variabletoassign].variableValue = $rootScope.ruleeffects[executingEvent.event][action.id].data;
-                                    }
-                                }
+                                        $rootScope.ruleeffects[executingEvent.event][action.id].ineffect = ruleEffective;
+                                    }
+
+                                    //In case the rule is of type "assign variable" and the rule is effective,
+                                    //the variable data result needs to be applied to the correct variable:
+                                    if($rootScope.ruleeffects[executingEvent.event][action.id].action === "ASSIGNVARIABLE" && $rootScope.ruleeffects[executingEvent.event][action.id].ineffect){
+                                        //from earlier evaluation, the data portion of the ruleeffect now contains the value of the variable to be assign.
+                                        //the content portion of the ruleeffect defines the name for the variable, when dollar is removed:
+                                        var variabletoassign = $rootScope.ruleeffects[executingEvent.event][action.id].content.replace("#{","").replace("}","");
+
+                                        if(!angular.isDefined(variablesHash[variabletoassign])){
+                                            $log.warn("Variable " + variabletoassign + " was not defined.");
+                                        }
+
+                                        //Even if the variable is not defined: we assign it:
+                                        if(variablesHash[variabletoassign].variableValue !== $rootScope.ruleeffects[executingEvent.event][action.id].data){
+                                            //If the variable was actually updated, we assume that there is an updated ruleeffect somewhere:
+                                            updatedEffectsExits = true;
+                                            //Then we assign the new value:
+                                            variablesHash[variabletoassign].variableValue = $rootScope.ruleeffects[executingEvent.event][action.id].data;
+                                        }
+                                    }
+                                });
                             });
-                        });
 
-                        //Broadcast rules finished if there was any actual changes to the event.
-                        if(updatedEffectsExits){
-                            $rootScope.$broadcast("ruleeffectsupdated", { event: executingEvent.event });
+                            //Broadcast rules finished if there was any actual changes to the event.
+                            if(updatedEffectsExits){
+                                $rootScope.$broadcast("ruleeffectsupdated", { event: executingEvent.event });
+                            }
                         }
-                    }
 
-                    return true;
+                        return true;
+                    });
                 });
             });
         }