=== 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%;"> {{$select.selected.name || $select.selected}} @@ -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"/> @@ -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"/> @@ -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"> @@ -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"/> @@ -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"/> @@ -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"/> === 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); } }); });