← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 19862: Registration now makes calls to the program rules engine

 

------------------------------------------------------------
revno: 19862
committer: Markus Bekken <markus.bekken@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2015-08-26 14:29:22 +0200
message:
  Registration now makes calls to the program rules engine
modified:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/default-registration-form.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.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-tracker-capture/components/registration/default-registration-form.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/default-registration-form.html	2015-08-19 20:13:21 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/default-registration-form.html	2015-08-26 12:29:22 +0000
@@ -12,7 +12,7 @@
                                 ng-required="attribute.mandatory || attribute.unique"
                                 ng-disabled="editingDisabled"
                                 name="foo" 
-                                on-select="validationAndSkipLogic(selectedTei, attribute.id)"
+                                on-select="teiValueUpdated(selectedTei, attribute.id)"
                                 style="width:100%;">
                         <ui-select-match allow-clear="true" style="width:100%; height:34px; line-height:1.0; padding: 2px 6px; margin-top:5px" placeholder="{{'select_or_search' | translate}}">{{$select.selected.name  || $select.selected}}</ui-select-match>
                         <ui-select-choices  repeat="option.name as option in optionSets[attributesById[attribute.id].optionSet.id].options | filter: $select.search | limitTo:30">
@@ -31,7 +31,7 @@
                                max-date="attribute.allowFutureDate ? '' : 0"
                                ng-model="selectedTei[attribute.id]"
                                ng-disabled="editingDisabled" 
-                               blur-or-change="validationAndSkipLogic(selectedTei, attribute.id)"
+                               blur-or-change="teiValueUpdated(selectedTei, attribute.id)"
                                ng-required="attribute.mandatory || attribute.unique"/>
                     </span>
                     <span ng-switch-when="trueOnly">
@@ -40,7 +40,7 @@
                                class="form-control" 
                                ng-model="selectedTei[attribute.id]" 
                                ng-disabled="editingDisabled" 
-                               ng-change="validationAndSkipLogic(selectedTei, attribute.id)"
+                               ng-change="teiValueUpdated(selectedTei, attribute.id)"
                                ng-required="attribute.mandatory || attribute.unique"/>
                     </span>
                     <span ng-switch-when="bool">
@@ -48,7 +48,7 @@
                                 ng-model="selectedTei[attribute.id]" 
                                 class="form-control" 
                                 ng-disabled="editingDisabled" 
-                                ng-change="validationAndSkipLogic(selectedTei, attribute.id)"
+                                ng-change="teiValueUpdated(selectedTei, attribute.id)"
                                 ng-required="attribute.mandatory || attribute.unique">
                             <option value="">{{'please_select'| translate}}</option>                        
                             <option value="false">{{'no'| translate}}</option>
@@ -61,7 +61,7 @@
                                class="form-control" 
                                ng-model="selectedTei[attribute.id]" 
                                ng-disabled="editingDisabled" 
-                               ng-blur="validationAndSkipLogic(selectedTei, attribute.id)"
+                               ng-blur="teiValueUpdated(selectedTei, attribute.id)"
                                ng-required="attribute.mandatory || attribute.unique"/>
                     </span>
                     <span ng-switch-when="email">
@@ -70,7 +70,7 @@
                                class="form-control" 
                                ng-model="selectedTei[attribute.id]" 
                                ng-disabled="editingDisabled" 
-                               ng-blur="validationAndSkipLogic(selectedTei, attribute.id)"
+                               ng-blur="teiValueUpdated(selectedTei, attribute.id)"
                                ng-required="attribute.mandatory || attribute.unique"/>
                     </span>
                     <span ng-switch-default>
@@ -79,7 +79,7 @@
                                class="form-control" 
                                ng-model="selectedTei[attribute.id]" 
                                ng-disabled="editingDisabled" 
-                               ng-blur="validationAndSkipLogic(selectedTei, attribute.id)"
+                               ng-blur="teiValueUpdated(selectedTei, attribute.id)"
                                ng-required="attribute.mandatory || attribute.unique"/>                                    
                     </span>
                 </span>                

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js	2015-08-19 20:13:21 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js	2015-08-26 12:29:22 +0000
@@ -18,7 +18,9 @@
                 EventUtils,
                 RegistrationService,
                 DateUtils,
-                SessionStorageService) {
+                SessionStorageService,
+                TrackerRulesFactory,
+                TrackerRulesExecutionService) {
     
     $scope.today = DateUtils.getToday();
     $scope.trackedEntityForm = null;
@@ -60,6 +62,11 @@
         $scope.trackedEntities.selected = $scope.trackedEntities.available[0];
     });
     
+    $scope.allProgramRules = [];
+    TrackerRulesFactory.getRules($scope.selectedProgram.id).then(function(rules){                    
+        $scope.allProgramRules = rules;
+    });  
+
     //watch for selection of program
     $scope.$watch('selectedProgram', function() {        
         $scope.trackedEntityForm = null;
@@ -107,7 +114,7 @@
         //reset form
         $scope.selectedTei = {};
         $scope.selectedEnrollment = {};
-        $scope.outerForm.submitted = false;
+        $scope.outerForm.submitted = false;         
 
         if(destination === 'DASHBOARD') {
             $location.path('/dashboard').search({tei: teiId,                                            
@@ -262,9 +269,94 @@
         }, 100);
     };
     
-    /*$scope.validationAndSkipLogic = function(tei, field){
-    };*/
-    
+    var processRuleEffect = function(){
+
+        angular.forEach($rootScope.ruleeffects['registration'], function (effect) {
+            if (effect.dataElement) {
+                //in the data entry controller we only care about the "hidefield", showerror and showwarning actions
+                if (effect.action === "HIDEFIELD") {
+                    if (effect.dataElement) {
+                        if (effect.ineffect && affectedEvent[effect.dataElement.id]) {
+                            //If a field is going to be hidden, but contains a value, we need to take action;
+                            if (effect.content) {
+                                //TODO: Alerts is going to be replaced with a proper display mecanism.
+                                alert(effect.content);
+                            }
+                            else {
+                                //TODO: Alerts is going to be replaced with a proper display mecanism.
+                                alert($scope.prStDes[effect.dataElement.id].dataElement.formName + "Was blanked out and hidden by your last action");
+                            }
+
+                            //Blank out the value:
+                            affectedEvent[effect.dataElement.id] = "";
+                            $scope.saveDatavalueForEvent($scope.prStDes[effect.dataElement.id], null, affectedEvent);
+                        }
+
+                        $scope.hiddenFields[effect.dataElement.id] = effect.ineffect;
+                    }
+                    else {
+                        $log.warn("ProgramRuleAction " + effect.id + " is of type HIDEFIELD, bot does not have a dataelement defined");
+                    }
+                } else if (effect.action === "SHOWERROR") {
+                    if (effect.dataElement) {
+                        
+                        if(effect.ineffect) {
+                            $scope.errorMessages[effect.dataElement.id] = effect.content;
+                        } else {
+                            $scope.errorMessages[effect.dataElement.id] = false;
+                        }
+                    }
+                    else {
+                        $log.warn("ProgramRuleAction " + effect.id + " is of type HIDEFIELD, bot does not have a dataelement defined");
+                    }
+                } else if (effect.action === "SHOWWARNING") {
+                    if (effect.dataElement) {
+                        if(effect.ineffect) {
+                            $scope.warningMessages[effect.dataElement.id] = effect.content;
+                        } else {
+                            $scope.warningMessages[effect.dataElement.id] = false;
+                        }
+                    }
+                    else {
+                        $log.warn("ProgramRuleAction " + effect.id + " is of type HIDEFIELD, bot does not have a dataelement defined");
+                    }
+                }
+            }
+        });
+    };
+    
+    $scope.executeRules = function () {   
+        var flag = {debug: true, verbose: true};
+        
+        //repopulate attributes with updated values
+        $scope.selectedTei.attributes = [];
+        
+        angular.forEach($scope.attributes, function(metaAttribute){
+            var newAttributeInArray = {attribute:metaAttribute.id,
+                code:metaAttribute.code,
+                displayName:metaAttribute.displayName,
+                type:metaAttribute.valueType
+            };
+            if($scope.selectedTei[newAttributeInArray.attribute]){
+                newAttributeInArray.value = $scope.selectedTei[newAttributeInArray.attribute];
+            }
+            
+           $scope.selectedTei.attributes.push(newAttributeInArray);
+        });
+        TrackerRulesExecutionService.executeRules($scope.allProgramRules, 'registration', null, null, $scope.selectedTei, $scope.selectedEnrollment, flag);
+
+    };
+    
+    $scope.teiValueUpdated = function(tei, field){
+        $scope.executeRules();
+    };
+    
+    //listen for rule effect changes
+    $scope.$on('ruleeffectsupdated', function (event, args) {
+        processRuleEffect(args.event);
+    });
+
+
     $scope.interacted = function(field) {
         var status = false;
         if(field){            

=== 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-08-24 09:55:12 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js	2015-08-26 12:29:22 +0000
@@ -771,7 +771,8 @@
                 }
 
                 var valueFound = false;
-                if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE"){
+                //If variable evs is not defined, it means the rules is run before any events is registered, skip the types that require an event
+                if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE" && evs){
                     if(programStageId) {
                         angular.forEach(evs.byStage[programStageId], function(event) {
                             if(angular.isDefined(event[dataElementId])
@@ -787,7 +788,7 @@
                     }
 
                 }
-                else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM"){
+                else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM" && evs){
                     angular.forEach(evs.all, function(event) {
                         if(angular.isDefined(event[dataElementId])
                                 && event[dataElementId] !== null ){
@@ -796,14 +797,14 @@
                          }
                     });
                 }
-                else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_CURRENT_EVENT"){
+                else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_CURRENT_EVENT" && evs){
                     if(angular.isDefined(executingEvent[dataElementId])
                             && executingEvent[dataElementId] !== null ){
                         valueFound = true;
                         variables = pushVariable(variables, programVariable.name, executingEvent[dataElementId], allDes[dataElementId].dataElement.type, valueFound, '#' );
                     }      
                 }
-                else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_PREVIOUS_EVENT"){
+                else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_PREVIOUS_EVENT" && evs){
                     //Only continue checking for a value if there is more than one event.
                     if(evs.all && evs.all.length > 1) {
                         var previousvalue = null;
@@ -840,7 +841,7 @@
                 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"){
+                else if(programVariable.programRuleVariableSourceType === "NUMBEROFEVENTS_PROGRAMSTAGE" && evs){
                     var numberOfEvents = 0;
                     if( programStageId && evs.byStage[programStageId] ) {
                         numberOfEvents = evs.byStage[programStageId].length;
@@ -849,14 +850,18 @@
                     variables = pushVariable(variables, programVariable.name, numberOfEvents, 'int', valueFound, '#' );
                 }
                 else {
-                    //Missing handing of ruletype
-                    $log.warn("Unknown programRuleVariableSourceType:" + programVariable.programRuleVariableSourceType);
+                    //If the rules was executed without events, we ended up in this else clause as expected, as most of the variables require an event to be mapped
+                    if(evs)
+                    {
+                        //If the rules was executed and events was supplied, we should have found an if clause for the the source type, and not ended up in this dead end else. 
+                        $log.warn("Unknown programRuleVariableSourceType:" + programVariable.programRuleVariableSourceType);
+                    }
                 }
 
 
                 if(!valueFound){
                     //If there is still no value found, assign default value:
-                    if(dataElementId) {
+                    if(dataElementId && allDes) {
                         var dataElement = allDes[dataElementId];
                         if( dataElement ) {
                             variables = pushVariable(variables, programVariable.name, "", dataElement.dataElement.type, false, '#' );
@@ -996,14 +1001,16 @@
     };
     
     var runDhisFunctions = function(expression, variablesHash, flag){
-        //Called from "runExpression". Only proceed with this logic in case there seems to be dhis function calls: "dhis." is present.
-        if(angular.isDefined(expression) && expression.indexOf("dhis.") !== -1){   
-            var dhisFunctions = [{name:"dhis.daysbetween",parameters:2},
-                                {name:"dhis.yearsbetween",parameters:2},
-                                {name:"dhis.floor",parameters:1},
-                                {name:"dhis.modulus",parameters:2},
-                                {name:"dhis.concatenate"},
-                                {name:"dhis.adddays",parameters:2}];
+        //Called from "runExpression". Only proceed with this logic in case there seems to be dhis function calls: "d2:" is present.
+        if(angular.isDefined(expression) && expression.indexOf("d2:") !== -1){   
+            var dhisFunctions = [{name:"d2:daysbetween",parameters:2},
+                                {name:"d2:yearsbetween",parameters:2},
+                                {name:"d2:floor",parameters:1},
+                                {name:"d2:modulus",parameters:2},
+                                {name:"d2:concatenate"},
+                                {name:"d2:adddays",parameters:2},
+                                {name:"d2:zing",parameters:1},
+                                {name:"d2:oizp",parameters:1}];
 
             angular.forEach(dhisFunctions, function(dhisFunction){
                 //Replace each * with a regex that matches each parameter, allowing commas only inside single quotation marks.
@@ -1032,8 +1039,8 @@
                         }
                     }
 
-                    //Special block for dhis.weeksBetween(*,*) - add such a block for all other dhis functions.
-                    if(dhisFunction.name === "dhis.daysbetween")
+                    //Special block for d2:weeksBetween(*,*) - add such a block for all other dhis functions.
+                    if(dhisFunction.name === "d2:daysbetween")
                     {
                         var firstdate = $filter('trimquotes')(parameters[0]);
                         var seconddate = $filter('trimquotes')(parameters[1]);
@@ -1042,7 +1049,7 @@
                         //Replace the end evaluation of the dhis function:
                         expression = expression.replace(callToThisFunction, seconddate.diff(firstdate,'days'));
                     }
-                    else if(dhisFunction.name === "dhis.yearsbetween")
+                    else if(dhisFunction.name === "d2:yearsbetween")
                     {
                         var firstdate = $filter('trimquotes')(parameters[0]);
                         var seconddate = $filter('trimquotes')(parameters[1]);
@@ -1051,13 +1058,13 @@
                         //Replace the end evaluation of the dhis function:
                         expression = expression.replace(callToThisFunction, seconddate.diff(firstdate,'years'));
                     }
-                    else if(dhisFunction.name === "dhis.floor")
+                    else if(dhisFunction.name === "d2:floor")
                     {
                         var floored = Math.floor(parameters[0]);
                         //Replace the end evaluation of the dhis function:
                         expression = expression.replace(callToThisFunction, floored);
                     }
-                    else if(dhisFunction.name === "dhis.modulus")
+                    else if(dhisFunction.name === "d2:modulus")
                     {
                         var dividend = Number(parameters[0]);
                         var divisor = Number(parameters[1]);
@@ -1065,7 +1072,7 @@
                         //Replace the end evaluation of the dhis function:
                         expression = expression.replace(callToThisFunction, rest);
                     }
-                    else if(dhisFunction.name === "dhis.concatenate")
+                    else if(dhisFunction.name === "d2:concatenate")
                     {
                         var returnString = "'";
                         for (var i = 0; i < parameters.length; i++) {
@@ -1074,7 +1081,7 @@
                         returnString += "'";
                         expression = expression.replace(callToThisFunction, returnString);
                     }
-                    else if(dhisFunction.name === "dhis.adddays")
+                    else if(dhisFunction.name === "d2:adddays")
                     {
                         var date = $filter('trimquotes')(parameters[0]);
                         var daystoadd = $filter('trimquotes')(parameters[1]);
@@ -1082,6 +1089,25 @@
                         var newdatestring = "'" + newdate + "'";
                         //Replace the end evaluation of the dhis function:
                         expression = expression.replace(callToThisFunction, newdatestring);
+                    }else if(dhisFunction.name === "d2:zing")
+                    {
+                        var number = parameters[0];
+                        if( number < 0 ) {
+                            number = 0;
+                        }
+                        
+                        //Replace the end evaluation of the dhis function:
+                        expression = expression.replace(callToThisFunction, number);
+                    }else if(dhisFunction.name === "d2:oizp")
+                    {
+                        var number = parameters[0];
+                        var output = 1;
+                        if( number < 0 ) {
+                            output = 0;
+                        }
+                        
+                        //Replace the end evaluation of the dhis function:
+                        expression = expression.replace(callToThisFunction, output);
                     }
                 });
             });